收口前端平台组件库能力

新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件
迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome
补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
This commit is contained in:
2026-06-10 10:24:18 +08:00
parent a4ee6ff698
commit 1ad25e30f8
226 changed files with 23364 additions and 7825 deletions

View File

@@ -1,10 +1,18 @@
import { X } from 'lucide-react';
import type { ReactNode } from 'react';
import type {
CustomWorldCreatorIntent,
CustomWorldGenerationMode,
} from '../types';
import { PlatformActionButton } from './common/PlatformActionButton';
import { PlatformModalCloseButton } from './common/PlatformModalCloseButton';
import { PlatformProgressBar } from './common/PlatformProgressBar';
import { PlatformStatusMessage } from './common/PlatformStatusMessage';
import { PlatformSubpanel } from './common/PlatformSubpanel';
import {
PlatformSelectField,
PlatformTextField,
} from './common/PlatformTextField';
type BaseModalProps = {
isOpen: boolean;
@@ -28,13 +36,11 @@ function SelectionModal({
<div className="platform-modal-shell platform-remap-surface flex max-h-[90vh] w-full max-w-2xl flex-col overflow-hidden rounded-3xl shadow-[0_30px_80px_rgba(0,0,0,0.55)]">
<div className="flex items-center justify-between border-b border-white/10 px-5 py-4">
<div className="text-base font-semibold text-white">{title}</div>
<button
type="button"
<PlatformModalCloseButton
label={`关闭${title}`}
variant="editorDark"
onClick={onClose}
className="rounded-full border border-white/10 bg-white/5 p-2 text-zinc-300 transition hover:bg-white/10 hover:text-white"
>
<X className="h-4 w-4" />
</button>
/>
</div>
<div className="min-h-0 flex-1 overflow-y-auto px-5 py-5">
{children}
@@ -79,50 +85,71 @@ export function CharacterDraftModal(props: {
onClose={onClose}
footer={(
<>
<button
type="button"
<PlatformActionButton
surface="editorDark"
tone="secondary"
size="sm"
onClick={onClose}
className="rounded-2xl border border-white/10 bg-white/5 px-4 py-2 text-sm text-zinc-300 transition hover:bg-white/10 hover:text-white"
>
</button>
<button
type="button"
</PlatformActionButton>
<PlatformActionButton
surface="editorDark"
tone="success"
size="sm"
onClick={onConfirm}
className="rounded-2xl bg-emerald-400 px-4 py-2 text-sm font-semibold text-slate-950 transition hover:bg-emerald-300"
>
</button>
</PlatformActionButton>
</>
)}
>
<div className="space-y-4">
<div className="rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-sm text-zinc-300">
<PlatformSubpanel
as="div"
surface="dark"
radius="md"
padding="row"
className="text-sm text-zinc-300"
>
{characterLabel}
</div>
</PlatformSubpanel>
<label className="block">
<div className="mb-2 text-sm font-medium text-zinc-200"></div>
<input
<PlatformTextField
value={draftName}
onChange={(event) => onNameChange(event.target.value)}
placeholder="输入一个更贴合这次旅程的称呼"
className="w-full rounded-2xl border border-white/10 bg-black/30 px-4 py-3 text-sm text-white outline-none transition focus:border-emerald-400/40"
surface="editorDark"
tone="emerald"
density="roomy"
className="rounded-2xl"
/>
</label>
<label className="block">
<div className="mb-2 text-sm font-medium text-zinc-200"></div>
<textarea
<PlatformTextField
variant="textarea"
value={draftBackstory}
onChange={(event) => onBackstoryChange(event.target.value)}
rows={6}
placeholder="可以补充这次开局想强调的身份、经历、执念或禁忌。"
className="w-full rounded-2xl border border-white/10 bg-black/30 px-4 py-3 text-sm leading-7 text-white outline-none transition focus:border-emerald-400/40"
surface="editorDark"
tone="emerald"
size="md"
density="roomy"
className="rounded-2xl leading-7"
/>
</label>
{error ? (
<div className="rounded-2xl border border-rose-400/25 bg-rose-500/10 px-4 py-3 text-sm text-rose-100">
<PlatformStatusMessage
tone="error"
surface="editorDark"
size="md"
className="rounded-2xl"
>
{error}
</div>
</PlatformStatusMessage>
) : null}
</div>
</SelectionModal>
@@ -199,22 +226,24 @@ export function CustomWorldCreatorModal(props: CustomWorldCreatorModalProps) {
onClose={onClose}
footer={(
<>
<button
type="button"
<PlatformActionButton
surface="editorDark"
tone="secondary"
size="sm"
onClick={onClose}
disabled={isGenerating}
className="rounded-2xl border border-white/10 bg-white/5 px-4 py-2 text-sm text-zinc-300 transition hover:bg-white/10 hover:text-white disabled:cursor-not-allowed disabled:opacity-50"
>
</button>
<button
type="button"
</PlatformActionButton>
<PlatformActionButton
surface="editorDark"
tone="primary"
size="sm"
onClick={onSubmit}
disabled={isGenerating}
className="rounded-2xl bg-sky-400 px-4 py-2 text-sm font-semibold text-slate-950 transition hover:bg-sky-300 disabled:cursor-not-allowed disabled:opacity-50"
>
{isGenerating ? '生成中...' : '开始生成'}
</button>
</PlatformActionButton>
</>
)}
>
@@ -222,18 +251,21 @@ export function CustomWorldCreatorModal(props: CustomWorldCreatorModalProps) {
{hasCreatorIntentProps(props) ? (
<label className="block">
<div className="mb-2 text-sm font-medium text-zinc-200"></div>
<select
<PlatformSelectField
value={props.generationMode}
onChange={(event) =>
props.onGenerationModeChange(
event.target.value as CustomWorldGenerationMode,
)
}
className="w-full rounded-2xl border border-white/10 bg-black/30 px-4 py-3 text-sm text-white outline-none transition focus:border-sky-400/40"
surface="editorDark"
tone="sky"
density="roomy"
className="rounded-2xl"
>
<option value="fast"></option>
<option value="full"></option>
</select>
</PlatformSelectField>
</label>
) : null}
@@ -241,33 +273,49 @@ export function CustomWorldCreatorModal(props: CustomWorldCreatorModalProps) {
</div>
<textarea
<PlatformTextField
variant="textarea"
value={draftText}
onChange={(event) => updateDraftText(event.target.value)}
rows={8}
placeholder="例:一个被潮雾与失落列岛切碎的边境世界,旧盟约、沉船秘术与灯塔守望者纠缠在一起……"
className="w-full rounded-2xl border border-white/10 bg-black/30 px-4 py-3 text-sm leading-7 text-white outline-none transition focus:border-sky-400/40"
surface="editorDark"
tone="sky"
size="md"
density="roomy"
className="rounded-2xl leading-7"
/>
{isGenerating ? (
<div className="rounded-2xl border border-sky-300/15 bg-sky-500/10 px-4 py-3">
<PlatformStatusMessage
tone="info"
surface="editorDark"
size="md"
className="rounded-2xl"
>
<div className="mb-2 flex items-center justify-between text-xs tracking-[0.16em] text-sky-100/80">
<span>{progressLabel}</span>
<span>{Math.max(0, Math.min(100, Math.round(progress)))}%</span>
</div>
<div className="h-2 overflow-hidden rounded-full bg-white/10">
<div
className="h-full rounded-full bg-gradient-to-r from-sky-300 to-cyan-200 transition-[width] duration-300"
style={{ width: `${Math.max(6, Math.min(100, progress))}%` }}
/>
</div>
</div>
<PlatformProgressBar
value={progress}
minVisibleValue={6}
ariaLabel="自定义世界生成进度"
className="bg-white/10"
fillClassName="bg-gradient-to-r from-sky-300 to-cyan-200"
/>
</PlatformStatusMessage>
) : null}
{error ? (
<div className="rounded-2xl border border-rose-400/25 bg-rose-500/10 px-4 py-3 text-sm text-rose-100">
<PlatformStatusMessage
tone="error"
surface="editorDark"
size="md"
className="rounded-2xl"
>
{error}
</div>
</PlatformStatusMessage>
) : null}
</div>
</SelectionModal>