This commit is contained in:
2026-04-26 20:50:58 +08:00
parent a3a9bfa194
commit 67161bd6d1
142 changed files with 3349 additions and 10674 deletions

View File

@@ -68,15 +68,19 @@ function Section({
badge,
actions,
children,
className = '',
}: {
title: string;
subtitle?: string;
badge?: ReactNode;
actions?: ReactNode;
children: ReactNode;
className?: string;
}) {
return (
<div className="platform-surface platform-surface--soft px-3.5 py-3">
<div
className={`platform-surface platform-surface--soft px-3.5 py-3 ${className}`}
>
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<div className="text-xs font-bold tracking-[0.16em] text-white">
@@ -220,9 +224,7 @@ function PendingEntityCard({
<div className="text-sm font-semibold text-[var(--platform-text-strong)]">
{title}
</div>
<div className="mt-1 text-xs leading-6">
{phaseLabel}
</div>
<div className="mt-1 text-xs leading-6">{phaseLabel}</div>
</div>
<div className="platform-pill platform-pill--cool px-2.5 py-1 text-[10px]">
{Math.round(progress)}%
@@ -286,9 +288,11 @@ function buildSceneChapterSearchText(
}
function buildSceneTaskDescriptionText(sceneChapters: SceneChapterBlueprint[]) {
return compactTextList(
sceneChapters.map((chapter) => chapter.sceneTaskDescription),
)[0] ?? '';
return (
compactTextList(
sceneChapters.map((chapter) => chapter.sceneTaskDescription),
)[0] ?? ''
);
}
function SceneActPreviewStrip({
@@ -364,9 +368,7 @@ function CatalogCard({
onClick={disabled ? undefined : onClick}
aria-disabled={disabled}
className={`w-full rounded-[1.3rem] border p-2.5 text-left transition-colors xl:p-3 ${
isSelected
? 'border-rose-300/35 bg-rose-500/10'
: 'platform-subpanel'
isSelected ? 'border-rose-300/35 bg-rose-500/10' : 'platform-subpanel'
}`}
>
<div className="flex items-start gap-3 xl:gap-3.5">
@@ -388,7 +390,9 @@ function CatalogCard({
<div className="mt-1.5 text-sm leading-5 text-zinc-300 xl:line-clamp-2">
{description || '暂无描述'}
</div>
{actions ? <div className="mt-2 flex flex-wrap gap-2">{actions}</div> : null}
{actions ? (
<div className="mt-2 flex flex-wrap gap-2">{actions}</div>
) : null}
</div>
</div>
</div>
@@ -402,9 +406,7 @@ function CatalogCard({
onClick={disabled ? undefined : onClick}
aria-disabled={disabled}
className={`w-full rounded-[1.4rem] border p-3 text-left transition-colors ${
isSelected
? 'border-rose-300/35 bg-rose-500/10'
: 'platform-subpanel'
isSelected ? 'border-rose-300/35 bg-rose-500/10' : 'platform-subpanel'
}`}
>
<div className="space-y-3">
@@ -816,17 +818,19 @@ export function CustomWorldEntityCatalog({
return (
<div
ref={scrollContainerRef}
className="h-full min-h-0 space-y-3 overflow-y-auto overscroll-contain pr-1 scrollbar-hide xl:space-y-4 xl:pr-2"
className="h-full min-h-0 space-y-3 overflow-y-auto overscroll-contain pr-1 scrollbar-hide xl:space-y-4 xl:pr-2 2xl:space-y-5 2xl:pr-3"
>
<div className="px-1 pb-1 text-center xl:rounded-[2rem] xl:border xl:border-[var(--platform-subpanel-border)] xl:bg-white/55 xl:px-6 xl:py-4 xl:text-left xl:shadow-[0_18px_70px_rgba(255,79,139,0.08)] xl:backdrop-blur-sm">
<div className="px-1 pb-1 text-center xl:flex xl:items-end xl:justify-between xl:gap-6 xl:rounded-[2rem] xl:border xl:border-[var(--platform-subpanel-border)] xl:bg-white/55 xl:px-6 xl:py-3 xl:text-left xl:shadow-[0_18px_70px_rgba(255,79,139,0.08)] xl:backdrop-blur-sm 2xl:px-7">
<div className="text-[11px] font-bold tracking-[0.28em] text-zinc-500">
</div>
<div className="mt-2 text-3xl font-black text-[var(--platform-text-strong)] sm:text-[2.2rem] xl:mt-1 xl:text-[2rem]">
{profile.name}
</div>
<div className="mt-2 text-sm tracking-[0.18em] text-zinc-400 xl:mt-1 xl:text-xs">
{profile.subtitle}
<div className="min-w-0 xl:flex xl:flex-1 xl:items-end xl:justify-between xl:gap-5">
<div className="mt-2 truncate text-3xl font-black text-[var(--platform-text-strong)] sm:text-[2.2rem] xl:mt-0 xl:text-[2rem] 2xl:text-[2.25rem]">
{profile.name}
</div>
<div className="mt-2 min-w-0 text-sm tracking-[0.18em] text-zinc-400 xl:mt-0 xl:max-w-[34rem] xl:truncate xl:text-right xl:text-xs">
{profile.subtitle}
</div>
</div>
</div>
@@ -898,7 +902,7 @@ export function CustomWorldEntityCatalog({
</div>
{activeTab === 'world' ? (
<div className="space-y-3 xl:grid xl:grid-cols-[0.8fr_1.2fr] xl:items-start xl:gap-3 xl:space-y-0">
<div className="space-y-3 xl:grid xl:grid-cols-[minmax(18rem,0.82fr)_minmax(0,1fr)_minmax(24rem,1.08fr)] xl:items-start xl:gap-3 xl:space-y-0 2xl:gap-4">
<Section title="档案规模">
<div className="grid grid-cols-3 gap-2 text-center text-[11px] text-zinc-300">
<div className="platform-subpanel rounded-xl px-2 py-3">
@@ -926,7 +930,7 @@ export function CustomWorldEntityCatalog({
title="角色维度"
subtitle={profile.attributeSchema?.schemaName}
>
<div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
<div className="grid grid-cols-2 gap-2 sm:grid-cols-3 xl:grid-cols-2 2xl:grid-cols-3">
{attributeSlots.map((slot) => (
<div
key={slot.slotId}
@@ -963,19 +967,20 @@ export function CustomWorldEntityCatalog({
)
}
>
<div className="space-y-3 text-sm leading-7 text-zinc-300">
<p>{profile.summary}</p>
<div className="platform-banner platform-banner--warning rounded-2xl px-3 py-3">
线{profile.playerGoal}
</div>
<div className="platform-subpanel rounded-2xl px-3 py-3">
{profile.tone}
</div>
<div className="space-y-3 text-sm leading-7 text-zinc-300">
<p>{profile.summary}</p>
<div className="platform-banner platform-banner--warning rounded-2xl px-3 py-3">
线{profile.playerGoal}
</div>
<div className="platform-subpanel rounded-2xl px-3 py-3">
{profile.tone}
</div>
</div>
</Section>
<Section
title="基本设定"
className="xl:col-span-3"
actions={
readOnly ? (
<SmallButton
@@ -1006,14 +1011,16 @@ export function CustomWorldEntityCatalog({
</div>
{entry.value ? (
<div className="mt-3 flex flex-wrap gap-2">
{parseFoundationTagText(entry.value).map((tag, index) => (
<span
key={`${entry.id}-${index}-${tag}`}
className="rounded-full border border-white/10 bg-white/[0.06] px-3 py-1 text-xs leading-5 text-zinc-100"
>
{tag}
</span>
))}
{parseFoundationTagText(entry.value).map(
(tag, index) => (
<span
key={`${entry.id}-${index}-${tag}`}
className="rounded-full border border-white/10 bg-white/[0.06] px-3 py-1 text-xs leading-5 text-zinc-100"
>
{tag}
</span>
),
)}
</div>
) : (
<div className="mt-2 text-sm leading-7 text-zinc-100">
@@ -1029,7 +1036,7 @@ export function CustomWorldEntityCatalog({
) : null}
{activeTab === 'playable' ? (
<div className="space-y-3 xl:grid xl:grid-cols-2 xl:gap-3 xl:space-y-0 2xl:grid-cols-3">
<div className="space-y-3 xl:grid xl:grid-cols-3 xl:gap-3 xl:space-y-0 2xl:grid-cols-4 2xl:gap-4">
{pendingGeneratedEntity?.kind === 'playable' ? (
<PendingEntityCard
title={pendingGeneratedEntity.title}
@@ -1060,7 +1067,9 @@ export function CustomWorldEntityCatalog({
<CatalogCard
title={role.name}
description={description || '暂无描述'}
badge={recentPlayableIdSet.has(role.id) ? <NewBadge /> : null}
badge={
recentPlayableIdSet.has(role.id) ? <NewBadge /> : null
}
isSelectionMode={false}
isSelected={false}
layout="compact"
@@ -1093,9 +1102,9 @@ export function CustomWorldEntityCatalog({
className="h-full w-full object-cover object-top"
/>
) : (
<div className="flex h-full w-full items-center justify-center bg-[rgba(255,255,255,0.64)] px-3 text-center text-xs font-semibold tracking-[0.16em] text-[var(--platform-text-soft)]">
{role.name.slice(0, 4) || '角色'}
</div>
<div className="flex h-full w-full items-center justify-center bg-[rgba(255,255,255,0.64)] px-3 text-center text-xs font-semibold tracking-[0.16em] text-[var(--platform-text-soft)]">
{role.name.slice(0, 4) || '角色'}
</div>
)
}
/>
@@ -1140,7 +1149,7 @@ export function CustomWorldEntityCatalog({
) : null}
{activeTab === 'story' ? (
<div className="space-y-3 xl:grid xl:grid-cols-2 xl:gap-3 xl:space-y-0 2xl:grid-cols-3">
<div className="space-y-3 xl:grid xl:grid-cols-3 xl:gap-3 xl:space-y-0 2xl:grid-cols-4 2xl:gap-4">
{pendingGeneratedEntity?.kind === 'story' ? (
<PendingEntityCard
title={pendingGeneratedEntity.title}
@@ -1200,7 +1209,7 @@ export function CustomWorldEntityCatalog({
) : null}
{activeTab === 'landmarks' ? (
<div className="space-y-3 xl:grid xl:grid-cols-2 xl:gap-3 xl:space-y-0 2xl:grid-cols-3">
<div className="space-y-3 xl:grid xl:grid-cols-3 xl:gap-3 xl:space-y-0 2xl:grid-cols-4 2xl:gap-4">
{pendingGeneratedEntity?.kind === 'landmark' ? (
<PendingEntityCard
title={pendingGeneratedEntity.title}
@@ -1218,16 +1227,15 @@ export function CustomWorldEntityCatalog({
`scene-entry-${index}-${scene.name.trim() || scene.kind}`,
)}
title={scene.name}
description={
compactTextList([
scene.kind === 'camp'
? `开局场景 · ${scene.description}`
: scene.description,
scene.sceneTaskDescription,
]).join(' / ')
}
description={compactTextList([
scene.kind === 'camp'
? `开局场景 · ${scene.description}`
: scene.description,
scene.sceneTaskDescription,
]).join(' / ')}
badge={
scene.kind === 'landmark' && recentLandmarkIdSet.has(scene.id) ? (
scene.kind === 'landmark' &&
recentLandmarkIdSet.has(scene.id) ? (
<NewBadge />
) : null
}
@@ -1270,4 +1278,3 @@ export function CustomWorldEntityCatalog({
</div>
);
}