继续收口首页公开分区异步状态壳
统一首页公开列表与我的创作分区的异步状态切换到 PlatformAsyncStatePanel 补充首页异步状态回归测试覆盖登录态作品分区与桌面公开空态 更新 PlatformUiKit 收口计划与共享决策记录
This commit is contained in:
@@ -53,6 +53,7 @@
|
||||
- 2026-06-10 追加:`PlatformStatusDialog` 支持自定义图标、图标可访问标签以及动作按钮 surface / size / className 透传,用来承接玩法结果页里保留品牌视觉但语义仍是“状态结果弹层”的场景;大鱼吃小鱼结果页的发布失败弹层已迁移到这套组件,业务页不再保留 `UnifiedConfirmDialog + PlatformIconBadge` 的专用组合。
|
||||
- 2026-06-10 追加:`PlatformStatusDialog` 继续支持 header notice 布局、body content、close button、backdrop / Escape 关闭路径,用来承接“提示 / 规则阻断 / 作品不可用 / 泥点不足”这类带标题栏的状态 notice;平台入口的 `draftGenerationPointNotice`、`workNotFoundRecoveryDialog` 和 RPG 大编辑器里的 `EditorNoticeDialog` 已迁移到这套共享组件,不再各自维护 `UnifiedConfirmDialog` 壳层和关闭策略。
|
||||
- 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-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`。
|
||||
|
||||
@@ -259,6 +259,7 @@
|
||||
19.3.35. 白底 / 暗色面板里的轻量空态和普通 CTA 继续按共享组件收口:`PuzzleResultView.tsx` 的“还没有可编辑的拼图草稿”、`RpgCreationAssetDebugPanel.tsx` 的“没有可诊断项”、`VisualNovelEntityGrid` 的空实体列表、`AccountModal.tsx` 里账号安全分区的“无安全限制 / 无登录设备 / 无操作记录”以及 `LoginScreen.tsx` 的“当前登录入口暂不可用”都改为 `PlatformEmptyState`;`Match3DResultView.tsx` 的引用素材列表直接交给 `PlatformAssetPickerGrid` 自己处理空态。`AdventureEntityModal.tsx` 的私聊按钮、`InventoryPanel.tsx` 的锻造 / 合成按钮、`RpgAdventurePanel.tsx` 底部 `队伍 / 背包 / 换一换 / 退出聊天` 按钮,以及 `RpgAdventurePanelOverlays.tsx` 里的“查看任务 / 保存并退出”都改为 `PlatformActionButton surface="editorDark"`,业务页只贴回局部 sky / emerald / runtime 皮肤。后续白底子面板里的只读空态优先使用 `PlatformEmptyState surface="subpanel"`;暗色编辑 / 运行面板里的普通动作优先使用 `PlatformActionButton surface="editorDark"`,若还需要 stopPropagation、局部字号或图标排版,可保留薄包装层,但不要再回退到原生 `<button>` 基础 chrome。验证命令:`npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx src/components/rpg-creation-result/RpgCreationAssetDebugPanel.test.tsx src/components/AdventureEntityModal.test.tsx src/components/InventoryPanel.test.tsx src/components/auth/AccountModal.test.tsx src/components/rpg-runtime-panels/RpgAdventurePanel.test.tsx src/components/rpg-runtime-panels/RpgAdventurePanel.npcChat.test.tsx src/components/rpg-runtime-panels/RpgAdventurePanel.questOffer.test.tsx src/components/common/PlatformEmptyState.test.tsx src/components/common/PlatformActionButton.test.tsx`、`npm run check:encoding`。
|
||||
19.3.36. `VisualNovelEntityGrid` 的空态也继续收口到 `PlatformEmptyState surface="subpanel" size="inline"`;角色 / 场景 / 剧情阶段共用这一网格组件后,白底实体列表里的“暂无角色 / 暂无场景 / 暂无剧情阶段”等同构空态不再回退成 `PlatformSubpanel`。同时,`RpgCreationRoleAssetStudioModalImpl.tsx` 与 `RpgCreationEntityEditorShared.tsx` 保留局部 `ActionButton` 语义壳,但按钮本体已统一委托给 `PlatformActionButton surface="editorDark"`,只在包装层补最小的 `stopPropagation`、tone 映射和局部 class 适配。后续类似“暗色编辑器局部包装按钮”优先沿用这种薄包装模式,不再直接手写原生 `<button>` 基础 chrome。验证命令:`npm run test -- src/components/visual-novel-result/VisualNovelResultView.test.tsx src/components/common/PlatformEmptyState.test.tsx src/components/rpg-creation-asset-studio/RpgCreationRoleAssetStudioModal.test.tsx src/components/CustomWorldEntityEditorModal.test.tsx src/components/common/PlatformActionButton.test.tsx`、`npm run check:encoding`。
|
||||
19.3.37. 暗色编辑器里的局部动作按钮继续往共享 `editorDark` button 收口:`CustomWorldNpcVisualEditor.tsx` 的本地 `ActionButton` 和 `SkillEffectPreview.tsx` 的“重新预览”按钮都改为委托 `PlatformActionButton surface="editorDark"`。这类局部包装仍可保留 `stopPropagation`、图标布局、`tone` 映射和少量局部视觉覆写,但按钮本体不再直接使用原生 `<button>` 承接边框 / 底色 / hover / disabled chrome。验证命令:`npm run test -- src/components/common/PlatformActionButton.test.tsx`、`npm run typecheck`、`npm run check:encoding`、`git diff --check`。
|
||||
19.3.38. `PlatformAsyncStatePanel` 继续从 profile / 作品架扩展到首页公开分区:`RpgEntryHomeView.tsx` 的移动端排行、发现页寓教于乐 / 默认公开 feed、桌面首页“今日游戏 / 推荐”、桌面发现页寓教于乐 / 默认公开 feed,以及“我的创作”分区都统一改成 `loadingState / emptyState / children` 三个 slot 切换。页面继续把 `platformError` 保留在状态壳外层,让错误提示可以和内容并存;`recommend runtime`、分类筛选和其它含二级筛选 / 运行态语义的分支暂不并入这次收口。后续首页、作品架或白底列表若只是纯 `loading / empty / content` 互斥状态,优先直接复用 `PlatformAsyncStatePanel`,不要再把空态与读取态分支手写回业务 JSX。验证命令:`npx vitest run src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx`、`npm run typecheck`、`npm run check:encoding`、`git diff --check`。
|
||||
19.3. creative-agent 首页的侧边栏菜单、账号入口、开启新对话、我的创作、首页激励 CTA 和 prompt suggestion 按钮迁移到 `PlatformIconButton` / `PlatformActionButton`;首页继续保留 `creative-agent-home__*` 本地 class 承接透明顶栏、抽屉和品牌化胶囊视觉,不把视觉回收和语义收口绑成一次大改。`Beta` 徽标和历史记录纯文本行暂保留本地实现,等出现更多同构轻量列表行后再评估是否抽新的共享 row primitive。
|
||||
19.4. 大鱼吃小鱼结果页 hero 的返回入口迁移到 `PlatformIconButton variant="darkMini"`,测试 / 发布动作迁移到 `PlatformActionButton surface="editorDark"`;结果页只保留测试运行、发布提交和文案状态语义,不再手写 hero 顶栏按钮壳。
|
||||
19.4.1. 大鱼吃小鱼结果页的发布失败弹层迁移到 `src/components/common/PlatformStatusDialog.tsx`;`PlatformStatusDialog` 补充自定义图标、可访问标签和动作按钮样式透传后,`BigFishResultView` 不再保留 `BigFishResultErrorModal` 内联的 `UnifiedConfirmDialog + PlatformIconBadge` 组合。结果页只保留失败文案和关闭回调,发布失败的状态图标、遮罩、白底面板和“知道了”主动作统一由共享状态弹层承接。验证命令:`npm run test -- src/components/common/PlatformStatusDialog.test.tsx src/components/big-fish-result/BigFishResultView.test.tsx`、`npm run typecheck`。
|
||||
|
||||
@@ -983,7 +983,11 @@ function renderLoggedInHomeView(
|
||||
overrides: Partial<
|
||||
Pick<
|
||||
RpgEntryHomeViewProps,
|
||||
'activeTab' | 'hasUnreadDraftUpdate' | 'draftTabContent'
|
||||
| 'activeTab'
|
||||
| 'hasUnreadDraftUpdate'
|
||||
| 'draftTabContent'
|
||||
| 'myEntries'
|
||||
| 'isLoadingPlatform'
|
||||
>
|
||||
> = {},
|
||||
) {
|
||||
@@ -1025,10 +1029,10 @@ function renderLoggedInHomeView(
|
||||
saveError={null}
|
||||
featuredEntries={[]}
|
||||
latestEntries={[]}
|
||||
myEntries={[]}
|
||||
myEntries={overrides.myEntries ?? []}
|
||||
historyEntries={[]}
|
||||
profileDashboard={null}
|
||||
isLoadingPlatform={false}
|
||||
isLoadingPlatform={overrides.isLoadingPlatform ?? false}
|
||||
isLoadingDashboard={false}
|
||||
isResumingSaveWorldKey={null}
|
||||
platformError={null}
|
||||
@@ -3514,6 +3518,40 @@ test('logged in draft bottom tab shows unread marker', () => {
|
||||
expect(draftButton.querySelector('.platform-nav-unread-dot')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('logged in saves tab shows loading state while fetching my entries', () => {
|
||||
renderLoggedInHomeView({
|
||||
activeTab: 'saves',
|
||||
isLoadingPlatform: true,
|
||||
});
|
||||
|
||||
expect(screen.getByText('我的创作')).toBeTruthy();
|
||||
expect(screen.getByText('正在读取你的作品...')).toBeTruthy();
|
||||
expect(
|
||||
screen.queryByText('你还没有保存任何自定义世界,先创建一个草稿开始吧。'),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test('logged in saves tab shows empty state when my entries are missing', () => {
|
||||
renderLoggedInHomeView({
|
||||
activeTab: 'saves',
|
||||
myEntries: [],
|
||||
});
|
||||
|
||||
expect(screen.getByText('我的创作')).toBeTruthy();
|
||||
expect(
|
||||
screen.getByText('你还没有保存任何自定义世界,先创建一个草稿开始吧。'),
|
||||
).toBeTruthy();
|
||||
expect(screen.queryByText('正在读取你的作品...')).toBeNull();
|
||||
});
|
||||
|
||||
test('desktop home shows empty states when public shelves are unavailable', () => {
|
||||
mockDesktopLayout();
|
||||
renderLoggedOutHomeView(vi.fn(), {}, 'home', true);
|
||||
|
||||
expect(screen.getByText('今天暂时还没有新游戏。')).toBeTruthy();
|
||||
expect(screen.getByText('暂时还没有推荐作品。')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('logged in create tab shows real wallet balance beside the brand', () => {
|
||||
mockNarrowMobileLayout();
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ import { shouldShowRechargeEntry } from '../../services/payment/paymentPlatform'
|
||||
import type { CustomWorldProfile } from '../../types';
|
||||
import { useAuthUi } from '../auth/AuthUiContext';
|
||||
import { PlatformAcknowledgeStatusDialog } from '../common/PlatformAcknowledgeStatusDialog';
|
||||
import { PlatformAsyncStatePanel } from '../common/PlatformAsyncStatePanel';
|
||||
import { CopyFeedbackButton } from '../common/CopyFeedbackButton';
|
||||
import { LegalDocumentModal } from '../common/LegalDocumentModal';
|
||||
import {
|
||||
@@ -3539,9 +3540,14 @@ export function RpgEntryHomeView({
|
||||
}
|
||||
/>
|
||||
|
||||
{isLoadingPlatform ? (
|
||||
<PlatformEmptyState>正在读取公开作品...</PlatformEmptyState>
|
||||
) : rankingEntries.length > 0 ? (
|
||||
<PlatformAsyncStatePanel
|
||||
isLoading={isLoadingPlatform}
|
||||
loadingState={<PlatformEmptyState>正在读取公开作品...</PlatformEmptyState>}
|
||||
isEmpty={rankingEntries.length === 0}
|
||||
emptyState={
|
||||
<PlatformEmptyState>{activeRankingConfig.emptyText}</PlatformEmptyState>
|
||||
}
|
||||
>
|
||||
<div className="mt-3 grid min-w-0 gap-2.5">
|
||||
{rankingEntries.map((entry, index) => (
|
||||
<PlatformRankingItem
|
||||
@@ -3553,9 +3559,7 @@ export function RpgEntryHomeView({
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<PlatformEmptyState>{activeRankingConfig.emptyText}</PlatformEmptyState>
|
||||
)}
|
||||
</PlatformAsyncStatePanel>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -3823,11 +3827,18 @@ export function RpgEntryHomeView({
|
||||
</section>
|
||||
) : discoverChannel === 'edutainment' ? (
|
||||
<section className="platform-mobile-home-feed">
|
||||
{isLoadingPlatform ? (
|
||||
<PlatformEmptyState>正在读取公开作品...</PlatformEmptyState>
|
||||
) : edutainmentFeedEntries.length > 0 ||
|
||||
onOpenChildMotionDemo ||
|
||||
onOpenBabyLoveDrawing ? (
|
||||
<PlatformAsyncStatePanel
|
||||
isLoading={isLoadingPlatform}
|
||||
loadingState={<PlatformEmptyState>正在读取公开作品...</PlatformEmptyState>}
|
||||
isEmpty={
|
||||
edutainmentFeedEntries.length === 0 &&
|
||||
!onOpenChildMotionDemo &&
|
||||
!onOpenBabyLoveDrawing
|
||||
}
|
||||
emptyState={
|
||||
<PlatformEmptyState>暂时还没有可展示的作品。</PlatformEmptyState>
|
||||
}
|
||||
>
|
||||
<div className="grid min-w-0 gap-3">
|
||||
{edutainmentFeedEntries.map((entry) => {
|
||||
const cardKey = buildPublicGalleryCardKey(entry);
|
||||
@@ -3881,20 +3892,23 @@ export function RpgEntryHomeView({
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
) : (
|
||||
<PlatformEmptyState>
|
||||
暂时还没有可展示的作品。
|
||||
</PlatformEmptyState>
|
||||
)}
|
||||
</PlatformAsyncStatePanel>
|
||||
</section>
|
||||
) : (
|
||||
<section
|
||||
ref={mobileDiscoverFeedRef}
|
||||
className="platform-mobile-home-feed"
|
||||
>
|
||||
{isLoadingPlatform ? (
|
||||
<PlatformEmptyState>正在读取公开作品...</PlatformEmptyState>
|
||||
) : discoverFeedEntries.length > 0 ? (
|
||||
<PlatformAsyncStatePanel
|
||||
isLoading={isLoadingPlatform}
|
||||
loadingState={<PlatformEmptyState>正在读取公开作品...</PlatformEmptyState>}
|
||||
isEmpty={discoverFeedEntries.length === 0}
|
||||
emptyState={
|
||||
<PlatformEmptyState>
|
||||
公开广场暂时还没有可展示的作品。
|
||||
</PlatformEmptyState>
|
||||
}
|
||||
>
|
||||
<div className="grid min-w-0 gap-3">
|
||||
{discoverFeedEntries.map(
|
||||
(entry: PlatformPublicGalleryCard) => {
|
||||
@@ -3918,11 +3932,7 @@ export function RpgEntryHomeView({
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<PlatformEmptyState>
|
||||
公开广场暂时还没有可展示的作品。
|
||||
</PlatformEmptyState>
|
||||
)}
|
||||
</PlatformAsyncStatePanel>
|
||||
</section>
|
||||
)}
|
||||
</>
|
||||
@@ -4043,11 +4053,18 @@ export function RpgEntryHomeView({
|
||||
) : discoverChannel === 'edutainment' ? (
|
||||
<section className="platform-desktop-panel px-5 py-5">
|
||||
<SectionHeader title={EDUTAINMENT_WORK_TAG} detail="EDUTAINMENT" />
|
||||
{isLoadingPlatform ? (
|
||||
<PlatformEmptyState>正在读取公开作品...</PlatformEmptyState>
|
||||
) : edutainmentFeedEntries.length > 0 ||
|
||||
onOpenChildMotionDemo ||
|
||||
onOpenBabyLoveDrawing ? (
|
||||
<PlatformAsyncStatePanel
|
||||
isLoading={isLoadingPlatform}
|
||||
loadingState={<PlatformEmptyState>正在读取公开作品...</PlatformEmptyState>}
|
||||
isEmpty={
|
||||
edutainmentFeedEntries.length === 0 &&
|
||||
!onOpenChildMotionDemo &&
|
||||
!onOpenBabyLoveDrawing
|
||||
}
|
||||
emptyState={
|
||||
<PlatformEmptyState>暂时还没有可展示的作品。</PlatformEmptyState>
|
||||
}
|
||||
>
|
||||
<div className="grid gap-4 xl:grid-cols-3">
|
||||
{edutainmentFeedEntries.map((entry) => (
|
||||
<WorldCard
|
||||
@@ -4096,9 +4113,7 @@ export function RpgEntryHomeView({
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
) : (
|
||||
<PlatformEmptyState>暂时还没有可展示的作品。</PlatformEmptyState>
|
||||
)}
|
||||
</PlatformAsyncStatePanel>
|
||||
</section>
|
||||
) : (
|
||||
<section className="platform-desktop-panel px-5 py-5">
|
||||
@@ -4106,9 +4121,16 @@ export function RpgEntryHomeView({
|
||||
title={discoverChannel === 'today' ? '今日游戏' : '推荐'}
|
||||
detail={discoverChannel === 'today' ? 'TODAY GAMES' : 'RECOMMENDED'}
|
||||
/>
|
||||
{isLoadingPlatform ? (
|
||||
<PlatformEmptyState>正在读取公开作品...</PlatformEmptyState>
|
||||
) : discoverFeedEntries.length > 0 ? (
|
||||
<PlatformAsyncStatePanel
|
||||
isLoading={isLoadingPlatform}
|
||||
loadingState={<PlatformEmptyState>正在读取公开作品...</PlatformEmptyState>}
|
||||
isEmpty={discoverFeedEntries.length === 0}
|
||||
emptyState={
|
||||
<PlatformEmptyState>
|
||||
公开广场暂时还没有可展示的作品。
|
||||
</PlatformEmptyState>
|
||||
}
|
||||
>
|
||||
<div className="grid gap-4 xl:grid-cols-3">
|
||||
{discoverFeedEntries.map((entry) => (
|
||||
<WorldCard
|
||||
@@ -4121,11 +4143,7 @@ export function RpgEntryHomeView({
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<PlatformEmptyState>
|
||||
公开广场暂时还没有可展示的作品。
|
||||
</PlatformEmptyState>
|
||||
)}
|
||||
</PlatformAsyncStatePanel>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
@@ -4181,9 +4199,18 @@ export function RpgEntryHomeView({
|
||||
{platformError}
|
||||
</PlatformStatusMessage>
|
||||
) : null}
|
||||
{isLoadingPlatform ? (
|
||||
<PlatformEmptyState>正在读取你的作品...</PlatformEmptyState>
|
||||
) : myEntries.length > 0 ? (
|
||||
<PlatformAsyncStatePanel
|
||||
isLoading={isLoadingPlatform}
|
||||
loadingState={<PlatformEmptyState>正在读取你的作品...</PlatformEmptyState>}
|
||||
isEmpty={myEntries.length === 0}
|
||||
emptyState={
|
||||
<PlatformEmptyState>
|
||||
{isAuthenticated
|
||||
? '你还没有保存任何自定义世界,先创建一个草稿开始吧。'
|
||||
: '登录后查看你的作品。'}
|
||||
</PlatformEmptyState>
|
||||
}
|
||||
>
|
||||
<div className="grid grid-cols-2 gap-2.5 sm:gap-3 xl:grid-cols-3">
|
||||
{myEntries.map(
|
||||
(entry: CustomWorldLibraryEntry<CustomWorldProfile>) => (
|
||||
@@ -4201,13 +4228,7 @@ export function RpgEntryHomeView({
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<PlatformEmptyState>
|
||||
{isAuthenticated
|
||||
? '你还没有保存任何自定义世界,先创建一个草稿开始吧。'
|
||||
: '登录后查看你的作品。'}
|
||||
</PlatformEmptyState>
|
||||
)}
|
||||
</PlatformAsyncStatePanel>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
@@ -4629,9 +4650,14 @@ export function RpgEntryHomeView({
|
||||
TODAY
|
||||
</PlatformPillBadge>
|
||||
</div>
|
||||
{isLoadingPlatform ? (
|
||||
<PlatformEmptyState>正在读取今日游戏...</PlatformEmptyState>
|
||||
) : desktopTodayEntries.length > 0 ? (
|
||||
<PlatformAsyncStatePanel
|
||||
isLoading={isLoadingPlatform}
|
||||
loadingState={<PlatformEmptyState>正在读取今日游戏...</PlatformEmptyState>}
|
||||
isEmpty={desktopTodayEntries.length === 0}
|
||||
emptyState={
|
||||
<PlatformEmptyState>今天暂时还没有新游戏。</PlatformEmptyState>
|
||||
}
|
||||
>
|
||||
<div className="space-y-3">
|
||||
{desktopTodayEntries.slice(0, 3).map((entry, index) => (
|
||||
<DesktopTrendingItem
|
||||
@@ -4642,9 +4668,7 @@ export function RpgEntryHomeView({
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<PlatformEmptyState>今天暂时还没有新游戏。</PlatformEmptyState>
|
||||
)}
|
||||
</PlatformAsyncStatePanel>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -4653,9 +4677,14 @@ export function RpgEntryHomeView({
|
||||
>
|
||||
<section className="platform-desktop-panel px-5 py-5">
|
||||
<SectionHeader title="推荐" detail="RECOMMENDED" />
|
||||
{isLoadingPlatform ? (
|
||||
<PlatformEmptyState>正在读取推荐作品...</PlatformEmptyState>
|
||||
) : desktopFeaturedGrid.length > 0 ? (
|
||||
<PlatformAsyncStatePanel
|
||||
isLoading={isLoadingPlatform}
|
||||
loadingState={<PlatformEmptyState>正在读取推荐作品...</PlatformEmptyState>}
|
||||
isEmpty={desktopFeaturedGrid.length === 0}
|
||||
emptyState={
|
||||
<PlatformEmptyState>暂时还没有推荐作品。</PlatformEmptyState>
|
||||
}
|
||||
>
|
||||
<div className="grid gap-4 xl:grid-cols-2">
|
||||
{desktopFeaturedGrid.map((entry) => (
|
||||
<WorldCard
|
||||
@@ -4668,9 +4697,7 @@ export function RpgEntryHomeView({
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<PlatformEmptyState>暂时还没有推荐作品。</PlatformEmptyState>
|
||||
)}
|
||||
</PlatformAsyncStatePanel>
|
||||
</section>
|
||||
|
||||
{desktopLibraryPreview.length > 0 ||
|
||||
|
||||
Reference in New Issue
Block a user