From de0f0c139967d00ca9b4492caf39b98083c0ec8d Mon Sep 17 00:00:00 2001 From: kdletters Date: Thu, 11 Jun 2026 03:13:00 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=A7=E7=BB=AD=E6=94=B6=E5=8F=A3=E9=A6=96?= =?UTF-8?q?=E9=A1=B5=E5=8F=AF=E5=AF=BC=E8=88=AA=E6=89=81=E5=B9=B3=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 PlatformNavigableListItem 统一 desktop flat row 的交互骨架 接入首页搜索结果与桌面最近作品最近浏览入口 补充组件测试首页回归测试并更新收口计划和共享决策记录 --- .hermes/shared-memory/decision-log.md | 1 + ...】PlatformUiKit弹窗组件收口计划-2026-06-08.md | 1 + .../common/PlatformNavigableListItem.test.tsx | 48 ++++++++++ .../common/PlatformNavigableListItem.tsx | 88 +++++++++++++++++++ .../RpgEntryHomeView.recharge.test.tsx | 48 +++++++++- src/components/rpg-entry/RpgEntryHomeView.tsx | 76 ++++++++-------- 6 files changed, 224 insertions(+), 38 deletions(-) create mode 100644 src/components/common/PlatformNavigableListItem.test.tsx create mode 100644 src/components/common/PlatformNavigableListItem.tsx diff --git a/.hermes/shared-memory/decision-log.md b/.hermes/shared-memory/decision-log.md index af8001fd..2cb13b4d 100644 --- a/.hermes/shared-memory/decision-log.md +++ b/.hermes/shared-memory/decision-log.md @@ -55,6 +55,7 @@ - 2026-06-10 追加:`CustomWorldEntityCatalog` 的 `minimum-playable` 规则阻断提示也统一迁到 `PlatformStatusDialog`,不再和删除角色 / 批量删除共用 `UnifiedConfirmDialog` 配置;同日平台入口公开编号搜索把 error 分支从用户摘要 modal 中拆出,未命中结果单独走 `PlatformStatusDialog`,命中用户继续保留 `UnifiedModal + PlatformSubpanel` 信息布局。 - 2026-06-11 追加:`PlatformAsyncStatePanel` 继续从 profile modal 与作品架扩展到 RPG 首页公开分区;`RpgEntryHomeView.tsx` 的移动端排行、发现页寓教于乐 / 默认公开 feed、桌面首页“今日游戏 / 推荐”、桌面发现页寓教于乐 / 默认公开 feed,以及“我的创作”分区已统一改成 `loadingState / emptyState / children` 三态 slot。页面级 `platformError` 继续留在状态壳外层,保证错误提示可以和内容并存;`recommend runtime`、分类筛选等含运行态或二级筛选语义的分支暂不硬并入这一轮。 - 2026-06-11 追加:暗色 / 像素 modal 的标准 footer 布局统一抽到 `src/components/common/PlatformDarkModalFooter.tsx`;该组件只负责 dark footer 的分隔线、padding 和常见动作区排布,不持有“取消 / 确认”业务语义。`NpcModals.tsx` 的交易 / 赠礼 / 招募 footer、`SelectionCustomizationModals.tsx` 的 `SelectionModal` footer、`RpgAdventurePanelOverlays.tsx` 的 goal panel footer,以及 `InventoryItemViews.tsx` 的详情 footer wrapper 已接入;sticky 工作台 footer、正文内单 CTA 收尾和 runtime HUD 工具条暂不并入这一抽象。 +- 2026-06-11 追加:桌面首页里的轻量可点击扁平行开始统一收口到 `src/components/common/PlatformNavigableListItem.tsx`;这一轮只覆盖 `RpgEntryHomeView.tsx` 的搜索结果行、桌面“最近作品”和“最近浏览”行。组件只承接 `button + left content + right affordance` 结构、默认 `type="button"` 与 `leading / trailing` 插槽,暂不扩成覆盖趋势卡、教培 promo card、分类卡片或 runtime 列表项的万能 row primitive。 - 2026-06-09 追加:通用输入 Composer 的上传参考图、发送和移除参考图已迁移到 `PlatformIconButton`;图标上传仍使用 `asChild="label"` 保留 label + file input 语义,公共组件会自动写入隐藏文本,确保内嵌 file input 继承可访问名称。 - 2026-06-10 追加:creation-agent composer 的上传文档 / 上传参考图入口使用 `PlatformIconButton` 默认 `platformIcon`;工作台只保留动态 label、title、busy 状态和 picker 回调,发送按钮继续保留主题色动作布局。验证命令:`npm run test -- src/components/creation-agent/CreationAgentWorkspace.test.tsx src/components/common/PlatformIconButton.test.tsx`。 - 2026-06-10 追加:作品详情顶部返回 / 分享和封面轮播上一张 / 下一张入口使用 `PlatformIconButton variant="platformIcon"`;详情页保留原 `platform-work-detail__*` 局部 class 控制位置和尺寸,点赞、复制三态等专用动作暂不迁移。验证命令:`npm run test -- src/components/platform-entry/PlatformWorkDetailView.test.tsx src/components/common/PlatformIconButton.test.tsx`。 diff --git a/docs/technical/【前端架构】PlatformUiKit弹窗组件收口计划-2026-06-08.md b/docs/technical/【前端架构】PlatformUiKit弹窗组件收口计划-2026-06-08.md index 4a47ed40..0b7e8537 100644 --- a/docs/technical/【前端架构】PlatformUiKit弹窗组件收口计划-2026-06-08.md +++ b/docs/technical/【前端架构】PlatformUiKit弹窗组件收口计划-2026-06-08.md @@ -260,6 +260,7 @@ 19.3.36. `VisualNovelEntityGrid` 的空态也继续收口到 `PlatformEmptyState surface="subpanel" size="inline"`;角色 / 场景 / 剧情阶段共用这一网格组件后,白底实体列表里的“暂无角色 / 暂无场景 / 暂无剧情阶段”等同构空态不再回退成 `PlatformSubpanel`。同时,`RpgCreationRoleAssetStudioModalImpl.tsx` 与 `RpgCreationEntityEditorShared.tsx` 保留局部 `ActionButton` 语义壳,但按钮本体已统一委托给 `PlatformActionButton surface="editorDark"`,只在包装层补最小的 `stopPropagation`、tone 映射和局部 class 适配。后续类似“暗色编辑器局部包装按钮”优先沿用这种薄包装模式,不再直接手写原生 ` + ); +} diff --git a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx index 8683c782..912dc4d7 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx @@ -19,6 +19,7 @@ import type { import type { ConfirmWechatProfileRechargeOrderResponse, CreateProfileRechargeOrderResponse, + PlatformBrowseHistoryEntry, ProfilePlayStatsResponse, ProfileReferralInviteCenterResponse, ProfileTaskCenterResponse, @@ -902,6 +903,7 @@ function renderLoggedOutHomeView( | 'onOpenRecommendGalleryDetail' | 'onOpenChildMotionDemo' | 'onSearchPublicCode' + | 'historyEntries' | 'recommendRuntimeContent' | 'activeRecommendEntryKey' | 'isStartingRecommendEntry' @@ -945,7 +947,7 @@ function renderLoggedOutHomeView( featuredEntries={overrides.featuredEntries ?? []} latestEntries={overrides.latestEntries ?? []} myEntries={[]} - historyEntries={[]} + historyEntries={overrides.historyEntries ?? []} profileDashboard={null} isLoadingPlatform={false} isLoadingDashboard={false} @@ -3746,7 +3748,14 @@ test('discover search fuzzy matches public work id, name, author and description await user.clear(searchInput); await user.type(searchInput, '火桥{enter}'); - expect(await within(discoverPanel).findByText('火桥谜图')).toBeTruthy(); + const lavaBridgeResultButton = await within(discoverPanel).findByRole( + 'button', + { name: /火桥谜图/u }, + ); + expect(lavaBridgeResultButton.className).toContain( + 'platform-navigable-list-item', + ); + expect(within(discoverPanel).getByText('火桥谜图')).toBeTruthy(); expect(within(discoverPanel).queryByText('月井机关')).toBeNull(); await user.clear(searchInput); @@ -5336,6 +5345,41 @@ test('desktop logged in home syncs mobile home modules without square or latest expect(screen.queryByText('1777110165.990127Z')).toBeNull(); }); +test('desktop home quick access rows reuse shared navigable list item', async () => { + mockDesktopLayout(); + const user = userEvent.setup(); + const onOpenRecommendGalleryDetail = vi.fn(); + const historyEntry = { + ownerUserId: 'history-user-1', + profileId: 'history-profile-1', + worldName: '桌面最近浏览作品', + subtitle: '历史副标题', + summaryText: '这是最近浏览入口。', + coverImageSrc: null, + themeMode: 'mythic', + authorDisplayName: '历史作者', + visitedAt: new Date().toISOString(), + } satisfies PlatformBrowseHistoryEntry; + + renderLoggedOutHomeView( + vi.fn(), + { + historyEntries: [historyEntry], + onOpenRecommendGalleryDetail, + }, + 'home', + true, + ); + + const historyButton = screen.getByRole('button', { + name: /桌面最近浏览作品/u, + }); + + expect(historyButton.className).toContain('platform-navigable-list-item'); + await user.click(historyButton); + expect(onOpenRecommendGalleryDetail).toHaveBeenCalledTimes(1); +}); + test('mobile home moves category shelf into game category channel', async () => { const user = userEvent.setup(); const { container } = renderStatefulLoggedOutHomeView({ diff --git a/src/components/rpg-entry/RpgEntryHomeView.tsx b/src/components/rpg-entry/RpgEntryHomeView.tsx index 0a1f9296..c4f24165 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.tsx @@ -87,6 +87,7 @@ import { PlatformFieldLabel } from '../common/PlatformFieldLabel'; import { PlatformIconBadge } from '../common/PlatformIconBadge'; import { PlatformIconButton } from '../common/PlatformIconButton'; import { PlatformModalCloseButton } from '../common/PlatformModalCloseButton'; +import { PlatformNavigableListItem } from '../common/PlatformNavigableListItem'; import { PlatformPillBadge } from '../common/PlatformPillBadge'; import { PlatformSegmentedTabs } from '../common/PlatformSegmentedTabs'; import { PlatformStatusDialog } from '../common/PlatformStatusDialog'; @@ -1918,7 +1919,7 @@ function DesktopTrendingItem({ + ); })} @@ -4723,11 +4725,21 @@ export function RpgEntryHomeView({ ); return ( - + ); })} @@ -4760,9 +4763,8 @@ export function RpgEntryHomeView({ ); return ( - + ); })}