- Add Next.js frontend service (nextjs) with Dockerfile and source - Update docker-compose.yml: image names, Drupal 11.3.3, nextjs service - Add docker-compose.override.yml.disabled for dev hot-reload - Add install-headless-modules.sh for OAuth/JSON:API module setup - Add README.md with full setup and configuration guide - Update nginx/Dockerfile and nginx.conf.template for cms. subdomain - Update drupal/Dockerfile PHP-FPM build args - Gitignore **/.vscode/ to prevent IDE workspace files from being tracked
78 lines
2.3 KiB
TypeScript
78 lines
2.3 KiB
TypeScript
"use client"
|
|
|
|
const TEXT = "I'm Robert."
|
|
|
|
type Direction = "up" | "down" | "r" | "e" | "t"
|
|
|
|
const LETTER_ANIMS: Record<number, Direction> = {
|
|
0: "down", // I
|
|
1: "up", // '
|
|
2: "down", // m
|
|
3: "down", // space - treat as down for delay
|
|
4: "r", // R (special)
|
|
5: "down", // o
|
|
6: "up", // b
|
|
7: "e", // e (special: o first, then e)
|
|
8: "down", // r
|
|
9: "t", // t (special: appears with o, then slides right)
|
|
10: "down", // .
|
|
}
|
|
|
|
const DELAYS_MS = [0, 80, 240, 320, 400, 560, 680, 760, 1400, 760, 1560]
|
|
|
|
export function AnimatedHeroTitle() {
|
|
return (
|
|
<h1
|
|
className="home-hero-title mb-2 font-bold tracking-tight text-slate-900"
|
|
style={{ fontSize: "var(--fluid-hero)" }}
|
|
>
|
|
{TEXT.split("").map((char, i) => {
|
|
if (char === " ") {
|
|
return <span key={i} className="inline-block" style={{ width: "0.25em" }} aria-hidden />
|
|
}
|
|
const dir = LETTER_ANIMS[i] ?? "down"
|
|
const delay = DELAYS_MS[i] ?? i * 80
|
|
|
|
const animClass =
|
|
dir === "r"
|
|
? "hero-letter-r animate-letter-from-up"
|
|
: dir === "e"
|
|
? "hero-letter-e"
|
|
: dir === "t"
|
|
? "hero-letter-t animate-letter-t-slide"
|
|
: dir === "up"
|
|
? "animate-letter-from-up"
|
|
: "animate-letter-from-down"
|
|
const animDelay =
|
|
dir === "r" ? delay + 320 : dir === "e" ? delay + 1050 : delay
|
|
const style =
|
|
dir === "r"
|
|
? { "--b-delay": `${delay}ms`, animationDelay: `${animDelay}ms` } as React.CSSProperties
|
|
: dir === "e"
|
|
? { "--o-delay": `${delay}ms` } as React.CSSProperties
|
|
: { animationDelay: `${animDelay}ms` }
|
|
|
|
return (
|
|
<span
|
|
key={i}
|
|
className={`inline-block overflow-hidden ${animClass}`}
|
|
style={style}
|
|
aria-hidden
|
|
>
|
|
{dir === "e" ? (
|
|
<span className="block animate-letter-e-fade-in" style={{ animationDelay: `${animDelay}ms` }}>
|
|
e
|
|
</span>
|
|
) : dir === "r" ? (
|
|
"R"
|
|
) : dir === "t" ? (
|
|
"t"
|
|
) : (
|
|
char
|
|
)}
|
|
</span>
|
|
)
|
|
})}
|
|
</h1>
|
|
)
|
|
}
|