Files
arcadia-admin/app/components/copy-id.tsx
jules 3fcdddefda Phase 7: polish — overview health, reduced-motion, mobile, a11y, copy-ids
- Overview health hero derives from subsystem probes when the backend gives no
  overall status, so it never says "Unknown" next to an all-Healthy Subsystems
  card (the audit's most jarring contradiction). Home error copy now uses the
  Phase-2 describeError instead of raw backend strings.
- Global prefers-reduced-motion guard (transitions, loops, aurora field) +
  motion-reduce on the sidebar width transition.
- Mobile: content reserves a top row (pt-16 md:p-6) so the floating hamburger
  never overlaps the page H1.
- A11y: collapsed rail items get an explicit aria-label.
- Monitoring: disk "busiest mount" tile shows the % as the value and the long
  mount path as a truncated caption, so it no longer clips mid-word.
- New CopyId component (click-to-copy UUIDs), wired into Profile.

Typecheck 36→36, 24-route sweep clean. Remaining items (lib a11y labels,
table aria-sort, dev-only monitoring data) noted in the spec.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 14:40:58 +10:00

52 lines
1.5 KiB
TypeScript

import { useState } from "react"
import { Check, Copy } from "lucide-react"
/**
* A monospace id (UUID, slug, token name) that copies to the clipboard on
* click, with a brief checkmark. Raw ids are common in an admin console and
* useless if you can't get them into a support ticket or a CLI.
*/
export function CopyId({
value,
label,
className = "",
dataAction,
}: {
value: string
/** What's being copied, for the aria-label. Defaults to "id". */
label?: string
className?: string
dataAction?: string
}) {
const [copied, setCopied] = useState(false)
const copy = async () => {
try {
await navigator.clipboard.writeText(value)
setCopied(true)
setTimeout(() => setCopied(false), 1200)
} catch {
// Clipboard blocked (insecure context / permissions) — no-op; the value
// is still selectable by hand.
}
}
return (
<button
type="button"
onClick={copy}
data-action={dataAction}
aria-label={`Copy ${label ?? "id"}`}
title="Copy"
className={`group inline-flex max-w-full items-center gap-1 rounded bg-muted px-1.5 py-0.5 font-mono text-xs transition-colors hover:bg-accent ${className}`}
>
<span className="truncate">{value}</span>
{copied ? (
<Check className="size-3 shrink-0 text-emerald-500" />
) : (
<Copy className="size-3 shrink-0 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100" />
)}
</button>
)
}