init with react+axum+spacetimedb
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-26 18:06:23 +08:00
commit cbc27bad4a
20199 changed files with 883714 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
/* @vitest-environment jsdom */
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { beforeEach, expect, test, vi } from 'vitest';
import type { BigFishSessionSnapshotResponse } from '../../../packages/shared/src/contracts/bigFish';
import { BigFishAgentWorkspace } from './BigFishAgentWorkspace';
const baseSession: BigFishSessionSnapshotResponse = {
sessionId: 'big-fish-session-1',
currentTurn: 3,
progressPercent: 64,
stage: 'collecting_anchors',
anchorPack: {
gameplayPromise: {
key: 'gameplayPromise',
label: '玩法承诺',
value: '从微光小鱼一路吞噬成长为深海巨兽',
status: 'confirmed',
},
ecologyVisualTheme: {
key: 'ecologyVisualTheme',
label: '生态视觉主题',
value: '幽蓝珊瑚海沟',
status: 'confirmed',
},
growthLadder: {
key: 'growthLadder',
label: '成长阶梯',
value: '',
status: 'missing',
},
riskTempo: {
key: 'riskTempo',
label: '风险节奏',
value: '',
status: 'missing',
},
},
draft: null,
assetSlots: [],
assetCoverage: {
levelMainImageReadyCount: 0,
levelMotionReadyCount: 0,
backgroundReady: false,
requiredLevelCount: 8,
publishReady: false,
blockers: [],
},
messages: [
{
id: 'message-1',
role: 'assistant',
kind: 'chat',
text: '爽点和生态已经清楚,继续补剩余关键词。',
createdAt: '2026-04-24T10:00:00.000Z',
},
],
lastAssistantReply: '爽点和生态已经清楚,继续补剩余关键词。',
publishReady: false,
updatedAt: '2026-04-24T10:00:00.000Z',
};
beforeEach(() => {
if (!Element.prototype.scrollIntoView) {
Element.prototype.scrollIntoView = () => {};
}
});
test('big fish workspace submits quick keyword fill request after two turns', async () => {
const user = userEvent.setup();
const onSubmitMessage = vi.fn();
render(
<BigFishAgentWorkspace
session={baseSession}
onBack={() => {}}
onSubmitMessage={onSubmitMessage}
onExecuteAction={() => {}}
/>,
);
await user.click(screen.getByRole('button', { name: '补充剩余设定' }));
expect(onSubmitMessage).toHaveBeenCalledWith(
expect.objectContaining({
text: '请补充剩余设定。',
quickFillRequested: true,
}),
);
});
test('big fish workspace hides keyword fill before two turns', () => {
render(
<BigFishAgentWorkspace
session={{ ...baseSession, currentTurn: 1 }}
onBack={() => {}}
onSubmitMessage={() => {}}
onExecuteAction={() => {}}
/>,
);
expect(screen.queryByRole('button', { name: '补充剩余设定' })).toBeNull();
});

View File

@@ -0,0 +1,123 @@
import type {
BigFishAnchorItemResponse,
BigFishSessionSnapshotResponse,
ExecuteBigFishActionRequest,
SendBigFishMessageRequest,
} from '../../../packages/shared/src/contracts/bigFish';
import {
buildCreationAgentChatMessage,
createCreationAgentChatQuickActions,
createCreationAgentClientMessageId,
resolveCreationAgentQuickActionMessage,
} from '../../services/creation-agent';
import {
type CreationAgentAnchorView,
type CreationAgentSessionView,
type CreationAgentTheme,
CreationAgentWorkspace,
} from '../creation-agent';
type BigFishAgentWorkspaceProps = {
session: BigFishSessionSnapshotResponse | null;
streamingReplyText?: string;
isStreamingReply?: boolean;
isBusy?: boolean;
error?: string | null;
onBack: () => void;
onSubmitMessage: (payload: SendBigFishMessageRequest) => void;
onExecuteAction: (payload: ExecuteBigFishActionRequest) => void;
};
const BIG_FISH_AGENT_THEME: CreationAgentTheme = {
accentTextClass: 'text-cyan-100/85',
accentBgClass: 'bg-cyan-200',
accentButtonClass: 'bg-cyan-200 shadow-cyan-950/20',
userBubbleClass: 'bg-cyan-600 text-white',
heroClass:
'border border-cyan-100/16 bg-[radial-gradient(circle_at_top_left,rgba(45,212,191,0.22),transparent_32%),linear-gradient(135deg,rgba(8,47,73,0.96),rgba(13,24,38,0.96))]',
anchorGridClass: 'grid gap-2 sm:grid-cols-4',
};
function mapBigFishAnchor(
anchor: BigFishAnchorItemResponse,
): CreationAgentAnchorView {
return {
key: anchor.key,
label: anchor.label,
value: anchor.value,
status: anchor.status,
};
}
function mapBigFishSession(
session: BigFishSessionSnapshotResponse,
): CreationAgentSessionView {
return {
sessionId: session.sessionId,
// 所有玩法的 Agent 聊天页顶部模块只保留操作与进度,不展示标题和引导副文案。
title: null,
assistantSummary: null,
currentTurn: session.currentTurn,
progressPercent: session.progressPercent,
anchors: [
session.anchorPack.gameplayPromise,
session.anchorPack.ecologyVisualTheme,
session.anchorPack.growthLadder,
session.anchorPack.riskTempo,
].map(mapBigFishAnchor),
messages: session.messages,
recommendedReplies: [],
};
}
export function BigFishAgentWorkspace({
session,
streamingReplyText = '',
isStreamingReply = false,
isBusy = false,
error = null,
onBack,
onSubmitMessage,
onExecuteAction,
}: BigFishAgentWorkspaceProps) {
return (
<CreationAgentWorkspace
session={session ? mapBigFishSession(session) : null}
theme={BIG_FISH_AGENT_THEME}
loadingText="正在准备大鱼吃小鱼共创工作区..."
composerPlaceholder="说说这局的生态、成长或爽点..."
primaryActionLabel="生成结果页"
streamingReplyText={streamingReplyText}
isStreamingReply={isStreamingReply}
isBusy={isBusy}
error={error}
quickActions={createCreationAgentChatQuickActions()}
onBack={onBack}
onSubmitText={(text) => {
onSubmitMessage(
buildCreationAgentChatMessage({
clientMessageId: createCreationAgentClientMessageId('big-fish'),
text,
}),
);
}}
onPrimaryAction={() => {
onExecuteAction({ action: 'big_fish_compile_draft' });
}}
onQuickAction={(action) => {
const quickActionMessage = resolveCreationAgentQuickActionMessage(
action.key,
'请总结一下当前已经成形的大鱼吃小鱼设定。',
);
onSubmitMessage(
buildCreationAgentChatMessage({
clientMessageId: createCreationAgentClientMessageId('big-fish'),
...quickActionMessage,
}),
);
}}
/>
);
}
export default BigFishAgentWorkspace;