实现创作者主页与关注粉丝功能
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 6m35s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m10s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m29s
Project CI / Frontend tests (pull_request) Failing after 55s
Project CI / Backend tests (pull_request) Successful in 8m13s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m37s
Project CI / Repository checks (pull_request) Successful in 7m5s
Project CI / Native shell tests (pull_request) Successful in 9m2s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 6m35s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m10s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m29s
Project CI / Frontend tests (pull_request) Failing after 55s
Project CI / Backend tests (pull_request) Successful in 8m13s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m37s
Project CI / Repository checks (pull_request) Successful in 7m5s
Project CI / Native shell tests (pull_request) Successful in 9m2s
新增创作者公开主页、第四导航入口、详情作者跳转及关注按钮 实现关注与粉丝列表、取消后重新关注、回关及移除粉丝交互 新增私有关注关系表、类型契约、受信过程和站内查询写入接口 按作者过滤公开游戏并保持既有四十八项读取边界 复用共享用户行、关注按钮及游戏卡,接入移动布局和页面深链 补充定向测试、隔离数据库及浏览器验收脚本并归并工程验证文档
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
Palette,
|
||||
Search,
|
||||
UserRound,
|
||||
UsersRound,
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
type ComponentType,
|
||||
@@ -27,6 +28,11 @@ import {
|
||||
pushAppHistoryPath,
|
||||
replaceAppHistoryPath,
|
||||
} from '../../routing/activeAppPageRoutes';
|
||||
import {
|
||||
connectionsPath,
|
||||
type CreatorConnectionKind,
|
||||
creatorPath,
|
||||
} from '../../services/creatorProfileClient';
|
||||
import { loadFrontendRuntimeConfig } from '../../services/frontendRuntimeConfigService';
|
||||
import { getPlatformProfileDashboard } from '../../services/platform-entry/platformProfileClient';
|
||||
import { usePlatformWalletStore } from '../../stores/usePlatformWalletStore';
|
||||
@@ -35,6 +41,7 @@ import { FLOATING_FEEDBACK_FORM_URL } from '../common/floatingFeedbackEntryModel
|
||||
import { PlatformActionButton } from '../common/PlatformActionButton';
|
||||
import { PlatformSubpanel } from '../common/PlatformSubpanel';
|
||||
import { ClientDownloadEntry } from '../creation-home/ClientDownloadEntry';
|
||||
import { setCreatorViewer } from '../creator/creatorRelationshipState';
|
||||
import { PaymentCheckoutView } from './PaymentCheckoutView';
|
||||
import {
|
||||
PlatformActiveMobileWelcomeDialog,
|
||||
@@ -80,6 +87,14 @@ const GameGalleryPage = lazy(async () => {
|
||||
return { default: module.GameGalleryPage };
|
||||
});
|
||||
|
||||
const CreatorPage = lazy(async () => {
|
||||
const module = await import('../creator/CreatorPage');
|
||||
return { default: module.CreatorPage };
|
||||
});
|
||||
const CreatorConnectionsPage = lazy(async () => {
|
||||
const module = await import('../creator/CreatorConnectionsPage');
|
||||
return { default: module.CreatorConnectionsPage };
|
||||
});
|
||||
const GameDetailPage = lazy(async () => {
|
||||
const module = await import('../game-distribution/GameDetailPage');
|
||||
return { default: module.GameDetailPage };
|
||||
@@ -181,16 +196,20 @@ function MobileProfileDock({
|
||||
onOpenProfile,
|
||||
gameActive,
|
||||
onOpenGames,
|
||||
creatorActive,
|
||||
onOpenCreator,
|
||||
}: {
|
||||
active: boolean;
|
||||
onOpenProfile: () => void;
|
||||
gameActive: boolean;
|
||||
onOpenGames: () => void;
|
||||
creatorActive: boolean;
|
||||
onOpenCreator: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="platform-mobile-bottom-dock min-w-0 shrink-0 lg:hidden">
|
||||
<nav
|
||||
className="platform-bottom-nav grid grid-cols-2"
|
||||
className="platform-bottom-nav grid grid-cols-3"
|
||||
aria-label="移动平台导航"
|
||||
>
|
||||
<ActiveBottomNavButton
|
||||
@@ -199,6 +218,12 @@ function MobileProfileDock({
|
||||
label="游戏"
|
||||
onClick={onOpenGames}
|
||||
/>
|
||||
<ActiveBottomNavButton
|
||||
active={creatorActive}
|
||||
icon={UsersRound}
|
||||
label="创作者主页"
|
||||
onClick={onOpenCreator}
|
||||
/>
|
||||
<ActiveBottomNavButton
|
||||
active={active}
|
||||
icon={UserRound}
|
||||
@@ -410,6 +435,39 @@ export function PlatformEntryFlowShellImpl({
|
||||
setSelectionStage('profile-payment', { path: '/profile/payment' });
|
||||
}, [setSelectionStage]);
|
||||
|
||||
const creatorViewer = authUi?.canAccessProtectedData
|
||||
? (authUi.user?.id ?? null)
|
||||
: null;
|
||||
useEffect(() => {
|
||||
setCreatorViewer(creatorViewer);
|
||||
}, [creatorViewer]);
|
||||
const openCreator = useCallback(
|
||||
(id?: string) => {
|
||||
const path = id ? creatorPath(id) : '/creators';
|
||||
pushAppHistoryPath(path);
|
||||
setSelectionStage('creator-home', { path });
|
||||
},
|
||||
[setSelectionStage],
|
||||
);
|
||||
const openCreatorConnections = useCallback(
|
||||
(id: string, tab: CreatorConnectionKind) => {
|
||||
const path = connectionsPath(id, tab);
|
||||
pushAppHistoryPath(path);
|
||||
setSelectionStage('creator-connections', { path });
|
||||
},
|
||||
[setSelectionStage],
|
||||
);
|
||||
const backFromCreator = useCallback(() => {
|
||||
if (hasAppHistoryBackEntry()) {
|
||||
window.history.back();
|
||||
return;
|
||||
}
|
||||
const owner =
|
||||
selectionStage === 'creator-connections'
|
||||
? new URLSearchParams(window.location.search).get('id')
|
||||
: null;
|
||||
openCreator(owner ?? undefined);
|
||||
}, [openCreator, selectionStage]);
|
||||
const openGames = useCallback(() => {
|
||||
setSelectionStage('games', { path: '/games' });
|
||||
}, [setSelectionStage]);
|
||||
@@ -561,6 +619,8 @@ export function PlatformEntryFlowShellImpl({
|
||||
<MobileProfileDock
|
||||
active={false}
|
||||
gameActive={false}
|
||||
creatorActive={false}
|
||||
onOpenCreator={() => openCreator()}
|
||||
onOpenProfile={openProfile}
|
||||
onOpenGames={openGames}
|
||||
/>
|
||||
@@ -599,6 +659,9 @@ export function PlatformEntryFlowShellImpl({
|
||||
const isCreationStage =
|
||||
!isProfileStage &&
|
||||
(selectionStage === 'platform' || selectionStage === 'creation-home');
|
||||
const isCreatorStage =
|
||||
selectionStage === 'creator-home' ||
|
||||
selectionStage === 'creator-connections';
|
||||
const isGamesStage =
|
||||
selectionStage === 'games' ||
|
||||
selectionStage === 'game-detail' ||
|
||||
@@ -677,6 +740,13 @@ export function PlatformEntryFlowShellImpl({
|
||||
label="游戏"
|
||||
onClick={openGames}
|
||||
/>
|
||||
<ActiveRailButton
|
||||
active={isCreatorStage}
|
||||
icon={UsersRound}
|
||||
iconSrc="/creation-home/nav-profile.png"
|
||||
label="创作者主页"
|
||||
onClick={() => openCreator()}
|
||||
/>
|
||||
<ActiveRailButton
|
||||
active={isProfileStage}
|
||||
icon={UserRound}
|
||||
@@ -829,6 +899,31 @@ export function PlatformEntryFlowShellImpl({
|
||||
searchKeyword={activeSearchKeyword}
|
||||
/>
|
||||
</Suspense>
|
||||
) : isCreatorStage ? (
|
||||
<Suspense
|
||||
fallback={<LoadingPanel label="正在加载创作者主页…" />}
|
||||
>
|
||||
{selectionStage === 'creator-connections' ? (
|
||||
<CreatorConnectionsPage
|
||||
id={gameId}
|
||||
tab={
|
||||
gameSearchParams.get('tab') === 'followers'
|
||||
? 'followers'
|
||||
: 'following'
|
||||
}
|
||||
onOpenCreator={openCreator}
|
||||
onOpenConnections={openCreatorConnections}
|
||||
onBack={backFromCreator}
|
||||
/>
|
||||
) : (
|
||||
<CreatorPage
|
||||
id={gameId}
|
||||
onOpenConnections={openCreatorConnections}
|
||||
onOpenGame={openGameDetail}
|
||||
onBack={backFromCreator}
|
||||
/>
|
||||
)}
|
||||
</Suspense>
|
||||
) : isGamesStage ? (
|
||||
<Suspense
|
||||
fallback={<LoadingPanel label="正在加载游戏广场..." />}
|
||||
@@ -867,6 +962,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
) : selectionStage === 'game-detail' ? (
|
||||
<GameDetailPage
|
||||
gameId={gameId}
|
||||
onOpenCreator={openCreator}
|
||||
ownerView={gameSearchParams.get('owner') === '1'}
|
||||
onBack={backFromGameDetail}
|
||||
onPlay={openGamePlay}
|
||||
@@ -889,6 +985,8 @@ export function PlatformEntryFlowShellImpl({
|
||||
<MobileProfileDock
|
||||
active={isProfileStage}
|
||||
gameActive={isGamesStage}
|
||||
creatorActive={isCreatorStage}
|
||||
onOpenCreator={() => openCreator()}
|
||||
onOpenProfile={openProfile}
|
||||
onOpenGames={openGames}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user