129 lines
3.8 KiB
TypeScript
129 lines
3.8 KiB
TypeScript
import { useEffect, useRef, useState } from "react";
|
|
import { Card } from "@/components/ui/card";
|
|
import { Button } from "@/components/ui/button";
|
|
import type { PaletteRole } from "./ThemePaletteGrid";
|
|
|
|
const ROLE_TO_TOKEN: Record<string, string> = {
|
|
background: "--background",
|
|
surface: "--card",
|
|
overlay: "--secondary",
|
|
text: "--foreground",
|
|
"accent-1": "--primary",
|
|
"accent-2": "--accent",
|
|
"accent-3": "--muted",
|
|
};
|
|
|
|
interface ThemePreviewPanelProps {
|
|
palette: PaletteRole[];
|
|
variant: "dark" | "light";
|
|
className?: string;
|
|
}
|
|
|
|
export function ThemePreviewPanel({
|
|
palette,
|
|
variant,
|
|
className,
|
|
}: ThemePreviewPanelProps) {
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
const [announcement, setAnnouncement] = useState("");
|
|
|
|
useEffect(() => {
|
|
const container = containerRef.current;
|
|
if (!container || palette.length === 0) return;
|
|
|
|
palette.forEach((role) => {
|
|
const tokenName = ROLE_TO_TOKEN[role.name];
|
|
if (!tokenName) return;
|
|
const value = variant === "dark" ? role.dark.hex : role.light.hex;
|
|
container.style.setProperty(tokenName, value);
|
|
});
|
|
|
|
setAnnouncement("Palette updated");
|
|
}, [palette, variant]);
|
|
|
|
return (
|
|
<div
|
|
ref={containerRef}
|
|
className={`nexus-theme-preview relative rounded-lg border border-[var(--border,hsl(var(--border)))] overflow-hidden${className ? ` ${className}` : ""}`}
|
|
aria-label="Theme preview"
|
|
style={{ backgroundColor: "var(--background, #1e1e2e)" }}
|
|
>
|
|
{/* Visually hidden aria-live announcer */}
|
|
<div
|
|
aria-live="polite"
|
|
aria-atomic="true"
|
|
className="sr-only"
|
|
>
|
|
{announcement}
|
|
</div>
|
|
|
|
{/* Mini Nexus UI mock */}
|
|
<div className="flex h-40">
|
|
{/* Narrow sidebar strip */}
|
|
<div
|
|
className="flex flex-col items-center gap-2 py-3 px-2"
|
|
style={{
|
|
width: 48,
|
|
backgroundColor: "var(--card, #181825)",
|
|
borderRight: "1px solid var(--border, #313244)",
|
|
}}
|
|
>
|
|
<div
|
|
className="h-5 w-5 rounded"
|
|
style={{ backgroundColor: "var(--primary, #89b4fa)" }}
|
|
/>
|
|
<div
|
|
className="h-4 w-4 rounded opacity-60"
|
|
style={{ backgroundColor: "var(--muted, #313244)" }}
|
|
/>
|
|
<div
|
|
className="h-4 w-4 rounded opacity-60"
|
|
style={{ backgroundColor: "var(--muted, #313244)" }}
|
|
/>
|
|
</div>
|
|
|
|
{/* Main content area */}
|
|
<div
|
|
className="flex-1 p-3"
|
|
style={{ backgroundColor: "var(--background, #1e1e2e)" }}
|
|
>
|
|
<Card
|
|
className="p-3 h-full"
|
|
style={{
|
|
backgroundColor: "var(--card, #181825)",
|
|
color: "var(--foreground, #cdd6f4)",
|
|
border: "1px solid var(--border, #313244)",
|
|
}}
|
|
>
|
|
<div className="flex flex-col gap-2 h-full">
|
|
<div
|
|
className="h-3 w-3/4 rounded"
|
|
style={{ backgroundColor: "var(--foreground, #cdd6f4)", opacity: 0.7 }}
|
|
/>
|
|
<div
|
|
className="h-2 w-full rounded"
|
|
style={{ backgroundColor: "var(--muted, #313244)" }}
|
|
/>
|
|
<div
|
|
className="h-2 w-2/3 rounded"
|
|
style={{ backgroundColor: "var(--muted, #313244)" }}
|
|
/>
|
|
<div className="mt-auto">
|
|
<Button
|
|
size="xs"
|
|
style={{
|
|
backgroundColor: "var(--primary, #89b4fa)",
|
|
color: "var(--primary-foreground, #1e1e2e)",
|
|
}}
|
|
className="border-0"
|
|
>
|
|
Action
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|