feat: integrate jump-hop shelf and asset flow

This commit is contained in:
kdletters
2026-05-24 19:00:21 +08:00
parent 2ba4691bc0
commit 42037860d5
25 changed files with 1018 additions and 149 deletions

View File

@@ -6,6 +6,7 @@ import type { CustomWorldWorkSummary } from '../../../packages/shared/src/contra
import type { BabyObjectMatchDraft } from '../../../packages/shared/src/contracts/edutainmentBabyObject';
import type { Match3DWorkSummary } from '../../../packages/shared/src/contracts/match3dWorks';
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
import type { JumpHopWorkSummaryResponse } from '../../../packages/shared/src/contracts/jumpHop';
import type { CustomWorldLibraryEntry } from '../../../packages/shared/src/contracts/runtime';
import type { SquareHoleWorkSummary } from '../../../packages/shared/src/contracts/squareHoleWorks';
import type { VisualNovelWorkSummary } from '../../../packages/shared/src/contracts/visualNovel';
@@ -61,6 +62,9 @@ type CustomWorldCreationHubProps = {
squareHoleItems?: SquareHoleWorkSummary[];
onOpenSquareHoleDetail?: (item: SquareHoleWorkSummary) => void;
onDeleteSquareHole?: ((item: SquareHoleWorkSummary) => void) | null;
jumpHopItems?: JumpHopWorkSummaryResponse[];
onOpenJumpHopDetail?: (item: JumpHopWorkSummaryResponse) => void;
onDeleteJumpHop?: ((item: JumpHopWorkSummaryResponse) => void) | null;
puzzleItems?: PuzzleWorkSummary[];
onOpenPuzzleDetail?: (item: PuzzleWorkSummary) => void;
onDeletePuzzle?: ((item: PuzzleWorkSummary) => void) | null;
@@ -169,6 +173,9 @@ export function CustomWorldCreationHub({
squareHoleItems = [],
onOpenSquareHoleDetail,
onDeleteSquareHole = null,
jumpHopItems = [],
onOpenJumpHopDetail,
onDeleteJumpHop = null,
puzzleItems = [],
onOpenPuzzleDetail,
onDeletePuzzle = null,
@@ -201,6 +208,7 @@ export function CustomWorldCreationHub({
bigFishItems,
match3dItems,
squareHoleItems: isSquareHoleCreationVisible ? squareHoleItems : [],
jumpHopItems,
puzzleItems,
babyObjectMatchItems,
barkBattleItems,
@@ -210,6 +218,7 @@ export function CustomWorldCreationHub({
canDeleteMatch3D: Boolean(onDeleteMatch3D),
canDeleteSquareHole:
isSquareHoleCreationVisible && Boolean(onDeleteSquareHole),
canDeleteJumpHop: Boolean(onDeleteJumpHop),
canDeletePuzzle: Boolean(onDeletePuzzle),
canDeleteBabyObjectMatch: Boolean(onDeleteBabyObjectMatch),
canDeleteBarkBattle: Boolean(onDeleteBarkBattle),
@@ -223,6 +232,8 @@ export function CustomWorldCreationHub({
onDeleteMatch3D: onDeleteMatch3D ?? undefined,
onOpenSquareHoleDetail,
onDeleteSquareHole: onDeleteSquareHole ?? undefined,
onOpenJumpHopDetail: onOpenJumpHopDetail ?? undefined,
onDeleteJumpHop: onDeleteJumpHop ?? undefined,
onOpenPuzzleDetail,
onDeletePuzzle: onDeletePuzzle ?? undefined,
onClaimPuzzlePointIncentive: onClaimPuzzlePointIncentive ?? undefined,
@@ -249,6 +260,7 @@ export function CustomWorldCreationHub({
onDeleteBabyObjectMatch,
onDeleteBarkBattle,
onDeleteVisualNovel,
onDeleteJumpHop,
onClaimPuzzlePointIncentive,
onOpenBigFishDetail,
onOpenDraft,
@@ -262,7 +274,9 @@ export function CustomWorldCreationHub({
getWorkState,
puzzleItems,
rpgLibraryEntries,
squareHoleItems,
onOpenSquareHoleDetail,
onOpenJumpHopDetail,
jumpHopItems,
visualNovelItems,
],
);
@@ -310,6 +324,9 @@ export function CustomWorldCreationHub({
case 'square-hole':
onOpenSquareHoleDetail?.(item.source.item);
return;
case 'jump-hop':
onOpenJumpHopDetail?.(item.source.item);
return;
case 'rpg':
if (item.status === 'draft') {
onOpenDraft(item.source.item);

View File

@@ -59,6 +59,7 @@ const CREATION_WORK_KIND_FALLBACK_COVER: Record<CreationWorkShelfKind, string> =
'big-fish': '/creation-type-references/big-fish.webp',
match3d: '/creation-type-references/match3d.webp',
'square-hole': '/creation-type-references/square-hole.webp',
'jump-hop': '/creation-type-references/jump-hop.webp',
puzzle: '/creation-type-references/puzzle.webp',
'baby-object-match': '/creation-type-references/creative-agent.webp',
'bark-battle': '/creation-type-references/bark-battle.webp',

View File

@@ -7,11 +7,13 @@ import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/p
import type { CustomWorldLibraryEntry } from '../../../packages/shared/src/contracts/runtime';
import type { SquareHoleWorkSummary } from '../../../packages/shared/src/contracts/squareHoleWorks';
import type { VisualNovelWorkSummary } from '../../../packages/shared/src/contracts/visualNovel';
import type { JumpHopWorkSummaryResponse } from '../../../packages/shared/src/contracts/jumpHop';
import { buildPublicWorkStagePath } from '../../routing/appPageRoutes';
import {
buildBabyObjectMatchPublicWorkCode,
buildBarkBattlePublicWorkCode,
buildBigFishPublicWorkCode,
buildJumpHopPublicWorkCode,
buildMatch3DPublicWorkCode,
buildPuzzlePublicWorkCode,
buildSquareHolePublicWorkCode,
@@ -30,6 +32,7 @@ export type CreationWorkShelfKind =
| 'big-fish'
| 'match3d'
| 'square-hole'
| 'jump-hop'
| 'puzzle'
| 'baby-object-match'
| 'bark-battle'
@@ -82,6 +85,10 @@ export type CreationWorkShelfSource =
kind: 'square-hole';
item: SquareHoleWorkSummary;
}
| {
kind: 'jump-hop';
item: JumpHopWorkSummaryResponse;
}
| {
kind: 'puzzle';
item: PuzzleWorkSummary;
@@ -136,6 +143,7 @@ export function buildCreationWorkShelfItems(params: {
bigFishItems: BigFishWorkSummary[];
match3dItems?: Match3DWorkSummary[];
squareHoleItems?: SquareHoleWorkSummary[];
jumpHopItems?: JumpHopWorkSummaryResponse[];
puzzleItems: PuzzleWorkSummary[];
babyObjectMatchItems?: BabyObjectMatchDraft[];
barkBattleItems?: BarkBattleWorkSummary[];
@@ -144,6 +152,7 @@ export function buildCreationWorkShelfItems(params: {
canDeleteBigFish?: boolean;
canDeleteMatch3D?: boolean;
canDeleteSquareHole?: boolean;
canDeleteJumpHop?: boolean;
canDeletePuzzle?: boolean;
canDeleteBabyObjectMatch?: boolean;
canDeleteBarkBattle?: boolean;
@@ -157,6 +166,8 @@ export function buildCreationWorkShelfItems(params: {
onDeleteMatch3D?: (item: Match3DWorkSummary) => void;
onOpenSquareHoleDetail?: (item: SquareHoleWorkSummary) => void;
onDeleteSquareHole?: (item: SquareHoleWorkSummary) => void;
onOpenJumpHopDetail?: (item: JumpHopWorkSummaryResponse) => void;
onDeleteJumpHop?: (item: JumpHopWorkSummaryResponse) => void;
onOpenPuzzleDetail?: (item: PuzzleWorkSummary) => void;
onDeletePuzzle?: (item: PuzzleWorkSummary) => void;
onClaimPuzzlePointIncentive?: (item: PuzzleWorkSummary) => void;
@@ -176,6 +187,7 @@ export function buildCreationWorkShelfItems(params: {
bigFishItems,
match3dItems = [],
squareHoleItems = [],
jumpHopItems = [],
puzzleItems,
babyObjectMatchItems = [],
barkBattleItems = [],
@@ -184,6 +196,7 @@ export function buildCreationWorkShelfItems(params: {
canDeleteBigFish = false,
canDeleteMatch3D = false,
canDeleteSquareHole = false,
canDeleteJumpHop = false,
canDeletePuzzle = false,
canDeleteBabyObjectMatch = false,
canDeleteBarkBattle = false,
@@ -197,6 +210,8 @@ export function buildCreationWorkShelfItems(params: {
onDeleteMatch3D,
onOpenSquareHoleDetail,
onDeleteSquareHole,
onOpenJumpHopDetail,
onDeleteJumpHop,
onOpenPuzzleDetail,
onDeletePuzzle,
onClaimPuzzlePointIncentive,
@@ -235,6 +250,12 @@ export function buildCreationWorkShelfItems(params: {
onDelete: onDeleteSquareHole,
}),
),
...jumpHopItems.map((item) =>
mapJumpHopWorkToShelfItem(item, canDeleteJumpHop, {
onOpen: onOpenJumpHopDetail,
onDelete: onDeleteJumpHop,
}),
),
...puzzleItems.map((item) =>
mapPuzzleWorkToShelfItem(item, canDeletePuzzle, {
onOpen: onOpenPuzzleDetail,
@@ -745,6 +766,51 @@ function mapSquareHoleWorkToShelfItem(
};
}
function mapJumpHopWorkToShelfItem(
item: JumpHopWorkSummaryResponse,
canDelete: boolean,
adapter: WorkShelfAdapter<JumpHopWorkSummaryResponse>,
): CreationWorkShelfItem {
const status = item.publicationStatus === 'published' ? 'published' : 'draft';
const publicWorkCode =
status === 'published' ? buildJumpHopPublicWorkCode(item.profileId) : null;
const coverImageSrc = normalizeCoverImageSrc(item.coverImageSrc);
return {
id: item.workId,
kind: 'jump-hop',
status,
title: item.workTitle,
summary: item.workDescription,
authorDisplayName: resolveAuthorDisplayName(item),
updatedAt: item.updatedAt,
coverImageSrc,
coverRenderMode: 'image',
coverCharacterImageSrcs: [],
publicWorkCode,
sharePath:
publicWorkCode && status === 'published'
? buildPublicWorkStagePath('work-detail', publicWorkCode)
: null,
openActionLabel: status === 'published' ? '查看详情' : '继续创作',
canDelete,
canShare: status === 'published' && Boolean(publicWorkCode),
badges: [
buildStatusBadge(status),
{ id: 'type', label: '跳一跳', tone: 'neutral' },
],
metrics:
status === 'published'
? buildPublishedMetrics({
playCount: item.playCount,
remixCount: 0,
likeCount: 0,
})
: [],
actions: buildWorkShelfActions(item, adapter),
source: { kind: 'jump-hop', item },
};
}
function resolveAuthorDisplayName(
...sources: Array<unknown>