feat: bootstrap auto virtual tryon admin frontend
This commit is contained in:
96
src/features/orders/components/resource-picker-card.tsx
Normal file
96
src/features/orders/components/resource-picker-card.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardEyebrow,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import type { ResourcePickerOption } from "@/features/orders/resource-picker-options";
|
||||
|
||||
type ResourcePickerCardProps = {
|
||||
description: string;
|
||||
disabled?: boolean;
|
||||
isLoading?: boolean;
|
||||
items: ResourcePickerOption[];
|
||||
label: string;
|
||||
title: string;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
function joinClasses(...values: Array<string | false | null | undefined>) {
|
||||
return values.filter(Boolean).join(" ");
|
||||
}
|
||||
|
||||
export function ResourcePickerCard({
|
||||
description,
|
||||
disabled = false,
|
||||
isLoading = false,
|
||||
items,
|
||||
label,
|
||||
title,
|
||||
value,
|
||||
onChange,
|
||||
}: ResourcePickerCardProps) {
|
||||
const selectedItem = items.find((item) => item.id === value) ?? null;
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardEyebrow>Mock backed selector</CardEyebrow>
|
||||
<CardTitle>{title}</CardTitle>
|
||||
<CardDescription>{description}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<label className="flex flex-col gap-2 text-sm text-[var(--ink-strong)]">
|
||||
<span className="font-medium">{label}</span>
|
||||
<select
|
||||
aria-label={label}
|
||||
className={joinClasses(
|
||||
"min-h-12 rounded-[18px] border border-[var(--border-strong)] bg-[var(--surface-muted)] px-4 text-sm text-[var(--ink-strong)]",
|
||||
"focus:outline-none focus:ring-2 focus:ring-[var(--accent-ring)]",
|
||||
)}
|
||||
disabled={disabled || isLoading}
|
||||
value={value}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
>
|
||||
<option value="">
|
||||
{isLoading ? "正在加载占位资源..." : "请选择一个资源"}
|
||||
</option>
|
||||
{items.map((item) => (
|
||||
<option key={item.id} value={item.id}>
|
||||
{item.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
{selectedItem ? (
|
||||
<div className="rounded-[20px] border border-[var(--border-soft)] bg-[var(--surface-muted)] p-4">
|
||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm font-semibold text-[var(--ink-strong)]">
|
||||
{selectedItem.name}
|
||||
</p>
|
||||
<p className="text-sm leading-6 text-[var(--ink-muted)]">
|
||||
{selectedItem.description}
|
||||
</p>
|
||||
</div>
|
||||
<span className="rounded-full bg-[var(--accent-soft)] px-3 py-1 font-[var(--font-mono)] text-[11px] uppercase tracking-[0.18em] text-[var(--accent-ink)]">
|
||||
{selectedItem.isMock ? "mock" : "live"}
|
||||
</span>
|
||||
</div>
|
||||
<p className="mt-3 font-[var(--font-mono)] text-xs text-[var(--ink-faint)]">
|
||||
{selectedItem.previewUri}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm leading-6 text-[var(--ink-muted)]">
|
||||
选择后会在摘要卡中同步显示资源名称与提交 ID。
|
||||
</p>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user