124 lines
3.1 KiB
TypeScript
124 lines
3.1 KiB
TypeScript
import type { ReactNode } from "react";
|
|
|
|
import { AppCard } from "@/components/ui/app-card";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export function WorkspaceHero({
|
|
eyebrow,
|
|
title,
|
|
description,
|
|
aside,
|
|
}: {
|
|
eyebrow: string;
|
|
title: string;
|
|
description: string;
|
|
aside?: ReactNode;
|
|
}) {
|
|
return (
|
|
<AppCard level={3}>
|
|
<CardContent className="flex flex-col gap-4 p-6 lg:flex-row lg:items-end lg:justify-between lg:p-8">
|
|
<div className="space-y-2">
|
|
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground">
|
|
{eyebrow}
|
|
</p>
|
|
<h2 className="text-2xl font-semibold text-foreground">{title}</h2>
|
|
<p className="max-w-3xl text-sm text-muted-foreground">{description}</p>
|
|
</div>
|
|
{aside ? <div className="flex flex-wrap gap-2">{aside}</div> : null}
|
|
</CardContent>
|
|
</AppCard>
|
|
);
|
|
}
|
|
|
|
export function WorkspaceSidebarPanel({
|
|
title,
|
|
children,
|
|
}: {
|
|
title: string;
|
|
children: ReactNode;
|
|
}) {
|
|
return (
|
|
<AppCard level={2}>
|
|
<CardHeader className="pb-4">
|
|
<CardTitle className="text-base">{title}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">{children}</CardContent>
|
|
</AppCard>
|
|
);
|
|
}
|
|
|
|
export function WorkspaceStepButton({
|
|
active,
|
|
completed,
|
|
index,
|
|
label,
|
|
eyebrow,
|
|
onClick,
|
|
completeIcon,
|
|
}: {
|
|
active: boolean;
|
|
completed: boolean;
|
|
index: number;
|
|
label: string;
|
|
eyebrow: string;
|
|
onClick: () => void;
|
|
completeIcon?: ReactNode;
|
|
}) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={onClick}
|
|
className={cn(
|
|
"flex w-full items-start gap-3 rounded-surface border px-4 py-3 text-left transition-colors",
|
|
active
|
|
? "border-input bg-accent/40"
|
|
: "border-input bg-background hover:bg-accent/20",
|
|
)}
|
|
>
|
|
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-pill border border-input bg-background text-sm font-semibold text-foreground">
|
|
{completed ? completeIcon ?? "OK" : index + 1}
|
|
</div>
|
|
<div className="min-w-0">
|
|
<p className="text-xs font-semibold uppercase tracking-[0.12em] text-muted-foreground">
|
|
{eyebrow}
|
|
</p>
|
|
<p className="mt-1 text-sm font-medium text-foreground">{label}</p>
|
|
</div>
|
|
</button>
|
|
);
|
|
}
|
|
|
|
export function WorkspaceLocaleCard({
|
|
title,
|
|
hint,
|
|
children,
|
|
}: {
|
|
title: string;
|
|
hint: string;
|
|
children: ReactNode;
|
|
}) {
|
|
return (
|
|
<AppCard level={2}>
|
|
<CardHeader className="pb-4">
|
|
<CardTitle className="text-lg">{title}</CardTitle>
|
|
<CardDescription>{hint}</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">{children}</CardContent>
|
|
</AppCard>
|
|
);
|
|
}
|
|
|
|
export function WorkspaceStatusBadge({
|
|
done,
|
|
doneLabel = "Ready",
|
|
openLabel = "Open",
|
|
}: {
|
|
done: boolean;
|
|
doneLabel?: string;
|
|
openLabel?: string;
|
|
}) {
|
|
return <Badge variant={done ? "success" : "warning"}>{done ? doneLabel : openLabel}</Badge>;
|
|
}
|