feat: add platform browse history tab updates
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
victo
2026-04-15 18:32:04 +08:00
parent 6363267bca
commit 00dfb78b00
3 changed files with 311 additions and 50 deletions

View File

@@ -1,4 +1,3 @@
import { type ComponentType, useMemo } from 'react';
import {
BookOpen,
Camera,
@@ -13,6 +12,7 @@ import {
Ticket,
UserPlus,
} from 'lucide-react';
import { type ComponentType, useMemo } from 'react';
import type {
CustomWorldGalleryCard,
@@ -20,6 +20,7 @@ import type {
} from '../../../packages/shared/src/contracts/runtime';
import type { HydratedSavedGameSnapshot } from '../../persistence/runtimeSnapshotTypes';
import type { AuthUser } from '../../services/authService';
import type { PlatformBrowseHistoryEntry } from '../../services/platformBrowseHistory';
import type { CustomWorldProfile } from '../../types';
import { getNineSliceStyle, UI_CHROME } from '../../uiAssets';
import { useAuthUi } from '../auth/AuthUiContext';
@@ -33,7 +34,7 @@ import {
resolvePlatformWorldLeadPortrait,
} from './platformWorldPresentation';
export type PlatformHomeTab = 'home' | 'create' | 'profile';
export type PlatformHomeTab = 'home' | 'create' | 'discover' | 'profile';
function SectionHeader({ title, detail }: { title: string; detail: string }) {
return (
@@ -312,6 +313,7 @@ export function PlatformHomeView({
featuredEntries,
latestEntries,
myEntries,
historyEntries,
isLoadingPlatform,
platformError,
onContinueGame,
@@ -327,6 +329,7 @@ export function PlatformHomeView({
featuredEntries: CustomWorldGalleryCard[];
latestEntries: CustomWorldGalleryCard[];
myEntries: CustomWorldLibraryEntry<CustomWorldProfile>[];
historyEntries: PlatformBrowseHistoryEntry[];
isLoadingPlatform: boolean;
platformError: string | null;
onContinueGame: () => void;
@@ -365,6 +368,8 @@ export function PlatformHomeView({
const tabIcons = {
home: "/Icons/Admurin's Pixel Items/Admurin's Pixel Items/Miscellaneous/Singles/192_RustyTrinket_House.png",
create: '/Icons/01_Scroll.png',
discover:
"/Icons/Admurin's Pixel Items/Admurin's Pixel Items/Miscellaneous/Singles/321_Compass.png",
profile: '/UI/Icon_Eq_Head.png',
} as const;
const recentPlayItems = savedSnapshot
@@ -519,6 +524,49 @@ export function PlatformHomeView({
);
}
if (activeTab === 'discover') {
content = (
<div className="space-y-4 pb-2">
<section
className="pixel-nine-slice"
style={getNineSliceStyle(UI_CHROME.panel, {
paddingX: 18,
paddingY: 16,
})}
>
<div className="rounded-full border border-white/10 bg-black/20 px-3 py-1 text-[10px] tracking-[0.2em] text-zinc-100">
DISCOVER
</div>
<div className="mt-4 text-3xl font-black text-white"></div>
<div className="mt-2 max-w-[28rem] text-sm leading-6 text-zinc-300">
便
</div>
</section>
<section>
<SectionHeader title="最近上新" detail="先看广场里的新内容" />
{isLoadingPlatform ? (
<EmptyShelf text="正在读取推荐内容..." />
) : latestEntries.length > 0 ? (
<div className="flex gap-3 overflow-x-auto pb-1 scrollbar-hide">
{latestEntries.map((entry: CustomWorldGalleryCard) => (
<WorldCard
key={`${entry.ownerUserId}:${entry.profileId}:discover`}
entry={entry}
badge={formatPlatformWorldTime(entry.publishedAt)}
metaLabel={describePlatformThemeLabel(entry.themeMode)}
onClick={() => onOpenGalleryDetail(entry)}
/>
))}
</div>
) : (
<EmptyShelf text="发现频道暂时还没有可展示的内容。" />
)}
</section>
</div>
);
}
if (activeTab === 'profile') {
content = (
<div className="space-y-4 pb-2">
@@ -662,6 +710,77 @@ export function PlatformHomeView({
)}
</section>
<section
className="pixel-nine-slice"
style={getNineSliceStyle(UI_CHROME.panel, {
paddingX: 16,
paddingY: 14,
})}
>
<SectionHeader title="历史浏览" detail="最近看过的作品" />
{historyEntries.length > 0 ? (
<div className="flex gap-3 overflow-x-auto pb-1 scrollbar-hide">
{historyEntries.map((entry) => (
<button
key={`${entry.ownerUserId}:${entry.profileId}:history`}
type="button"
onClick={() =>
onOpenGalleryDetail({
ownerUserId: entry.ownerUserId,
profileId: entry.profileId,
visibility: 'published',
publishedAt: entry.visitedAt,
updatedAt: entry.visitedAt,
worldName: entry.worldName,
subtitle: entry.subtitle,
summaryText: entry.summaryText,
coverImageSrc: entry.coverImageSrc,
themeMode: entry.themeMode,
authorDisplayName: entry.authorDisplayName,
playableNpcCount: 0,
landmarkCount: 0,
})
}
className="relative flex h-[10.5rem] w-[17rem] shrink-0 overflow-hidden rounded-[1.4rem] border border-white/10 bg-[linear-gradient(135deg,rgba(25,32,46,0.95),rgba(9,12,18,0.96))] p-4 text-left"
>
{entry.coverImageSrc ? (
<img
src={entry.coverImageSrc}
alt={entry.worldName}
className="absolute inset-0 h-full w-full object-cover opacity-22"
style={{ imageRendering: 'pixelated' }}
/>
) : null}
<div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(8,10,14,0.08),rgba(8,10,14,0.9))]" />
<div className="relative z-10 flex h-full flex-col">
<div className="flex items-start justify-between gap-3">
<span className="rounded-full border border-amber-300/20 bg-amber-500/10 px-3 py-1 text-[10px] tracking-[0.2em] text-amber-100">
HISTORY
</span>
<span className="text-[11px] text-zinc-400">
{formatSnapshotTime(entry.visitedAt)}
</span>
</div>
<div className="mt-auto">
<div className="line-clamp-1 text-xl font-black text-white">
{entry.worldName}
</div>
<div className="mt-1 text-sm text-zinc-300">
{entry.authorDisplayName}
</div>
<div className="mt-2 line-clamp-3 text-xs leading-5 text-zinc-400">
{entry.summaryText || entry.subtitle || '等待补充世界摘要。'}
</div>
</div>
</div>
</button>
))}
</div>
) : (
<EmptyShelf text="你最近还没有浏览过作品详情,去首页或发现逛一逛吧。" />
)}
</section>
<section
className="pixel-nine-slice"
style={getNineSliceStyle(UI_CHROME.panel, {
@@ -726,7 +845,7 @@ export function PlatformHomeView({
className="mt-4 border-t border-white/5 pt-3"
style={{ paddingBottom: 'calc(env(safe-area-inset-bottom) + 0.2rem)' }}
>
<div className="grid h-14 grid-cols-3 gap-1 rounded-[1.2rem] bg-black/18 px-1 py-1">
<div className="grid h-14 grid-cols-4 gap-1 rounded-[1.2rem] bg-black/18 px-1 py-1">
<PlatformTabButton
active={activeTab === 'home'}
label="首页"
@@ -739,6 +858,12 @@ export function PlatformHomeView({
iconSrc={tabIcons.create}
onClick={() => onTabChange('create')}
/>
<PlatformTabButton
active={activeTab === 'discover'}
label="发现"
iconSrc={tabIcons.discover}
onClick={() => onTabChange('discover')}
/>
<PlatformTabButton
active={activeTab === 'profile'}
label="我的"