调整创作主页顶部与左侧栏

更新 /creation 顶部栏和左侧功能栏的参考图规格

接入创作主页 image2 陶土风背景、图标和按钮素材

保留创作主页现有文案、搜索、登录、钱包、导航与项目创建逻辑

补充创作主页改版文档和移动端直达验证
This commit is contained in:
2026-06-19 17:35:40 +08:00
parent 98545d74d1
commit e13f7e99c2
28 changed files with 833 additions and 120 deletions
@@ -9169,6 +9169,23 @@ test('creation home desktop rail can return to platform tabs', async () => {
expect(window.location.pathname).toBe('/');
});
test('direct mobile creation home keeps landing content without mobile nav entry', async () => {
window.history.replaceState(null, '', '/creation');
const { container } = render(<TestWrapper withAuth />);
expect(
await screen.findByRole('main', { name: '陶泥儿创作主页' }),
).toBeTruthy();
const bottomNav = container.querySelector('.platform-bottom-nav');
expect(bottomNav).toBeTruthy();
expect(
within(bottomNav as HTMLElement).queryByRole('button', { name: '创作' }),
).toBeNull();
expect(
within(bottomNav as HTMLElement).queryByRole('button', { name: '项目' }),
).toBeNull();
});
test('embedded puzzle form timeout exits busy state and shows a readable error', async () => {
const user = userEvent.setup();
+57 -3
View File
@@ -288,6 +288,7 @@ export interface RpgEntryHomeViewProps {
createTabContent?: ReactNode;
draftTabContent?: ReactNode;
hasUnreadDraftUpdate?: boolean;
allowHiddenActiveTab?: boolean;
}
const PANEL_SURFACE_CLASS = 'platform-surface platform-surface--soft';
@@ -319,6 +320,19 @@ const PLATFORM_DESKTOP_NAV_TABS: PlatformNavTab[] = [
'projects',
'profile',
];
const CREATION_HOME_NAV_ICON_SRC: Record<PlatformNavTab, string> = {
home: '/creation-home/nav-recommend.png',
category: '/creation-home/nav-discover.png',
create: '/creation-home/nav-create.png',
projects: '/creation-home/nav-projects.png',
saves: '/creation-home/nav-projects.png',
profile: '/creation-home/nav-profile.png',
};
const CREATION_HOME_TOPBAR_ASSETS = {
brandMascot: '/creation-home/brand-mascot.png',
search: '/creation-home/topbar-search.png',
wallet: '/creation-home/topbar-wallet.png',
} as const;
const AVATAR_MAX_FILE_SIZE = 5 * 1024 * 1024;
const AVATAR_OUTPUT_SIZE = 256;
const AVATAR_ALLOWED_TYPES = new Set(['image/jpeg', 'image/png', 'image/webp']);
@@ -1011,6 +1025,13 @@ function PublicCodeSearchBar({
<div
className={`platform-desktop-search flex min-w-0 items-center gap-3 px-4 py-3 text-[var(--platform-text-soft)] ${className ?? ''}`}
>
<img
src={CREATION_HOME_TOPBAR_ASSETS.search}
alt=""
aria-hidden="true"
draggable={false}
className="creation-home-topbar-art creation-home-topbar-art--search"
/>
<Search className="h-4 w-4 shrink-0" />
<input
value={value}
@@ -1065,6 +1086,13 @@ function TopbarWalletShortcutButton({
.filter(Boolean)
.join(' ')}
>
<img
src={CREATION_HOME_TOPBAR_ASSETS.wallet}
alt=""
aria-hidden="true"
draggable={false}
className="creation-home-topbar-art creation-home-topbar-art--wallet"
/>
<PlatformIconBadge
icon={<Coins className="h-3.5 w-3.5" />}
size="xs"
@@ -1868,6 +1896,7 @@ function DesktopTabButton({
emphasized = false,
showDot = false,
disabled = false,
creationHomeIconSrc,
}: {
active: boolean;
label: string;
@@ -1876,6 +1905,7 @@ function DesktopTabButton({
emphasized?: boolean;
showDot?: boolean;
disabled?: boolean;
creationHomeIconSrc?: string;
}) {
const ariaLabel = showDot ? `${label},有新草稿` : label;
@@ -1888,6 +1918,15 @@ function DesktopTabButton({
className={`platform-desktop-rail__button ${emphasized ? 'platform-desktop-rail__button--primary' : ''} ${active ? 'platform-desktop-rail__button--active' : ''} disabled:cursor-not-allowed disabled:opacity-55`}
>
<span className="platform-desktop-rail__icon-shell">
{creationHomeIconSrc ? (
<img
src={creationHomeIconSrc}
alt=""
aria-hidden="true"
draggable={false}
className="creation-home-nav-art"
/>
) : null}
<Icon className="platform-desktop-rail__icon h-[1.1rem] w-[1.1rem]" />
{showDot ? (
<span aria-hidden="true" className="platform-nav-unread-dot" />
@@ -2597,6 +2636,7 @@ export function RpgEntryHomeView({
createTabContent,
draftTabContent,
hasUnreadDraftUpdate = false,
allowHiddenActiveTab = false,
}: RpgEntryHomeViewProps) {
const authUi = useAuthUi();
const showRechargeEntry = shouldShowRechargeEntry();
@@ -2935,11 +2975,15 @@ export function RpgEntryHomeView({
} as const satisfies Record<PlatformNavTab, string>;
useEffect(() => {
if (allowHiddenActiveTab) {
return;
}
if (!visibleMobileTabs.includes(activeTab) && !isDesktopLayout) {
onTabChange(isAuthenticated ? 'home' : 'category');
}
}, [
activeTab,
allowHiddenActiveTab,
isAuthenticated,
isDesktopLayout,
onTabChange,
@@ -5096,8 +5140,17 @@ export function RpgEntryHomeView({
<div className="flex h-full min-h-0 flex-col">
<div className="platform-desktop-shell flex h-full min-h-0 flex-col p-5 xl:p-6">
<div className="platform-desktop-topbar flex items-center gap-4 px-5 py-4">
<div className="flex min-w-0 flex-1 items-center gap-5">
<RpgEntryBrandLogo className="shrink-0" decorative />
<div className="platform-desktop-topbar__brand-search flex min-w-0 flex-1 items-center gap-5">
<span className="creation-home-brand-lockup shrink-0">
<img
src={CREATION_HOME_TOPBAR_ASSETS.brandMascot}
alt=""
aria-hidden="true"
draggable={false}
className="creation-home-brand-lockup__art"
/>
<RpgEntryBrandLogo className="shrink-0" decorative />
</span>
<PublicCodeSearchBar
value={desktopSearchKeyword}
onChange={updateDesktopSearchKeyword}
@@ -5109,7 +5162,7 @@ export function RpgEntryHomeView({
/>
</div>
<div className="flex items-center gap-3">
<div className="platform-desktop-topbar__actions flex items-center gap-3">
{isAuthenticated &&
(activeTab === 'create' || activeTab === 'saves') ? (
<TopbarWalletShortcutButton
@@ -5162,6 +5215,7 @@ export function RpgEntryHomeView({
active={isPlatformHomeTab(tab) && activeTab === tab}
label={tabLabels[tab]}
icon={tabIcons[tab]}
creationHomeIconSrc={CREATION_HOME_NAV_ICON_SRC[tab]}
emphasized={tab === 'create'}
showDot={false}
disabled={isRechargePaymentConfirmationPending}