/* * Editorial markdown components. * * All components use CSS variables from globals.css (no prefix). * Conflicting names with shadcn: --brand-primary, --brand-secondary, * --link-accent, --page-border. */ import { useCallback, useEffect, useRef, useState } from "react"; import Prism from "prismjs"; import "prismjs/components/prism-jsx"; import "prismjs/components/prism-tsx"; import "prismjs/components/prism-bash"; /* ========================================================================= TOC sidebar (fixed left) ========================================================================= */ function useActiveTocId() { const [activeId, setActiveId] = useState(""); useEffect(() => { const headings = document.querySelectorAll("h1[id]"); if (headings.length === 0) { return; } const observer = new IntersectionObserver( (entries) => { const visible: string[] = []; entries.forEach((entry) => { if (entry.isIntersecting && entry.target.id) { visible.push(entry.target.id); } }); if (visible.length > 0) { const sorted = visible.sort((a, b) => { const elA = document.getElementById(a); const elB = document.getElementById(b); if (!elA || !elB) { return 0; } return elA.getBoundingClientRect().top - elB.getBoundingClientRect().top; }); setActiveId(sorted[sorted.length - 1]); } }, { rootMargin: "-80px 0px -75% 0px", threshold: 0, }, ); headings.forEach((heading) => { observer.observe(heading); }); return () => { observer.disconnect(); }; }, []); return activeId; } export function TableOfContents({ items, logo, }: { items: Array<{ label: string; href: string }>; logo?: string; }) { const activeId = useActiveTocId(); return ( ); } /* ========================================================================= Back button (fixed top-right) ========================================================================= */ export function BackButton() { return ( { e.currentTarget.style.color = "var(--text-hover)"; e.currentTarget.style.transform = "scale(1.05)"; }} onMouseLeave={(e) => { e.currentTarget.style.color = "var(--text-secondary)"; e.currentTarget.style.transform = "scale(1)"; }} onMouseDown={(e) => { e.currentTarget.style.transform = "scale(0.95)"; }} onMouseUp={(e) => { e.currentTarget.style.transform = "scale(1.05)"; }} > ); } /* ========================================================================= Typography ========================================================================= */ export function SectionHeading({ id, children }: { id: string; children: React.ReactNode }) { return (

{children}

); } export function P({ children, className = "" }: { children: React.ReactNode; className?: string }) { return (

{children}

); } export function Caption({ children }: { children: React.ReactNode }) { return (

{children}

); } export function A({ href, children }: { href: string; children: React.ReactNode }) { return ( { e.currentTarget.style.textDecoration = "underline"; }} onMouseLeave={(e) => { e.currentTarget.style.textDecoration = "none"; }} > {children} ); } export function Code({ children }: { children: React.ReactNode }) { return ( {children} ); } /* ========================================================================= Layout ========================================================================= */ export function Divider() { return (
); } export function Section({ id, title, children }: { id: string; title: string; children: React.ReactNode }) { return ( <> {title} {children} ); } export function OL({ children }: { children: React.ReactNode }) { return (
    {children}
); } export function List({ children }: { children: React.ReactNode }) { return ( ); } export function Li({ children }: { children: React.ReactNode }) { return
  • {children}
  • ; } /* ========================================================================= Code block with Prism syntax highlighting and line numbers ========================================================================= */ export function CodeBlock({ children, lang = "jsx", lineHeight = "1.85" }: { children: string; lang?: string; lineHeight?: string }) { const codeRef = useRef(null); const lines = children.split("\n"); useEffect(() => { if (codeRef.current) { Prism.highlightElement(codeRef.current); } }, [children]); return (
              
    {children}
    ); } /* ========================================================================= Pixelated placeholder image Uses a tiny pre-generated image with CSS image-rendering: pixelated (nearest-neighbor / point sampling in GPU terms) for a crisp mosaic effect. The real image fades in on top once loaded — no flash because the placeholder stays underneath and the real image starts at opacity 0. ========================================================================= */ export function PixelatedImage({ src, placeholder, alt, width, height, className = "", style, }: { src: string; /** * URL of the tiny pixelated placeholder image. Use a static import so Vite * inlines it as a base64 data URI (all placeholders are < 4KB, well under * Vite's default assetsInlineLimit of 4096 bytes). This makes the * placeholder available synchronously on first render with zero HTTP * requests. Do NOT use dynamic imports or public/ paths — dynamic imports * add a microtask delay, and public/ files bypass Vite's asset pipeline. * * @example * ```tsx * import placeholderScreenshot from "../assets/placeholders/placeholder-screenshot@2x.png"; * * ``` */ placeholder: string; alt: string; width: number; height: number; className?: string; style?: React.CSSProperties; }) { const [loaded, setLoaded] = useState(false); // Handles both the normal onLoad event and the case where the image is // already cached (img.complete is true before React mounts the handler). const imgRef = useCallback((img: HTMLImageElement | null) => { if (img?.complete && img.naturalWidth > 0) { setLoaded(true); } }, []); return (
    {/* Placeholder: tiny image rendered with nearest-neighbor sampling */} {/* Real image: starts invisible, fades in over the placeholder */} {alt} { setLoaded(true); }} style={{ position: "relative", width: "100%", height: "100%", objectFit: "cover", opacity: loaded ? 1 : 0, transition: "opacity 0.4s ease", zIndex: 1, }} />
    ); } /* ========================================================================= Lazy video with pixelated poster placeholder Same visual pattern as PixelatedImage but for