收口前端平台组件库能力
新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件 迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome 补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
This commit is contained in:
@@ -14,6 +14,9 @@ import {
|
||||
NarrativeQaReport,
|
||||
WorldType,
|
||||
} from '../types';
|
||||
import { PlatformPillBadge } from './common/PlatformPillBadge';
|
||||
import { PlatformStatusMessage } from './common/PlatformStatusMessage';
|
||||
import { PlatformSubpanel } from './common/PlatformSubpanel';
|
||||
import {
|
||||
InventoryItemDetailModal,
|
||||
InventoryItemGrid,
|
||||
@@ -83,7 +86,10 @@ export function InventoryPanel({
|
||||
[playerCharacter, playerInventory, serverInventoryItems, worldType],
|
||||
);
|
||||
const documentItems = useMemo(
|
||||
() => inventoryItems.filter((item) => item.category === '文书' || item.tags.includes('document')),
|
||||
() =>
|
||||
inventoryItems.filter(
|
||||
(item) => item.category === '文书' || item.tags.includes('document'),
|
||||
),
|
||||
[inventoryItems],
|
||||
);
|
||||
|
||||
@@ -97,43 +103,65 @@ export function InventoryPanel({
|
||||
/>
|
||||
|
||||
{documentItems.length > 0 && (
|
||||
<div className="mt-4 rounded-2xl border border-white/10 bg-black/20 p-4">
|
||||
<PlatformSubpanel
|
||||
surface="dark"
|
||||
radius="sm"
|
||||
padding="md"
|
||||
className="mt-4"
|
||||
>
|
||||
<div className="mb-2 text-xs uppercase tracking-[0.2em] text-zinc-500">
|
||||
文书与证据
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{documentItems.map((item) => (
|
||||
<button
|
||||
<PlatformSubpanel
|
||||
as="button"
|
||||
key={item.id}
|
||||
type="button"
|
||||
onClick={() => setSelectedItem(item)}
|
||||
className="w-full rounded-xl border border-white/8 bg-black/20 px-3 py-2 text-left transition hover:border-white/15"
|
||||
surface="dark"
|
||||
radius="xs"
|
||||
padding="row"
|
||||
className="w-full text-left transition hover:border-white/15"
|
||||
>
|
||||
<div className="text-sm font-semibold text-white">{item.name}</div>
|
||||
<div className="text-sm font-semibold text-white">
|
||||
{item.name}
|
||||
</div>
|
||||
<div className="mt-1 text-xs text-zinc-400">
|
||||
{item.description || '记录着当前线程的阶段性线索。'}
|
||||
</div>
|
||||
</button>
|
||||
</PlatformSubpanel>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
)}
|
||||
|
||||
{(narrativeCodex.length > 0 || narrativeQaReport) && (
|
||||
<div className="mt-4 rounded-2xl border border-white/10 bg-black/20 p-4">
|
||||
<PlatformSubpanel
|
||||
surface="dark"
|
||||
radius="sm"
|
||||
padding="md"
|
||||
className="mt-4"
|
||||
>
|
||||
<div className="mb-2 text-xs uppercase tracking-[0.2em] text-zinc-500">
|
||||
故事档案
|
||||
</div>
|
||||
{narrativeQaReport && (
|
||||
<div className="mb-3 rounded-xl border border-amber-400/18 bg-amber-500/8 px-3 py-2 text-xs text-amber-100/85">
|
||||
<PlatformStatusMessage
|
||||
tone="warning"
|
||||
surface="editorDark"
|
||||
size="xs"
|
||||
className="mb-3"
|
||||
>
|
||||
QA:{narrativeQaReport.summary}
|
||||
</div>
|
||||
</PlatformStatusMessage>
|
||||
)}
|
||||
<div className="space-y-3">
|
||||
{narrativeCodex.slice(0, 3).map((section) => (
|
||||
<div
|
||||
<PlatformSubpanel
|
||||
key={section.id}
|
||||
className="rounded-xl border border-white/8 bg-black/20 p-3"
|
||||
surface="dark"
|
||||
radius="xs"
|
||||
padding="sm"
|
||||
>
|
||||
<div className="text-sm font-semibold text-white">
|
||||
{section.title}
|
||||
@@ -147,13 +175,18 @@ export function InventoryPanel({
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
)}
|
||||
|
||||
<div className="mt-4 rounded-2xl border border-white/10 bg-black/20 p-4">
|
||||
<PlatformSubpanel
|
||||
surface="dark"
|
||||
radius="sm"
|
||||
padding="md"
|
||||
className="mt-4"
|
||||
>
|
||||
<div className="mb-2 flex items-center justify-between gap-3 text-xs uppercase tracking-[0.2em] text-zinc-500">
|
||||
<span>工坊</span>
|
||||
<span className="text-emerald-200/80">
|
||||
@@ -162,9 +195,11 @@ export function InventoryPanel({
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{forgeRecipes.map((recipe) => (
|
||||
<div
|
||||
<PlatformSubpanel
|
||||
key={recipe.id}
|
||||
className="rounded-xl border border-white/8 bg-black/20 p-3"
|
||||
surface="dark"
|
||||
radius="xs"
|
||||
padding="sm"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
@@ -211,19 +246,22 @@ export function InventoryPanel({
|
||||
</button>
|
||||
</div>
|
||||
<div className="mt-2 flex flex-wrap gap-2">
|
||||
{recipe.requirements.map((requirement) => (
|
||||
<span
|
||||
key={`${recipe.id}-${requirement.id}`}
|
||||
className={`rounded-full border px-2 py-1 text-[10px] ${
|
||||
requirement.owned >= requirement.quantity
|
||||
? 'border-emerald-400/20 bg-emerald-500/10 text-emerald-100'
|
||||
: 'border-white/10 bg-black/20 text-zinc-400'
|
||||
}`}
|
||||
>
|
||||
{requirement.label} {requirement.owned}/
|
||||
{requirement.quantity}
|
||||
</span>
|
||||
))}
|
||||
{recipe.requirements.map((requirement) => {
|
||||
const isRequirementMet =
|
||||
requirement.owned >= requirement.quantity;
|
||||
|
||||
return (
|
||||
<PlatformPillBadge
|
||||
key={`${recipe.id}-${requirement.id}`}
|
||||
tone={isRequirementMet ? 'darkEmerald' : 'darkNeutral'}
|
||||
size="xxs"
|
||||
className={`px-2 ${isRequirementMet ? '' : 'text-zinc-400'}`}
|
||||
>
|
||||
{requirement.label} {requirement.owned}/
|
||||
{requirement.quantity}
|
||||
</PlatformPillBadge>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{(!recipe.canCraft || !recipe.action.enabled) &&
|
||||
(recipe.disabledReason || recipe.action.reason) && (
|
||||
@@ -231,10 +269,10 @@ export function InventoryPanel({
|
||||
{recipe.disabledReason ?? recipe.action.reason}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</PlatformSubpanel>
|
||||
</div>
|
||||
|
||||
<InventoryItemDetailModal
|
||||
|
||||
Reference in New Issue
Block a user