Function bodies 113 total
ListingCard function · typescript · L88-L163 (76 LOC)src/components/sections/FeaturedListings.tsx
function ListingCard({ listing, index }: { listing: Listing; index: number }) {
return (
<AnimateIn delay={index * 0.1}>
<div className="group min-w-[85vw] cursor-pointer border border-border bg-background transition-all duration-500 hover:border-accent/30 sm:min-w-[280px] md:min-w-0">
{/* Image placeholder */}
<div className="relative aspect-[4/3] overflow-hidden bg-background-tertiary">
{/* Hover zoom effect on placeholder */}
<div className="absolute inset-0 flex items-center justify-center transition-transform duration-700 group-hover:scale-110">
<span className="text-xs tracking-[0.2em] text-text-muted uppercase">
Listing Photo
</span>
</div>
{/* Hover overlay */}
<div className="absolute inset-0 bg-accent/0 transition-all duration-500 group-hover:bg-accent/10" />
{/* Featured badge */}
{listing.featured && (
<div className="absoluteFeaturedListings function · typescript · L165-L216 (52 LOC)src/components/sections/FeaturedListings.tsx
export default function FeaturedListings() {
const scrollRef = useRef<HTMLDivElement>(null);
return (
<section className="bg-background-secondary py-16 md:py-24 lg:py-32">
<div className="mx-auto max-w-7xl px-6 lg:px-10">
<AnimateIn>
<div className="flex flex-col items-center text-center">
<p className="text-xs font-medium tracking-[0.3em] text-accent uppercase">
Featured Properties
</p>
<h2 className="mt-4 font-heading text-4xl font-light tracking-tight text-text-primary md:text-5xl">
Active Listings
</h2>
<p className="mt-2 text-sm text-text-muted">
{activeCount} Active Listing{activeCount !== 1 ? "s" : ""}
</p>
<p className="mt-3 max-w-lg text-text-secondary">
Explore curated properties across the Okanagan. Updated daily from
the MLS.
</p>
</div>
</AnimateIn>
{Dropdown function · typescript · L117-L189 (73 LOC)src/components/sections/Hero.tsx
function Dropdown({ label, value, options, onChange }: DropdownProps) {
const [open, setOpen] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
function handleClickOutside(e: MouseEvent) {
if (ref.current && !ref.current.contains(e.target as Node)) {
setOpen(false);
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
return (
<div ref={ref} className="relative flex-1 min-w-0 sm:min-w-[130px]">
<button
onClick={() => setOpen((prev) => !prev)}
className={cn(
"flex w-full items-center justify-between gap-2 px-3 py-3 text-left sm:px-4",
"text-sm text-text-secondary transition-colors duration-200",
"hover:text-text-primary focus:outline-none",
open && "text-text-primary"
)}
type="button"
>
<span className="flex flex-col">
handleClickOutside function · typescript · L122-L126 (5 LOC)src/components/sections/Hero.tsx
function handleClickOutside(e: MouseEvent) {
if (ref.current && !ref.current.contains(e.target as Node)) {
setOpen(false);
}
}SellTabContent function · typescript · L194-L235 (42 LOC)src/components/sections/Hero.tsx
function SellTabContent() {
return (
<div className="glass rounded-2xl p-6 sm:p-8">
{/* 3-step process */}
<div className="grid gap-6 sm:grid-cols-3 sm:gap-4">
{sellSteps.map((step, i) => (
<div
key={step.step}
className="relative flex flex-col items-center text-center"
>
{/* Step number badge */}
<div className="flex h-11 w-11 items-center justify-center rounded-full border border-accent/30 bg-accent/10">
<span className="text-sm font-semibold text-accent">
{step.step}
</span>
</div>
{/* Connector line (desktop only) */}
{i < sellSteps.length - 1 && (
<div className="absolute top-[22px] left-[calc(50%+28px)] hidden h-px w-[calc(100%-56px)] bg-gradient-to-r from-accent/30 to-accent/10 sm:block" />
)}
<h3 className="mt-4 text-sm font-medium tracking-wide text-text-primary">
MoveTabContent function · typescript · L240-L281 (42 LOC)src/components/sections/Hero.tsx
function MoveTabContent() {
return (
<div className="glass rounded-2xl p-6 sm:p-8">
<div className="flex flex-col items-center text-center">
{/* Icon */}
<div className="flex h-14 w-14 items-center justify-center rounded-full border border-accent/20 bg-accent/5">
<Phone className="h-6 w-6 text-accent" />
</div>
{/* Copy */}
<h3 className="mt-5 font-heading text-2xl font-light tracking-tight text-text-primary sm:text-3xl">
Your Next Move,{" "}
<span className="italic text-accent">Strategically Planned</span>
</h3>
<p className="mt-3 max-w-lg text-sm leading-relaxed text-text-secondary">
Whether you're upsizing, downsizing, or relocating to the
Okanagan — I'll build a custom plan that aligns your
timeline, budget, and goals.
</p>
{/* Testimonial quote */}
<div className="mt-6 border-t border-border/50 pt-6">
<bloKarsenTabContent function · typescript · L286-L338 (53 LOC)src/components/sections/Hero.tsx
function KarsenTabContent() {
return (
<div className="glass rounded-2xl p-6 sm:p-8">
<div className="flex flex-col items-center text-center sm:flex-row sm:items-start sm:gap-8 sm:text-left">
{/* Headshot placeholder */}
<div className="shrink-0">
<div className="relative h-24 w-24 overflow-hidden rounded-full border border-accent/20 bg-background-secondary sm:h-28 sm:w-28">
<div className="flex h-full w-full items-center justify-center">
<User className="h-8 w-8 text-text-muted/40" />
</div>
</div>
</div>
{/* Content */}
<div className="mt-5 sm:mt-0">
<h3 className="font-heading text-2xl font-light tracking-tight text-text-primary">
Karsen Koltun
</h3>
<p className="mt-1 text-xs tracking-[0.15em] text-accent uppercase">
Realtor · Royal LePage
</p>
<p className="mt-3 max-w-md text-sm leading-relaxeAbout: code-quality intelligence by Repobility · https://repobility.com
Hero function · typescript · L343-L645 (303 LOC)src/components/sections/Hero.tsx
export default function Hero() {
const router = useRouter();
const [wordIndex, setWordIndex] = useState(0);
const [activeTab, setActiveTab] = useState("buy");
const sectionRef = useRef<HTMLElement>(null);
/* Search state */
const [location, setLocation] = useState("All Kelowna");
const [priceMin, setPriceMin] = useState("Any");
const [priceMax, setPriceMax] = useState("Any");
const [beds, setBeds] = useState("Any");
/* Parallax */
const { scrollYProgress } = useScroll({
target: sectionRef,
offset: ["start start", "end start"],
});
const headingY = useTransform(scrollYProgress, [0, 1], [0, -80]);
const overlayOpacity = useTransform(scrollYProgress, [0, 0.8], [0.55, 0.92]);
/* Rotating word timer */
useEffect(() => {
const interval = setInterval(() => {
setWordIndex((prev) => (prev + 1) % rotatingWords.length);
}, 3000);
return () => clearInterval(interval);
}, []);
/* Handle search */
function handleSearch() {
conshandleSearch function · typescript · L373-L381 (9 LOC)src/components/sections/Hero.tsx
function handleSearch() {
const params = new URLSearchParams();
if (location !== "All Kelowna") params.set("location", location);
if (priceMin !== "Any") params.set("priceMin", priceMin);
if (priceMax !== "Any") params.set("priceMax", priceMax);
if (beds !== "Any") params.set("beds", beds);
const query = params.toString();
router.push(`/search${query ? `?${query}` : ""}`);
}Newsletter function · typescript · L17-L323 (307 LOC)src/components/sections/Newsletter.tsx
export default function Newsletter() {
const [email, setEmail] = useState("");
const [interest, setInterest] = useState("");
const [isSubmitted, setIsSubmitted] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [honey, setHoney] = useState("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!email) return;
setIsSubmitting(true);
try {
await fetch("/api/lead", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: email.split("@")[0],
email,
source: "Newsletter Signup",
tags: [
"newsletter",
"market-report",
...(interest ? [`interest-${interest}`] : []),
],
customFields: {
interest: interest || "Not specified",
},
_honey: honey,
}),
});
setIsSubmitted(true);
} catch (err) {
SocialBar function · typescript · L60-L127 (68 LOC)src/components/sections/SocialBar.tsx
export default function SocialBar() {
const [hoveredPlatform, setHoveredPlatform] = useState<string | null>(null);
return (
<section className="border-y border-border bg-background py-14">
<div className="mx-auto max-w-7xl px-6 lg:px-10">
<AnimateIn>
{/* "Follow Along" header text */}
<p className="mb-8 text-center text-xs font-medium tracking-[0.4em] text-accent uppercase">
Follow Along
</p>
<div className="flex flex-wrap items-center justify-center gap-8 md:gap-14">
{socials.map((social) => (
<a
key={social.label}
href={social.href}
target="_blank"
rel="noopener noreferrer"
className="group flex items-center gap-3 transition-all duration-300"
onMouseEnter={() => setHoveredPlatform(social.hoverBg)}
onMouseLeave={() => setHoveredPlatform(null)}
>
useCountUp function · typescript · L14-L49 (36 LOC)src/components/sections/StatsBar.tsx
function useCountUp(
target: number,
decimals: number,
duration: number = 2000,
trigger: boolean = false
) {
const [value, setValue] = useState(0);
const frameRef = useRef<number>(0);
useEffect(() => {
if (!trigger) return;
const startTime = performance.now();
const animate = (currentTime: number) => {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Ease-out cubic
const eased = 1 - Math.pow(1 - progress, 3);
const current = eased * target;
setValue(Number(current.toFixed(decimals)));
if (progress < 1) {
frameRef.current = requestAnimationFrame(animate);
}
};
frameRef.current = requestAnimationFrame(animate);
return () => cancelAnimationFrame(frameRef.current);
}, [target, decimals, duration, trigger]);
return value;
}StatsBar function · typescript · L111-L128 (18 LOC)src/components/sections/StatsBar.tsx
export default function StatsBar() {
return (
<section className="border-y border-border bg-background-secondary">
<div className="mx-auto max-w-7xl px-6 py-14 lg:px-10">
<div className="grid grid-cols-2 gap-8 md:grid-cols-4">
{stats.map((stat, i) => (
<StatItem
key={stat.label}
stat={stat}
index={i}
isLast={i === stats.length - 1}
/>
))}
</div>
</div>
</section>
);
}GoogleLogo function · typescript · L14-L35 (22 LOC)src/components/sections/Testimonials.tsx
function GoogleLogo({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z"
fill="#4285F4"
/>
<path
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
fill="#34A853"
/>
<path
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
fill="#FBBC05"
/>
<path
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
fill="#EA4335"
/>
</svg>
);
}InstagramLogo function · typescript · L37-L54 (18 LOC)src/components/sections/Testimonials.tsx
function InstagramLogo({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" aria-hidden="true">
<defs>
<linearGradient id="ig-grad" x1="0%" y1="100%" x2="100%" y2="0%">
<stop offset="0%" stopColor="#FED373" />
<stop offset="25%" stopColor="#F15245" />
<stop offset="50%" stopColor="#D92E7F" />
<stop offset="75%" stopColor="#9B36B7" />
<stop offset="100%" stopColor="#515ECF" />
</linearGradient>
</defs>
<rect x="2" y="2" width="20" height="20" rx="5" stroke="url(#ig-grad)" strokeWidth="2" />
<circle cx="12" cy="12" r="5" stroke="url(#ig-grad)" strokeWidth="2" />
<circle cx="17.5" cy="6.5" r="1.5" fill="url(#ig-grad)" />
</svg>
);
}Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
FacebookLogo function · typescript · L56-L65 (10 LOC)src/components/sections/Testimonials.tsx
function FacebookLogo({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M24 12c0-6.627-5.373-12-12-12S0 5.373 0 12c0 5.99 4.388 10.954 10.125 11.854V15.47H7.078V12h3.047V9.356c0-3.007 1.792-4.668 4.533-4.668 1.312 0 2.686.234 2.686.234v2.953H15.83c-1.491 0-1.956.925-1.956 1.875V12h3.328l-.532 3.47h-2.796v8.385C19.612 22.954 24 17.99 24 12z"
fill="#1877F2"
/>
</svg>
);
}LinkedInLogo function · typescript · L67-L76 (10 LOC)src/components/sections/Testimonials.tsx
function LinkedInLogo({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 1 1 0-4.124 2.062 2.062 0 0 1 0 4.124zM6.89 20.452H3.58V9h3.31v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"
fill="#0A66C2"
/>
</svg>
);
}RateMyAgentLogo function · typescript · L78-L88 (11 LOC)src/components/sections/Testimonials.tsx
function RateMyAgentLogo({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" aria-hidden="true">
<rect x="1" y="1" width="22" height="22" rx="4" fill="#00B67A" />
<path
d="M12 5l1.76 3.56L17.5 9.2l-2.75 2.68.65 3.78L12 13.86l-3.4 1.8.65-3.78L6.5 9.2l3.74-.64L12 5z"
fill="white"
/>
</svg>
);
}TestimonialCard function · typescript · L195-L238 (44 LOC)src/components/sections/Testimonials.tsx
function TestimonialCard({ testimonial }: { testimonial: Testimonial }) {
return (
<div
className={cn(
"mb-4 flex w-full cursor-default break-inside-avoid flex-col justify-between gap-5 p-6",
"border border-border bg-background-secondary/50",
"transition-all duration-300 hover:-translate-y-0.5 hover:border-accent/20 hover:shadow-lg hover:shadow-accent/5"
)}
>
{/* Stars */}
<div>
<div className="flex gap-0.5">
{Array.from({ length: 5 }).map((_, i) => (
<Star key={i} className="h-3.5 w-3.5 fill-warm text-warm" />
))}
</div>
{/* Quote */}
<blockquote className="mt-4 text-sm leading-relaxed text-text-secondary">
“{testimonial.quote}”
</blockquote>
</div>
{/* Attribution */}
<div className="flex items-center gap-3 border-t border-border pt-4">
{/* Avatar placeholder with initials */}
<div className="flex hTestimonials function · typescript · L244-L371 (128 LOC)src/components/sections/Testimonials.tsx
export default function Testimonials() {
return (
<section className="relative bg-background py-16 md:py-24 lg:py-32 overflow-hidden">
{/* Decorative blurs */}
<div className="absolute top-20 -left-20 h-64 w-64 rounded-full bg-accent/5 blur-[100px]" />
<div className="absolute -right-20 bottom-20 h-64 w-64 rounded-full bg-warm/5 blur-[100px]" />
<div className="relative mx-auto max-w-7xl px-6 lg:px-10">
{/* Header */}
<AnimateIn>
<div className="text-center">
<p className="text-xs font-medium tracking-[0.3em] text-accent uppercase">
Testimonials
</p>
<h2 className="mt-4 font-heading text-4xl font-light tracking-tight text-text-primary md:text-5xl">
What Clients Say
</h2>
<p className="mx-auto mt-4 max-w-lg text-text-secondary">
Don't just take my word for it. Here's what{" "}
<span className="font-medium thandleMouseMove function · typescript · L18-L26 (9 LOC)src/components/ui/aceternity-input.tsx
function handleMouseMove({
currentTarget,
clientX,
clientY,
}: React.MouseEvent) {
const { left, top } = currentTarget.getBoundingClientRect();
mouseX.set(clientX - left);
mouseY.set(clientY - top);
}AnimateIn function · typescript · L13-L38 (26 LOC)src/components/ui/AnimateIn.tsx
export default function AnimateIn({
children,
className,
delay = 0,
direction = "up",
}: AnimateInProps) {
const directionOffset = {
up: { y: 40 },
down: { y: -40 },
left: { x: 40 },
right: { x: -40 },
none: {},
};
return (
<motion.div
initial={{ opacity: 0, ...directionOffset[direction] }}
whileInView={{ opacity: 1, x: 0, y: 0 }}
viewport={{ once: true, margin: "-80px" }}
transition={{ duration: 0.7, delay, ease: [0.25, 0.4, 0.25, 1] }}
className={cn(className)}
>
{children}
</motion.div>
);
}BackToTop function · typescript · L7-L42 (36 LOC)src/components/ui/BackToTop.tsx
export default function BackToTop() {
const [visible, setVisible] = useState(false);
useEffect(() => {
function handleScroll() {
setVisible(window.scrollY > 500);
}
window.addEventListener("scroll", handleScroll, { passive: true });
handleScroll();
return () => window.removeEventListener("scroll", handleScroll);
}, []);
function scrollToTop() {
window.scrollTo({ top: 0, behavior: "smooth" });
}
return (
<AnimatePresence>
{visible ? (
<motion.button
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.3, ease: [0.25, 0.4, 0.25, 1] }}
onClick={scrollToTop}
aria-label="Back to top"
className="fixed bottom-24 right-4 z-50 flex h-11 w-11 items-center justify-center rounded-full border border-accent bg-background text-accent transition-colors duration-300 hover:bg-accent hover:textRepobility — same analyzer, your code, free for public repos · /scan/
handleScroll function · typescript · L11-L13 (3 LOC)src/components/ui/BackToTop.tsx
function handleScroll() {
setVisible(window.scrollY > 500);
}scrollToTop function · typescript · L21-L23 (3 LOC)src/components/ui/BackToTop.tsx
function scrollToTop() {
window.scrollTo({ top: 0, behavior: "smooth" });
}Badge function · typescript · L25-L41 (17 LOC)src/components/ui/Badge.tsx
export default function Badge({
children,
variant = "accent",
size = "sm",
}: BadgeProps) {
return (
<span
className={cn(
"inline-flex items-center rounded-full border font-medium tracking-[0.1em] uppercase",
variantStyles[variant],
sizeStyles[size]
)}
>
{children}
</span>
);
}Button function · typescript · L58-L111 (54 LOC)src/components/ui/Button.tsx
export default function Button({
variant = "primary",
size = "md",
href,
showArrow = false,
loading = false,
children,
className,
...rest
}: ButtonProps) {
const baseClasses = cn(
"group inline-flex items-center justify-center font-medium uppercase transition-all duration-300",
variantStyles[variant],
sizeStyles[size],
loading && "pointer-events-none opacity-70",
className
);
const content = (
<>
{loading ? (
<Loader2 className="h-3.5 w-3.5 animate-spin" />
) : null}
<span>{children}</span>
{showArrow && !loading ? (
<ArrowRight className="h-3.5 w-3.5 transition-transform duration-300 group-hover:translate-x-1" />
) : null}
</>
);
if (href) {
const { disabled } = rest as ButtonAsLink;
if (disabled) {
return (
<span className={cn(baseClasses, "pointer-events-none opacity-40")} aria-disabled="true">
{content}
</span>
);
}
return (
Card function · typescript · L20-L48 (29 LOC)src/components/ui/Card.tsx
export default function Card({
href,
children,
className,
hoverable = true,
padding = "md",
}: CardProps) {
const cardClasses = cn(
"border border-border bg-background-secondary transition-all duration-500",
paddingMap[padding],
hoverable && "hover:border-accent/30",
href && hoverable && "cursor-pointer",
className
);
if (href) {
return (
<Link href={href} className={cn(cardClasses, "block")}>
{children}
</Link>
);
}
return (
<div className={cardClasses}>
{children}
</div>
);
}Container function · typescript · L18-L35 (18 LOC)src/components/ui/Container.tsx
export default function Container({
size = "lg",
children,
className,
as: Component = "div",
}: ContainerProps) {
return (
<Component
className={cn(
"mx-auto px-6 lg:px-10",
sizeMap[size],
className
)}
>
{children}
</Component>
);
}GradualBlur function · typescript · L56-L170 (115 LOC)src/components/ui/GradualBlur.tsx
function GradualBlur({
position = "bottom",
strength = 2,
height = "6rem",
divCount = 5,
exponential = false,
zIndex = 1000,
opacity = 1,
curve = "linear",
target = "parent",
className = "",
style = {},
}: GradualBlurProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
/* Build the layered blur divs */
const blurDivs = useMemo(() => {
const divs: React.ReactNode[] = [];
const increment = 100 / divCount;
const curveFunc = CURVE_FUNCTIONS[curve] || CURVE_FUNCTIONS.linear;
const direction = GRADIENT_DIRECTION[position] || "to bottom";
for (let i = 1; i <= divCount; i++) {
let progress = i / divCount;
progress = curveFunc(progress);
const blurValue = exponential
? Math.pow(2, progress * 4) * 0.0625 * strength
: 0.0625 * (progress * divCount + 1) * strength;
const p1 = Math.round((increment * Input function · typescript · L28-L119 (92 LOC)src/components/ui/Input.tsx
function Input(
{
label,
type = "text",
error,
required,
as = "input",
options = [],
rows = 5,
className,
id,
...rest
},
ref
) {
const fieldId = id || (label ? label.toLowerCase().replace(/\s+/g, "-") : undefined);
const fieldClasses = cn(
baseFieldStyles,
error && "border-red-500 focus:border-red-500",
className
);
const renderField = () => {
if (as === "textarea") {
return (
<textarea
ref={ref as React.Ref<HTMLTextAreaElement>}
id={fieldId}
rows={rows}
required={required}
className={cn(fieldClasses, "resize-none")}
{...(rest as React.TextareaHTMLAttributes<HTMLTextAreaElement>)}
/>
);
}
if (as === "select") {
return (
<select
ref={ref as React.Ref<HTMLSelectElement>}
id={fieldId}
required={requirRepobility · code-quality intelligence · https://repobility.com
Marquee function · typescript · L13-L51 (39 LOC)src/components/ui/Marquee.tsx
export function Marquee({
className,
reverse = false,
pauseOnHover = false,
children,
vertical = false,
repeat = 4,
...props
}: MarqueeProps) {
return (
<div
{...props}
className={cn(
"group flex overflow-hidden p-2 [--duration:40s] [--gap:1rem] [gap:var(--gap)]",
{
"flex-row": !vertical,
"flex-col": vertical,
},
className
)}
>
{Array(repeat)
.fill(0)
.map((_, i) => (
<div
key={i}
className={cn("flex shrink-0 justify-around [gap:var(--gap)]", {
"animate-marquee flex-row": !vertical,
"animate-marquee-vertical flex-col": vertical,
"group-hover:[animation-play-state:paused]": pauseOnHover,
"[animation-direction:reverse]": reverse,
})}
>
{children}
</div>
))}
</div>
);
}PageBlurEdges function · typescript · L12-L42 (31 LOC)src/components/ui/PageBlurEdges.tsx
export default function PageBlurEdges() {
return (
<>
{/* Top edge — below navbar */}
<GradualBlur
target="page"
position="top"
height="7rem"
strength={2}
divCount={5}
curve="bezier"
exponential
opacity={1}
zIndex={30}
/>
{/* Bottom edge — above footer */}
<GradualBlur
target="page"
position="bottom"
height="7rem"
strength={2}
divCount={5}
curve="bezier"
exponential
opacity={1}
zIndex={30}
/>
</>
);
}PageHero function · typescript · L21-L82 (62 LOC)src/components/ui/PageHero.tsx
export default function PageHero({
label,
heading,
accentText,
description,
children,
size = "md",
}: PageHeroProps) {
return (
<section
className={cn(
"relative flex items-center justify-center overflow-hidden",
sizeMap[size]
)}
>
{/* Background gradient */}
<div className="absolute inset-0">
<div className="absolute inset-0 bg-gradient-to-b from-background-tertiary via-background to-background" />
<div className="absolute inset-0 opacity-[0.03]" style={{
backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E")`,
}} />
</div>
{/* Subtle glow orbs */}
<div className="absolute top-1/3 left-1/2 h-[400px] w-[400px] -tranProgress function · typescript · L11-L25 (15 LOC)src/components/ui/Progress.tsx
export default function Progress({ value, className }: ProgressProps) {
return (
<div
className={cn(
"h-1.5 w-full overflow-hidden rounded-full bg-background-secondary",
className
)}
>
<div
className="h-full rounded-full bg-warm transition-all duration-500 ease-out"
style={{ width: `${Math.min(100, Math.max(0, value))}%` }}
/>
</div>
);
}ScrollProgress function · typescript · L5-L36 (32 LOC)src/components/ui/ScrollProgress.tsx
export default function ScrollProgress() {
const [progress, setProgress] = useState(0);
useEffect(() => {
function handleScroll() {
const scrollTop = window.scrollY;
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
if (docHeight <= 0) {
setProgress(0);
return;
}
const scrollPercent = (scrollTop / docHeight) * 100;
setProgress(Math.min(scrollPercent, 100));
}
window.addEventListener("scroll", handleScroll, { passive: true });
handleScroll();
return () => window.removeEventListener("scroll", handleScroll);
}, []);
return (
<div className="fixed top-0 left-0 right-0 z-50 h-[2px] bg-transparent">
<div
className="h-full bg-accent transition-[width] duration-100 ease-out"
style={{ width: `${progress}%` }}
/>
</div>
);
}handleScroll function · typescript · L9-L20 (12 LOC)src/components/ui/ScrollProgress.tsx
function handleScroll() {
const scrollTop = window.scrollY;
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
if (docHeight <= 0) {
setProgress(0);
return;
}
const scrollPercent = (scrollTop / docHeight) * 100;
setProgress(Math.min(scrollPercent, 100));
}ScrollRestoration function · typescript · L10-L18 (9 LOC)src/components/ui/ScrollRestoration.tsx
export default function ScrollRestoration() {
const pathname = usePathname();
useEffect(() => {
window.scrollTo({ top: 0, left: 0, behavior: "instant" });
}, [pathname]);
return null;
}SectionHeader function · typescript · L12-L55 (44 LOC)src/components/ui/SectionHeader.tsx
export default function SectionHeader({
label,
heading,
accentText,
description,
align = "center",
className,
}: SectionHeaderProps) {
return (
<div
className={cn(
align === "center" ? "text-center" : "text-left",
className
)}
>
{label ? (
<p className="mb-4 text-xs font-medium tracking-[0.3em] text-accent uppercase">
{label}
</p>
) : null}
<h2 className="font-heading text-3xl font-light leading-tight tracking-tight text-text-primary sm:text-4xl md:text-5xl">
{heading}
{accentText ? (
<>
{" "}
<span className="italic text-accent">{accentText}</span>
</>
) : null}
</h2>
{description ? (
<p
className={cn(
"mt-5 text-base leading-relaxed text-text-secondary",
align === "center" && "mx-auto max-w-2xl"
)}
>
{description}
</p>
) : null}About: code-quality intelligence by Repobility · https://repobility.com
Skeleton function · typescript · L17-L31 (15 LOC)src/components/ui/Skeleton.tsx
export default function Skeleton({
className,
variant = "text",
}: SkeletonProps) {
return (
<div
className={cn(
"animate-shimmer bg-background-secondary",
variantStyles[variant],
className
)}
aria-hidden="true"
/>
);
}getAllPosts function · typescript · L5-L9 (5 LOC)src/lib/blog.ts
export function getAllPosts(): BlogPost[] {
return [...posts].sort(
(a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()
);
}getPostBySlug function · typescript · L12-L14 (3 LOC)src/lib/blog.ts
export function getPostBySlug(slug: string): BlogPost | undefined {
return posts.find((p) => p.slug === slug);
}getAllSlugs function · typescript · L17-L19 (3 LOC)src/lib/blog.ts
export function getAllSlugs(): string[] {
return posts.filter((p) => p.content).map((p) => p.slug);
}getCategories function · typescript · L22-L25 (4 LOC)src/lib/blog.ts
export function getCategories(): string[] {
const cats = new Set(posts.map((p) => p.category));
return Array.from(cats).sort();
}createMetadata function · typescript · L24-L76 (53 LOC)src/lib/metadata.ts
export function createMetadata({
title,
description = "Premium real estate services in Kelowna, BC. Buy, sell, or get your home value with Karsen Koltun at Royal LePage.",
path = "",
ogImage = "/og-image.jpg",
noIndex = false,
}: CreateMetadataOptions = {}): Metadata {
const url = `${BASE_URL}${path}`;
const fullOgImage = ogImage.startsWith("http")
? ogImage
: `${BASE_URL}${ogImage}`;
return {
title: title ?? {
default: "Karsen Koltun | Kelowna Real Estate",
template: "%s | Karsen Koltun",
},
description,
metadataBase: new URL(BASE_URL),
alternates: {
canonical: url,
},
openGraph: {
type: "website",
locale: "en_CA",
url,
siteName: "Karsen Koltun | Kelowna Real Estate",
title: title
? `${title} | Karsen Koltun`
: "Karsen Koltun | Kelowna Real Estate",
description,
images: [
{
url: fullOgImage,
width: 1200,
height: 630,
getMonthlyRate function · typescript · L73-L77 (5 LOC)src/lib/mortgage.ts
export function getMonthlyRate(annualRate: number): number {
if (annualRate <= 0) return 0;
const semiAnnualRate = annualRate / 2;
return Math.pow(1 + semiAnnualRate, 1 / 6) - 1;
}calcMonthlyPayment function · typescript · L81-L90 (10 LOC)src/lib/mortgage.ts
export function calcMonthlyPayment(
principal: number,
annualRate: number,
amortYears: number
): number {
const r = getMonthlyRate(annualRate);
const n = amortYears * 12;
if (r === 0) return principal / n;
return (principal * (r * Math.pow(1 + r, n))) / (Math.pow(1 + r, n) - 1);
}Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
calcCMHC function · typescript · L94-L115 (22 LOC)src/lib/mortgage.ts
export function calcCMHC(
homePrice: number,
downPayment: number,
amortYears: number,
isFirstTimeBuyer: boolean
): number {
const mortgageAmount = homePrice - downPayment;
const ltv = mortgageAmount / homePrice;
if (ltv <= 0.8) return 0;
if (homePrice > 1_500_000) return 0;
let rate: number;
if (ltv > 0.9) rate = 0.04;
else if (ltv > 0.85) rate = 0.031;
else rate = 0.028;
// 30yr surcharge for eligible buyers
if (amortYears > 25 && isFirstTimeBuyer) rate += 0.002;
return mortgageAmount * rate;
}calcMinimumDownPayment function · typescript · L119-L127 (9 LOC)src/lib/mortgage.ts
export function calcMinimumDownPayment(homePrice: number): number {
if (homePrice <= 500_000) {
return homePrice * 0.05;
} else if (homePrice < 1_500_000) {
return 500_000 * 0.05 + (homePrice - 500_000) * 0.1;
} else {
return homePrice * 0.2;
}
}calcBCPTT function · typescript · L131-L149 (19 LOC)src/lib/mortgage.ts
export function calcBCPTT(homePrice: number): number {
let tax = 0;
if (homePrice > 3_000_000) {
tax += (homePrice - 3_000_000) * 0.05;
tax += 1_000_000 * 0.03;
tax += 1_800_000 * 0.02;
tax += 200_000 * 0.01;
} else if (homePrice > 2_000_000) {
tax += (homePrice - 2_000_000) * 0.03;
tax += 1_800_000 * 0.02;
tax += 200_000 * 0.01;
} else if (homePrice > 200_000) {
tax += (homePrice - 200_000) * 0.02;
tax += 200_000 * 0.01;
} else {
tax += homePrice * 0.01;
}
return tax;
}