1
This commit is contained in:
180
src/components/platform-entry/PlatformEntryCreationTypeModal.tsx
Normal file
180
src/components/platform-entry/PlatformEntryCreationTypeModal.tsx
Normal file
@@ -0,0 +1,180 @@
|
||||
import { ArrowRight, X } from 'lucide-react';
|
||||
|
||||
export interface PlatformEntryCreationTypeModalProps {
|
||||
isOpen: boolean;
|
||||
isBusy: boolean;
|
||||
error: string | null;
|
||||
onClose: () => void;
|
||||
onSelectRpg: () => void;
|
||||
onSelectBigFish: () => void;
|
||||
onSelectPuzzle: () => void;
|
||||
}
|
||||
|
||||
type CreationGameTypeCard = {
|
||||
id: 'rpg' | 'big-fish' | 'puzzle' | 'airp' | 'visual-novel';
|
||||
title: string;
|
||||
subtitle: string;
|
||||
badge: string;
|
||||
locked: boolean;
|
||||
};
|
||||
|
||||
const CREATION_GAME_TYPES: CreationGameTypeCard[] = [
|
||||
{
|
||||
id: 'rpg',
|
||||
title: '角色扮演 RPG',
|
||||
subtitle: 'Agent 共创',
|
||||
badge: '可创建',
|
||||
locked: false,
|
||||
},
|
||||
{
|
||||
id: 'big-fish',
|
||||
title: '大鱼吃小鱼',
|
||||
subtitle: '实时成长玩法',
|
||||
badge: '可创建',
|
||||
locked: false,
|
||||
},
|
||||
{
|
||||
id: 'puzzle',
|
||||
title: '拼图玩法',
|
||||
subtitle: '图像锚点共创',
|
||||
badge: '可创建',
|
||||
locked: false,
|
||||
},
|
||||
{
|
||||
id: 'airp',
|
||||
title: 'AIRP',
|
||||
subtitle: '敬请期待',
|
||||
badge: '锁定',
|
||||
locked: true,
|
||||
},
|
||||
{
|
||||
id: 'visual-novel',
|
||||
title: '视觉小说',
|
||||
subtitle: '敬请期待',
|
||||
badge: '锁定',
|
||||
locked: true,
|
||||
},
|
||||
];
|
||||
|
||||
function CreationTypeCard(props: {
|
||||
item: CreationGameTypeCard;
|
||||
busy: boolean;
|
||||
onSelect: () => void;
|
||||
}) {
|
||||
const { item, busy, onSelect } = props;
|
||||
const disabled = item.locked || busy;
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
disabled={disabled}
|
||||
onClick={onSelect}
|
||||
className={`platform-interactive-card relative overflow-hidden rounded-[1.65rem] border px-4 py-4 text-left ${
|
||||
item.locked
|
||||
? 'cursor-not-allowed border-[var(--platform-subpanel-border)] bg-[var(--platform-subpanel-fill)] text-[var(--platform-text-soft)]'
|
||||
: 'border-[var(--platform-cool-border)] bg-[radial-gradient(circle_at_top_left,rgba(255,255,255,0.24),transparent_34%),linear-gradient(135deg,rgba(255,79,139,0.96),rgba(255,145,110,0.9))] text-white'
|
||||
} ${busy && !item.locked ? 'opacity-70' : ''}`}
|
||||
>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<span
|
||||
className={`platform-pill px-3 ${
|
||||
item.locked
|
||||
? 'platform-pill--neutral text-[var(--platform-text-soft)]'
|
||||
: 'platform-pill--neutral border-white/30 bg-white/18 text-white'
|
||||
}`}
|
||||
>
|
||||
{item.locked ? item.badge : busy ? '正在开启' : item.badge}
|
||||
</span>
|
||||
{item.locked ? (
|
||||
<span className="text-lg leading-none text-white/45">·</span>
|
||||
) : (
|
||||
<ArrowRight className="h-4 w-4 text-white/80" />
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-8 text-xl font-black leading-tight text-inherit">
|
||||
{item.title}
|
||||
</div>
|
||||
<div
|
||||
className={`mt-2 text-sm ${
|
||||
item.locked ? 'text-zinc-500' : 'text-zinc-200/82'
|
||||
}`}
|
||||
>
|
||||
{item.subtitle}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台入口创作类型弹层。
|
||||
* 多玩法入口统一在这里分流,避免把非 RPG 玩法写进 RPG 命名脚本。
|
||||
*/
|
||||
export function PlatformEntryCreationTypeModal({
|
||||
isOpen,
|
||||
isBusy,
|
||||
error,
|
||||
onClose,
|
||||
onSelectRpg,
|
||||
onSelectBigFish,
|
||||
onSelectPuzzle,
|
||||
}: PlatformEntryCreationTypeModalProps) {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="platform-overlay fixed inset-0 z-[90] flex items-end justify-center p-3 backdrop-blur-sm sm:items-center sm:p-4">
|
||||
<div className="platform-modal-shell w-full max-w-3xl overflow-hidden rounded-[1.8rem]">
|
||||
<div className="bg-transparent">
|
||||
<div className="flex items-start justify-between gap-3 border-b border-[var(--platform-subpanel-border)] px-4 py-4 sm:px-5">
|
||||
<div>
|
||||
<div className="text-base font-semibold text-[var(--platform-text-strong)]">
|
||||
选择创作类型
|
||||
</div>
|
||||
<div className="mt-1 text-xs text-[var(--platform-text-base)]">
|
||||
先选玩法类型,再进入对应创作工作台。
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
disabled={isBusy}
|
||||
className="platform-icon-button disabled:cursor-not-allowed disabled:opacity-45"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="px-4 py-4 sm:px-5 sm:py-5">
|
||||
<div className="grid gap-3 sm:grid-cols-5">
|
||||
{CREATION_GAME_TYPES.map((item) => (
|
||||
<CreationTypeCard
|
||||
key={item.id}
|
||||
item={item}
|
||||
busy={isBusy}
|
||||
onSelect={() => {
|
||||
if (item.id === 'rpg') {
|
||||
onSelectRpg();
|
||||
}
|
||||
if (item.id === 'big-fish') {
|
||||
onSelectBigFish();
|
||||
}
|
||||
if (item.id === 'puzzle') {
|
||||
onSelectPuzzle();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{error ? (
|
||||
<div className="platform-banner platform-banner--danger mt-4 rounded-[1.25rem] text-sm leading-6">
|
||||
{error}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
17
src/components/platform-entry/PlatformEntryFlowShell.tsx
Normal file
17
src/components/platform-entry/PlatformEntryFlowShell.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { PlatformEntryFlowShellImpl } from './PlatformEntryFlowShellImpl';
|
||||
import type {
|
||||
PlatformEntryFlowShellProps,
|
||||
SelectionStage,
|
||||
} from './platformEntryTypes';
|
||||
|
||||
export type { PlatformEntryFlowShellProps, SelectionStage };
|
||||
|
||||
/**
|
||||
* 平台入口通用壳层。
|
||||
* RPG、Big Fish 等玩法创作入口在这里并列分流。
|
||||
*/
|
||||
export function PlatformEntryFlowShell(props: PlatformEntryFlowShellProps) {
|
||||
return <PlatformEntryFlowShellImpl {...props} />;
|
||||
}
|
||||
|
||||
export default PlatformEntryFlowShell;
|
||||
1504
src/components/platform-entry/PlatformEntryFlowShellImpl.tsx
Normal file
1504
src/components/platform-entry/PlatformEntryFlowShellImpl.tsx
Normal file
File diff suppressed because it is too large
Load Diff
9
src/components/platform-entry/PlatformEntryHomeView.tsx
Normal file
9
src/components/platform-entry/PlatformEntryHomeView.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 平台首页视图的通用出口。
|
||||
* 当前先复用成熟的首页实现,但避免让 `platform-entry` 继续直接依赖 RPG 命名组件。
|
||||
*/
|
||||
export {
|
||||
RpgEntryHomeView as PlatformEntryHomeView,
|
||||
type RpgEntryHomeViewProps as PlatformEntryHomeViewProps,
|
||||
type PlatformHomeTab,
|
||||
} from '../rpg-entry/RpgEntryHomeView';
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* 平台作品详情视图的通用出口。
|
||||
* 这里保留平台语义封装,减少 Big Fish 继续挂在 RPG 命名路径上的误导。
|
||||
*/
|
||||
export {
|
||||
RpgEntryWorldDetailView as PlatformEntryWorldDetailView,
|
||||
type RpgEntryWorldDetailViewProps as PlatformEntryWorldDetailViewProps,
|
||||
} from '../rpg-entry/RpgEntryWorldDetailView';
|
||||
9
src/components/platform-entry/index.ts
Normal file
9
src/components/platform-entry/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export {
|
||||
PlatformEntryFlowShell,
|
||||
type PlatformEntryFlowShellProps,
|
||||
type SelectionStage,
|
||||
} from './PlatformEntryFlowShell';
|
||||
export {
|
||||
PlatformEntryCreationTypeModal,
|
||||
type PlatformEntryCreationTypeModalProps,
|
||||
} from './PlatformEntryCreationTypeModal';
|
||||
9
src/components/platform-entry/platformEntryShared.ts
Normal file
9
src/components/platform-entry/platformEntryShared.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 平台入口共享 helper 的通用封装层。
|
||||
* 先复用既有实现,同时把多玩法入口依赖从 RPG 命名中隔离出来。
|
||||
*/
|
||||
export {
|
||||
buildCreationHubFallbackItems,
|
||||
normalizeAgentBackedProfile,
|
||||
resolveRpgCreationErrorMessage,
|
||||
} from '../rpg-entry/rpgEntryShared';
|
||||
41
src/components/platform-entry/platformEntryTypes.ts
Normal file
41
src/components/platform-entry/platformEntryTypes.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import type {
|
||||
CustomWorldAgentSessionSnapshot,
|
||||
} from '../../../packages/shared/src/contracts/customWorldAgent';
|
||||
import type { HydratedSavedGameSnapshot } from '../../persistence/runtimeSnapshotTypes';
|
||||
import type { CustomWorldProfile, GameState } from '../../types';
|
||||
|
||||
export type SelectionStage =
|
||||
| 'platform'
|
||||
| 'detail'
|
||||
| 'agent-workspace'
|
||||
| 'big-fish-agent-workspace'
|
||||
| 'big-fish-result'
|
||||
| 'big-fish-runtime'
|
||||
| 'puzzle-agent-workspace'
|
||||
| 'puzzle-result'
|
||||
| 'puzzle-gallery-detail'
|
||||
| 'puzzle-runtime'
|
||||
| 'custom-world-generating'
|
||||
| 'custom-world-result';
|
||||
|
||||
export type CustomWorldGenerationViewSource = 'agent-draft-foundation' | null;
|
||||
|
||||
export type CustomWorldResultViewSource = 'saved-profile' | 'agent-draft' | null;
|
||||
|
||||
export type CustomWorldAutoSaveState = 'idle' | 'saving' | 'saved' | 'error';
|
||||
|
||||
export type SyncedAgentDraftResult = {
|
||||
session: CustomWorldAgentSessionSnapshot | null;
|
||||
profile: CustomWorldProfile | null;
|
||||
};
|
||||
|
||||
export type PlatformEntryFlowShellProps = {
|
||||
selectionStage: SelectionStage;
|
||||
setSelectionStage: (stage: SelectionStage) => void;
|
||||
gameState: GameState;
|
||||
hasSavedGame: boolean;
|
||||
savedSnapshot: HydratedSavedGameSnapshot | null;
|
||||
handleContinueGame: (snapshot?: HydratedSavedGameSnapshot | null) => void;
|
||||
handleStartNewGame: () => void;
|
||||
handleCustomWorldSelect: (customWorldProfile: CustomWorldProfile) => void;
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* 平台入口 bootstrap 通用封装。
|
||||
* 现阶段逻辑仍复用既有实现,但对外暴露平台语义命名。
|
||||
*/
|
||||
export { useRpgEntryBootstrap as usePlatformEntryBootstrap } from '../rpg-entry/useRpgEntryBootstrap';
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* 平台入口详情态编排通用封装。
|
||||
* 通过平台语义出口避免 Big Fish 直接依赖 RPG 命名 hook。
|
||||
*/
|
||||
export { useRpgEntryLibraryDetail as usePlatformEntryLibraryDetail } from '../rpg-entry/useRpgEntryLibraryDetail';
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* 平台入口导航通用封装。
|
||||
* 多玩法统一从 `platform-entry` 暴露,RPG 目录只保留兼容与 RPG 专属能力。
|
||||
*/
|
||||
export { useRpgEntryNavigation as usePlatformEntryNavigation } from '../rpg-entry/useRpgEntryNavigation';
|
||||
Reference in New Issue
Block a user