feat: improve app ui and project metadata

This commit is contained in:
Yaojia Wang
2026-06-28 07:31:20 +02:00
parent 3bd464d400
commit 90a66437d7
86 changed files with 4892 additions and 1108 deletions

View File

@@ -1,7 +1,13 @@
"use client";
import { useCallback, useEffect, useMemo, useState } from "react";
import { Database, Sparkles } from "lucide-react";
import { Button } from "@/components/ui/Button";
import { Field } from "@/components/ui/Field";
import { SectionHeader } from "@/components/ui/SectionHeader";
import { StatusNote } from "@/components/ui/StatusNote";
import { TextInput } from "@/components/ui/TextInput";
import type { CharacterCardView } from "@/lib/api/types";
import {
MAX_CHARACTER_COUNT,
@@ -80,45 +86,39 @@ export function CharacterGenerator({
return (
<section className="flex flex-col gap-4" aria-label="角色生成器">
<div className="rounded border border-line bg-panel p-4">
<h2 className="mb-3 font-serif text-base text-ink"></h2>
<label className="mb-2 block text-sm text-ink-soft">
<input
<SectionHeader title="角色生成器" className="mb-3" />
<Field label="一句话需求" className="mb-3">
<TextInput
value={brief}
onChange={(e) => setBrief(e.target.value)}
placeholder="如:一个亦正亦邪的剑修,背负灭门血仇"
className="mt-1 w-full rounded border border-line bg-bg px-3 py-2 text-sm text-ink"
/>
</label>
</Field>
<div className="flex flex-wrap items-end gap-3">
<label className="text-sm text-ink-soft">
<input
<Field label="数量" className="w-24">
<TextInput
type="number"
min={MIN_CHARACTER_COUNT}
max={MAX_CHARACTER_COUNT}
value={count}
onChange={(e) => setCount(Number(e.target.value))}
className="mt-1 block w-20 rounded border border-line bg-bg px-2 py-1.5 text-sm text-ink"
/>
</label>
<label className="flex-1 text-sm text-ink-soft">
<input
</Field>
<Field label="定位(可选)" className="min-w-[12rem] flex-1">
<TextInput
value={role}
onChange={(e) => setRole(e.target.value)}
placeholder="主角 / CP / 对手 / 导师 / 工具人"
className="mt-1 block w-full rounded border border-line bg-bg px-2 py-1.5 text-sm text-ink"
/>
</label>
<button
type="button"
</Field>
<Button
onClick={() => void onGenerate()}
disabled={generating || brief.trim().length === 0}
className="rounded bg-cinnabar px-4 py-2 text-sm text-white disabled:opacity-50"
variant="primary"
>
<Sparkles className="h-4 w-4" aria-hidden="true" />
{generating ? "生成中…" : "生成"}
</button>
</Button>
</div>
</div>
@@ -151,20 +151,20 @@ export function CharacterGenerator({
onCancel={() => gen.reset()}
/>
) : (
<button
type="button"
<Button
onClick={() => void doIngest(false)}
disabled={ingesting || selectedCards.length === 0}
className="self-start rounded bg-cinnabar px-4 py-2 text-sm text-white disabled:opacity-50"
variant="primary"
>
<Database className="h-4 w-4" aria-hidden="true" />
{ingesting ? "入库中…" : `入库选中 ${selectedCards.length}`}
</button>
</Button>
)}
</div>
) : null}
{gen.ingestStatus === "done" && gen.created.length > 0 ? (
<p className="text-sm text-pass">{gen.created.join("、")}</p>
<StatusNote variant="success">{gen.created.join("、")}</StatusNote>
) : null}
</section>
);