Add landing logotype

This commit is contained in:
2026-02-23 20:24:01 +00:00
parent c3fb5e98b9
commit 3eef7d36dd
4 changed files with 198 additions and 14 deletions
+2 -14
View File
@@ -1,3 +1,4 @@
import { Landing } from "@/app/sections/landing";
import { MagneticHoverShowcase } from "@/components/magnetic-hover-showcase";
import { ScrollProgressIndicator } from "@/components/scroll-progress-indicator";
@@ -7,20 +8,7 @@ export default function Home() {
<ScrollProgressIndicator />
<main>
<section
id="landing"
className="flex min-h-screen items-center justify-center px-8 py-16 md:px-16 lg:px-24"
>
<div className="mx-auto max-w-4xl space-y-8 text-center">
<h1 className="font-bold font-heading text-6xl md:text-8xl">Welcome</h1>
<p className="font-body text-xl leading-relaxed md:text-2xl">
Scroll down to explore the sections and test the progress indicator.
</p>
<p className="font-cursive text-3xl text-accent-cyan md:text-4xl">
Watch the dots on the right...
</p>
</div>
</section>
<Landing />
<section id="about" className="min-h-[150vh] px-8 py-16 md:px-16 lg:px-24">
<div className="mx-auto max-w-4xl space-y-16">
+118
View File
@@ -0,0 +1,118 @@
import { LandingClient } from "./landing-client";
const letterSegments: Record<string, [number, number, number, number][]> = {
l: [
[0, 0, 2, 0],
[2, 0, 2, 10],
[2, 10, 0, 10],
[0, 10, 0, 0],
],
u: [
[0, 3, 0, 10],
[0, 10, 4, 10],
[4, 10, 4, 3],
[4, 3, 0, 3],
[2, 3, 2, 8],
],
i: [
[0, 3, 2, 3],
[2, 3, 2, 10],
[2, 10, 0, 10],
[0, 10, 0, 3],
[0, 0.5, 2, 0.5],
[2, 0.5, 2, 2.5],
[2, 2.5, 0, 2.5],
[0, 2.5, 0, 0.5],
],
s: [
[0, 3, 5, 3],
[0, 10, 5, 10],
[0, 3, 0, 7.67],
[0, 7.67, 0, 10],
[5, 3, 5, 5.33],
[5, 5.33, 5, 10],
[2, 5.33, 5, 5.33],
[0, 7.67, 3, 7.67],
],
d: [
[2, 0, 4, 0],
[4, 0, 4, 10],
[0, 3, 0, 10],
[0, 10, 4, 10],
[0, 3, 2, 3],
[2, 3, 2, 0],
[2, 5, 2, 8],
],
r: [
[0, 3, 4, 3],
[2, 5.33, 2, 10],
[2, 10, 0, 10],
[0, 10, 0, 3],
[4, 3, 4, 5.33],
[2, 5.33, 4, 5.33],
],
a: [
[0, 3, 0, 5.33],
[0, 5.33, 0, 10],
[0, 10, 5, 10],
[5, 10, 5, 3],
[5, 3, 0, 3],
[0, 5.33, 3, 5.33],
[2, 7.67, 3, 7.67],
],
v: [
[0, 3, 1.5, 10],
[5, 3, 3.5, 10],
[1.5, 10, 3.5, 10],
[2, 3, 2.5, 8],
[3, 3, 2.5, 8],
[0, 3, 2, 3],
[3, 3, 5, 3],
],
e: [
[5, 3, 5, 10],
[0, 3, 5, 3],
[0, 3, 0, 10],
[5, 10, 0, 10],
[5, 7.67, 2, 7.67],
[2, 5.33, 3, 5.33],
],
};
const letterLayout: [string, number][] = [
["l", 0],
["u", 2.5],
["i", 7],
["s", 9.5],
["d", 15],
["r", 19.5],
["a", 24],
["l", 29.5],
["v", 32],
["e", 37.5],
["s", 43],
];
const allPaths = letterLayout.reduce<{ d: string; key: string }[]>(
(paths, [letterKey, xOffset]) => {
const letter = letterSegments[letterKey];
if (letter) {
letter.forEach(([x1, y1, x2, y2]) => {
paths.push({
d: `M${x1 + xOffset},${y1} L${x2 + xOffset},${y2}`,
key: `seg-${paths.length}`,
});
});
}
return paths;
},
[],
);
export const Landing = () => {
return (
<section id="landing">
<LandingClient paths={allPaths} />
</section>
);
};
@@ -0,0 +1,63 @@
"use client";
import { type MotionValue, m, useScroll, useTransform } from "motion/react";
import { useRef } from "react";
import { springGentle } from "@/lib/motion";
const STROKE_WIDTH = 0.05;
const LogotypePath = ({
d,
scrollProgress,
}: {
d: string;
scrollProgress: MotionValue<number>;
}) => {
const strokeDashoffset = useTransform(scrollProgress, [0, 0.6], [0, 1]);
return (
<m.path
d={d}
pathLength={1}
strokeDasharray={1}
initial={{ strokeDashoffset: 1, opacity: 0 }}
animate={{ strokeDashoffset: 0, opacity: 1 }}
style={{ strokeDashoffset }}
transition={springGentle}
data-scroll-animated="stroke-dashoffset:0"
/>
);
};
type Props = {
paths: { d: string; key: string }[];
};
export const LandingClient = ({ paths }: Props) => {
const containerRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({
target: containerRef,
offset: ["start start", "end start"],
});
return (
<div ref={containerRef} className="flex min-h-screen w-full items-center justify-center">
<m.svg
role="img"
aria-label="luisdralves"
viewBox="-0.5 -0.5 49 11"
className="w-[90vw] max-w-6xl text-foreground"
fill="none"
stroke="currentColor"
strokeWidth={STROKE_WIDTH}
strokeLinecap="square"
strokeLinejoin="miter"
>
{paths.map(({ d, key }) => (
<LogotypePath key={key} d={d} scrollProgress={scrollYProgress} />
))}
</m.svg>
</div>
);
};
@@ -36,6 +36,21 @@ export const RadialReveal = ({ targetSection, origin, onComplete }: Props) => {
clone.style.transform = `translateY(-${clampedScrollY}px)`;
clone.style.pointerEvents = "none";
// Reset scroll-animated elements to their initial visual state
// Format: data-scroll-animated="property1:value1;property2:value2"
clone.querySelectorAll("[data-scroll-animated]").forEach((el) => {
const htmlEl = el as HTMLElement | SVGElement;
const resetValues = htmlEl.dataset.scrollAnimated;
if (resetValues) {
resetValues.split(";").forEach((pair) => {
const [property, value] = pair.split(":");
if (property && value !== undefined) {
htmlEl.style.setProperty(property, value);
}
});
}
});
overlayRef.current.innerHTML = "";
overlayRef.current.appendChild(clone);
setIsReady(true);