Files
writer-work-flow/apps/web/components/generation/CharacterCardItem.tsx
2026-06-28 07:31:20 +02:00

101 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { TextInput } from "@/components/ui/TextInput";
import type { CharacterCardView } from "@/lib/api/types";
interface CharacterCardItemProps {
card: CharacterCardView;
selected: boolean;
onToggle: () => void;
// 入库前作者就地编辑名/弧光(最小可编辑面,避免重型表单)。
onEdit?: (patch: Partial<CharacterCardView>) => void;
}
// 单张角色预览卡UX §6.6):勾选入库 + 关键字段就地编辑。
export function CharacterCardItem({
card,
selected,
onToggle,
onEdit,
}: CharacterCardItemProps) {
return (
<article
className={`rounded border p-3 text-sm ${
selected ? "border-cinnabar bg-[var(--color-cinnabar-wash)]" : "border-line bg-panel"
}`}
>
<header className="mb-2 flex items-center gap-2">
<input
type="checkbox"
checked={selected}
onChange={onToggle}
aria-label={`选择角色 ${card.name}`}
className="size-4 accent-cinnabar"
/>
{onEdit ? (
<TextInput
value={card.name}
onChange={(e) => onEdit({ name: e.target.value })}
aria-label="角色名"
controlSize="sm"
className="min-w-0 flex-1 font-serif text-base"
/>
) : (
<span className="flex-1 font-serif text-base text-ink">{card.name}</span>
)}
<span className="rounded bg-bg px-2 py-0.5 text-xs text-ink-soft">
{card.role}
</span>
</header>
{card.traits && card.traits.length > 0 ? (
<p className="mb-1 text-ink-soft">
<span className="text-ink"></span>
{card.traits.join("、")}
</p>
) : null}
<p className="mb-1 text-ink-soft">
<span className="text-ink"></span>
{card.backstory}
</p>
<div className="mb-1 flex items-start gap-1 text-ink-soft">
<span className="shrink-0 text-ink"></span>
{onEdit ? (
<TextInput
value={card.arc}
onChange={(e) => onEdit({ arc: e.target.value })}
aria-label="人物弧光"
controlSize="sm"
className="min-w-0 flex-1"
/>
) : (
<span>{card.arc}</span>
)}
</div>
{card.speech_tics && card.speech_tics.length > 0 ? (
<p className="mb-1 text-ink-soft">
<span className="text-ink"></span>
{card.speech_tics.join("、")}
</p>
) : null}
{card.relations && card.relations.length > 0 ? (
<ul className="mt-1 flex flex-wrap gap-1">
{card.relations.map((r, i) => (
<li
key={`${r.name}-${i}`}
className="rounded bg-bg px-2 py-0.5 text-xs text-ink-soft"
>
{r.kind}{r.name}
{r.note ? `${r.note}` : ""}
</li>
))}
</ul>
) : null}
</article>
);
}