since3-website/modules/landingPage/ui/components/tools/tool-panel.tsx
2026-09-25 00:45:33 +02:00

94 lines
2.9 KiB
TypeScript

"use client"
import { useId, useRef, useState } from "react"
import { motion } from "motion/react"
import { cn } from "@/lib/utils"
import { ContrastTool } from "./contrast-tool"
import { SnippetTool } from "./snippet-tool"
const TOOLS = [
{ key: "kontrast", label: "Kontrast-Check", Component: ContrastTool },
{ key: "snippet", label: "Snippet-Check", Component: SnippetTool },
] as const
type ToolKey = (typeof TOOLS)[number]["key"]
/** Glass panel hosting the live tools, with accessible tabs. */
export function ToolPanel() {
const id = useId()
const [active, setActive] = useState<ToolKey>("kontrast")
const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({})
const select = (key: ToolKey) => {
if (key === active) return
setActive(key)
}
// Arrow keys move between tabs (WAI-ARIA tabs pattern)
const onKeyDown = (event: React.KeyboardEvent) => {
const index = TOOLS.findIndex((tool) => tool.key === active)
const offset = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0
if (!offset) return
event.preventDefault()
const next = TOOLS[(index + offset + TOOLS.length) % TOOLS.length]
select(next.key)
tabRefs.current[next.key]?.focus()
}
const ActiveTool = TOOLS.find((tool) => tool.key === active)!.Component
return (
<div className="glass p-4 sm:p-8">
<div
role="tablist"
aria-label="Werkzeuge"
onKeyDown={onKeyDown}
className="flex w-fit gap-1 rounded-full border border-white/10 p-1"
>
{TOOLS.map((tool) => {
const selected = tool.key === active
return (
<button
key={tool.key}
ref={(node) => {
tabRefs.current[tool.key] = node
}}
role="tab"
type="button"
id={`${id}-tab-${tool.key}`}
aria-selected={selected}
aria-controls={`${id}-panel`}
tabIndex={selected ? 0 : -1}
onClick={() => select(tool.key)}
className={cn(
"relative rounded-full px-4 py-2 font-mono text-label transition-colors duration-200",
selected ? "text-black" : "text-ink-300 hover:text-white"
)}
>
{selected ? (
<motion.span
layoutId={`${id}-indicator`}
className="absolute inset-0 rounded-full bg-white"
transition={{ type: "spring", duration: 0.35, bounce: 0.15 }}
/>
) : null}
<span className="relative">{tool.label}</span>
</button>
)
})}
</div>
<div
role="tabpanel"
id={`${id}-panel`}
aria-labelledby={`${id}-tab-${active}`}
className="mt-8"
>
{/* key resets the tool state when switching tabs */}
<ActiveTool key={active} />
</div>
</div>
)
}