diff --git a/apps/docs/app/components/chords-logo.tsx b/apps/docs/app/components/chords-logo.tsx index ed1b439..2bdce9e 100644 --- a/apps/docs/app/components/chords-logo.tsx +++ b/apps/docs/app/components/chords-logo.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect, useRef, useId } from "react"; +import { useState, useEffect, useRef } from "react"; interface ChordsLogoProps { size?: "sm" | "lg"; @@ -61,105 +61,84 @@ export function ChordsLogo({ ); } -export function ChordsLogoAnimated({ className }: { className?: string }) { - const [done, setDone] = useState(false); - const svgRef = useRef(null); - const gradientRef = useRef(null); - const id = useId(); - const gradientId = `chords-glow-${id}`; +export function ChordsLogoAnimated() { + const textRef = useRef(null); + const shimmerRef = useRef(null); + const [shimmerDone, setShimmerDone] = useState(false); - const { height, fontSize } = sizes.lg; - const width = Math.round(fontSize * 0.55 * 6.5); + const v = variants.styled; + const { fontSize } = sizes.lg; + // Listen for shimmer animation end useEffect(() => { - const id = setTimeout(() => setDone(true), 100); - return () => clearTimeout(id); + const el = shimmerRef.current; + if (!el) return; + const onEnd = () => setShimmerDone(true); + el.addEventListener("animationiteration", onEnd); + return () => el.removeEventListener("animationiteration", onEnd); }, []); - const glowRef = useRef(null); - + // Mouse-follow radial glow via CSS background (active after shimmer) useEffect(() => { - const onMouseMove = (e: MouseEvent) => { - const svg = svgRef.current; - const gradient = gradientRef.current; - const glow = glowRef.current; - if (!svg || !gradient || !glow) return; + if (!shimmerDone) return; + + const el = textRef.current; + if (!el) return; - // Theme-aware glow color + // Set initial state — show text in currentColor until mouse moves + el.style.backgroundImage = "linear-gradient(currentColor, currentColor)"; + el.style.backgroundClip = "text"; + (el.style as unknown as Record).WebkitBackgroundClip = "text"; + el.style.webkitTextFillColor = "transparent"; + + const onMouseMove = (e: MouseEvent) => { const isDark = document.documentElement.classList.contains("dark"); - glow.setAttribute("stop-color", isDark ? "#f0c040" : "white"); + const glowColor = isDark ? "#FFD700" : "white"; - // Check if mouse is directly over the logo - const rect = svg.getBoundingClientRect(); + const rect = el.getBoundingClientRect(); const overLogo = e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom; + let x: number, y: number, r: number; if (overLogo) { - // Tight spotlight tracking the cursor on the letters - const x = (e.clientX - rect.left) / rect.width; - const y = (e.clientY - rect.top) / rect.height; - gradient.setAttribute("cx", String(x)); - gradient.setAttribute("cy", String(y)); - gradient.setAttribute("r", "0.2"); + x = ((e.clientX - rect.left) / rect.width) * 100; + y = ((e.clientY - rect.top) / rect.height) * 100; + r = 40; } else { - // Map full page to logo area - const x = e.clientX / window.innerWidth; - const y = e.clientY / window.innerHeight; - gradient.setAttribute("cx", String(x)); - gradient.setAttribute("cy", String(y)); - gradient.setAttribute("r", "0.35"); + x = (e.clientX / window.innerWidth) * 100; + y = (e.clientY / window.innerHeight) * 100; + r = 80; } + + el.style.backgroundImage = `radial-gradient(circle ${r}px at ${x}% ${y}%, ${glowColor}, currentColor 60%)`; }; document.addEventListener("mousemove", onMouseMove); return () => document.removeEventListener("mousemove", onMouseMove); - }, []); + }, [shimmerDone]); + + const textStyle: React.CSSProperties = { + fontFamily: v.fontFamily, + fontWeight: v.fontWeight, + fontSize, + display: "inline-block", + }; return ( - { + textRef.current = node; + shimmerRef.current = node; + }} + className={shimmerDone ? "shimmer-logo-gold" : "shimmer shimmer-logo-gold"} + style={textStyle} role="img" aria-label="Chords" - style={{ overflow: "visible" }} > - - - - - - - - - Chords - - + Chords + ); } diff --git a/apps/docs/app/globals.css b/apps/docs/app/globals.css index d785d5f..52787da 100644 --- a/apps/docs/app/globals.css +++ b/apps/docs/app/globals.css @@ -1,4 +1,3 @@ -@import url("https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400..700&family=Lato:wght@100&family=Style+Script&display=swap"); @import "tailwindcss"; @import "fumadocs-ui/css/neutral.css"; @import "fumadocs-ui/css/preset.css"; @@ -14,6 +13,11 @@ --color-fd-background: #0A0A0A; } +/* Golden shimmer for logo in dark mode */ +.dark .shimmer-logo-gold { + --shimmer-color: #FFD700; +} + /* Match sidebar bg to page background without affecting card components */ :root #nd-sidebar, .dark #nd-sidebar { diff --git a/apps/docs/app/layout.tsx b/apps/docs/app/layout.tsx index 39f77d3..8d9140d 100644 --- a/apps/docs/app/layout.tsx +++ b/apps/docs/app/layout.tsx @@ -16,6 +16,14 @@ export const metadata: Metadata = { export default function RootLayout({ children }: { children: ReactNode }) { return ( + + + + + diff --git a/apps/docs/app/page.tsx b/apps/docs/app/page.tsx index 11bde92..d81481c 100644 --- a/apps/docs/app/page.tsx +++ b/apps/docs/app/page.tsx @@ -75,7 +75,7 @@ export default function HomePage() {

- +

You own the UI. We handle the wiring.