Reusable dossier primitives (classification strips, brackets, readouts, provenance chips, notice states) plus server-rendered /operations overview, ledger drill-down, and AAR with permission-gated sections and an authorized reconciliation panel. Realtime refresh is enhancement only. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
37 lines
1.1 KiB
TypeScript
37 lines
1.1 KiB
TypeScript
import type { ReactNode } from "react";
|
|
|
|
/**
|
|
* Empty/error/loading notice states for operations surfaces.
|
|
* `error` renders with role="alert" (assertive); empty/loading render with
|
|
* role="status" (polite). Text is the message; optional action passes through.
|
|
*/
|
|
export function NoticeState({
|
|
variant,
|
|
message,
|
|
hint,
|
|
action,
|
|
}: {
|
|
variant: "empty" | "error" | "loading";
|
|
message: string;
|
|
hint?: string;
|
|
action?: ReactNode;
|
|
}) {
|
|
const role = variant === "error" ? "alert" : "status";
|
|
const tone =
|
|
variant === "error"
|
|
? "border-rose-500/30 bg-rose-500/5 text-rose-300"
|
|
: "border-border/60 bg-card/50 text-muted-foreground";
|
|
return (
|
|
<div
|
|
role={role}
|
|
data-slot="notice-state"
|
|
data-variant={variant}
|
|
aria-busy={variant === "loading" || undefined}
|
|
className={`flex flex-col items-center justify-center gap-1.5 rounded-none border border-dashed px-6 py-10 text-center ${tone}`}
|
|
>
|
|
<p className="text-sm font-medium">{message}</p>
|
|
{hint ? <p className="max-w-prose text-xs text-muted-foreground">{hint}</p> : null}
|
|
{action ? <div className="mt-2">{action}</div> : null}
|
|
</div>
|
|
);
|
|
}
|