Files
Genarrative/src/PuzzlePlaygroundApp.tsx
kdletters cbc27bad4a
Some checks failed
CI / verify (push) Has been cancelled
init with react+axum+spacetimedb
2026-04-26 18:06:23 +08:00

90 lines
3.3 KiB
TypeScript

import { useMemo, useState } from 'react';
import type {
DragPuzzlePieceRequest,
SwapPuzzlePiecesRequest,
} from '../packages/shared/src/contracts/puzzleRuntimeSession';
import type { PuzzleWorkSummary } from '../packages/shared/src/contracts/puzzleWorkSummary';
import { PuzzleRuntimeShell } from './components/puzzle-runtime/PuzzleRuntimeShell';
import {
advanceLocalPuzzleLevel,
dragLocalPuzzlePiece,
startLocalPuzzleRun,
swapLocalPuzzlePieces,
} from './services/puzzle-runtime/puzzleLocalRuntime';
const PLACEHOLDER_PUZZLE_IMAGE =
'data:image/svg+xml;utf8,' +
encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 960">
<defs>
<linearGradient id="sky" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#fef3c7" />
<stop offset="0.45" stop-color="#fb7185" />
<stop offset="1" stop-color="#312e81" />
</linearGradient>
<radialGradient id="glow" cx="42%" cy="34%" r="46%">
<stop offset="0" stop-color="#ffffff" stop-opacity="0.78" />
<stop offset="1" stop-color="#ffffff" stop-opacity="0" />
</radialGradient>
</defs>
<rect width="960" height="960" fill="url(#sky)" />
<circle cx="312" cy="282" r="210" fill="url(#glow)" />
<path d="M0 680 C170 610 278 724 424 650 C574 574 704 612 960 512 V960 H0 Z" fill="#1e1b4b" opacity="0.9" />
<path d="M0 766 C178 710 320 794 492 732 C642 678 780 708 960 652 V960 H0 Z" fill="#111827" opacity="0.78" />
<path d="M160 356 C238 298 326 304 388 376 C456 456 550 436 626 374 C710 306 824 330 882 410" fill="none" stroke="#fff7ed" stroke-width="18" stroke-linecap="round" opacity="0.72" />
<path d="M204 502 h552" stroke="#ffffff" stroke-width="16" stroke-linecap="round" opacity="0.3" />
<path d="M268 566 h424" stroke="#ffffff" stroke-width="12" stroke-linecap="round" opacity="0.22" />
</svg>`);
function buildPlaceholderPuzzleWork(): PuzzleWorkSummary {
return {
workId: 'placeholder-puzzle-work',
profileId: 'placeholder-puzzle-profile',
ownerUserId: 'placeholder-user',
sourceSessionId: null,
authorDisplayName: '占位作者',
levelName: '暮色群山',
summary: '用于直达玩法调试的本地占位拼图。',
themeTags: ['占位', '风景', '调试'],
coverImageSrc: PLACEHOLDER_PUZZLE_IMAGE,
coverAssetId: null,
publicationStatus: 'published',
updatedAt: new Date(0).toISOString(),
publishedAt: new Date(0).toISOString(),
playCount: 0,
publishReady: true,
};
}
export default function PuzzlePlaygroundApp() {
const placeholderWork = useMemo(() => buildPlaceholderPuzzleWork(), []);
const [run, setRun] = useState(() => startLocalPuzzleRun(placeholderWork));
const handleSwapPieces = (payload: SwapPuzzlePiecesRequest) => {
setRun((currentRun) => swapLocalPuzzlePieces(currentRun, payload));
};
const handleDragPiece = (payload: DragPuzzlePieceRequest) => {
setRun((currentRun) => dragLocalPuzzlePiece(currentRun, payload));
};
const handleRestart = () => {
setRun(startLocalPuzzleRun(placeholderWork));
};
const handleAdvanceNextLevel = () => {
setRun((currentRun) => advanceLocalPuzzleLevel(currentRun));
};
return (
<PuzzleRuntimeShell
run={run}
onBack={handleRestart}
onSwapPieces={handleSwapPieces}
onDragPiece={handleDragPiece}
onAdvanceNextLevel={handleAdvanceNextLevel}
/>
);
}