feat: add puzzle clear template runtime
This commit is contained in:
@@ -143,6 +143,7 @@ import {
|
||||
isEdutainmentGalleryEntry,
|
||||
isJumpHopGalleryEntry,
|
||||
isMatch3DGalleryEntry,
|
||||
isPuzzleClearGalleryEntry,
|
||||
isPuzzleGalleryEntry,
|
||||
isSquareHoleGalleryEntry,
|
||||
isVisualNovelGalleryEntry,
|
||||
@@ -1908,6 +1909,9 @@ function describePublicGalleryCardKind(entry: PlatformPublicGalleryCard) {
|
||||
if (isPuzzleGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag('拼图');
|
||||
}
|
||||
if (isPuzzleClearGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag('拼消消');
|
||||
}
|
||||
if (isMatch3DGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag('抓大鹅');
|
||||
}
|
||||
|
||||
@@ -10,10 +10,12 @@ import {
|
||||
formatPlatformWorldTime,
|
||||
isBarkBattleGalleryEntry,
|
||||
isEdutainmentGalleryEntry,
|
||||
isPuzzleClearGalleryEntry,
|
||||
isVisualNovelGalleryEntry,
|
||||
isWoodenFishGalleryEntry,
|
||||
mapBabyObjectMatchDraftToPlatformGalleryCard,
|
||||
mapBarkBattleWorkToPlatformGalleryCard,
|
||||
mapPuzzleClearWorkToPlatformGalleryCard,
|
||||
mapVisualNovelWorkToPlatformGalleryCard,
|
||||
mapWoodenFishWorkToPlatformGalleryCard,
|
||||
type PlatformEdutainmentGalleryCard,
|
||||
@@ -198,6 +200,35 @@ test('maps wooden fish work to platform gallery card with WF public code', () =>
|
||||
expect(buildPlatformWorldDisplayTags(card, 2)).toEqual(['敲木鱼']);
|
||||
});
|
||||
|
||||
test('maps puzzle clear work to platform gallery card with PC public code', () => {
|
||||
const card = mapPuzzleClearWorkToPlatformGalleryCard({
|
||||
runtimeKind: 'puzzle-clear',
|
||||
workId: 'puzzle-clear-work-1',
|
||||
profileId: 'puzzle-clear-profile-12345678',
|
||||
ownerUserId: 'user-1',
|
||||
sourceSessionId: 'puzzle-clear-session-1',
|
||||
workTitle: '星港拼消消',
|
||||
workDescription: '霓虹星港主题。',
|
||||
themePrompt: '霓虹星港',
|
||||
coverImageSrc: '/generated-puzzle-clear-assets/profile/atlas.png',
|
||||
publicationStatus: 'published',
|
||||
playCount: 6,
|
||||
updatedAt: '2026-05-30T00:00:00.000Z',
|
||||
publishedAt: '2026-05-30T00:00:00.000Z',
|
||||
publishReady: true,
|
||||
generationStatus: 'ready',
|
||||
});
|
||||
|
||||
expect(isPuzzleClearGalleryEntry(card)).toBe(true);
|
||||
expect(card.sourceType).toBe('puzzle-clear');
|
||||
expect(card.publicWorkCode).toBe('PC-12345678');
|
||||
expect(resolvePlatformPublicWorkCode(card)).toBe('PC-12345678');
|
||||
expect(resolvePlatformWorldFallbackCoverImage(card)).toBe(
|
||||
'/creation-type-references/puzzle.webp',
|
||||
);
|
||||
expect(buildPlatformWorldDisplayTags(card, 2)).toEqual(['拼消消', '霓虹星港']);
|
||||
});
|
||||
|
||||
test('resolves public work author from display name and public user code before stored author name', () => {
|
||||
const card = mapWoodenFishWorkToPlatformGalleryCard({
|
||||
publicWorkCode: 'WF-AUTHOR1',
|
||||
|
||||
@@ -7,6 +7,11 @@ import type {
|
||||
JumpHopGalleryCardResponse,
|
||||
JumpHopWorkProfileResponse,
|
||||
} from '../../../packages/shared/src/contracts/jumpHop';
|
||||
import type {
|
||||
PuzzleClearGalleryCardResponse,
|
||||
PuzzleClearWorkProfileResponse,
|
||||
PuzzleClearWorkSummaryResponse,
|
||||
} from '../../../packages/shared/src/contracts/puzzleClear';
|
||||
import type {
|
||||
Match3DGeneratedBackgroundAsset,
|
||||
Match3DGeneratedItemAsset,
|
||||
@@ -36,6 +41,7 @@ import {
|
||||
buildBigFishPublicWorkCode,
|
||||
buildJumpHopPublicWorkCode,
|
||||
buildMatch3DPublicWorkCode,
|
||||
buildPuzzleClearPublicWorkCode,
|
||||
buildPuzzlePublicWorkCode,
|
||||
buildSquareHolePublicWorkCode,
|
||||
buildVisualNovelPublicWorkCode,
|
||||
@@ -56,6 +62,7 @@ export type PlatformWorldCardLike =
|
||||
| PlatformMatch3DGalleryCard
|
||||
| PlatformSquareHoleGalleryCard
|
||||
| PlatformPuzzleGalleryCard
|
||||
| PlatformPuzzleClearGalleryCard
|
||||
| PlatformJumpHopGalleryCard
|
||||
| PlatformWoodenFishGalleryCard
|
||||
| PlatformVisualNovelGalleryCard
|
||||
@@ -213,6 +220,29 @@ export type PlatformJumpHopGalleryCard = {
|
||||
stylePreset?: string;
|
||||
};
|
||||
|
||||
export type PlatformPuzzleClearGalleryCard = {
|
||||
sourceType: 'puzzle-clear';
|
||||
workId: string;
|
||||
profileId: string;
|
||||
sourceSessionId?: string | null;
|
||||
publicWorkCode: string;
|
||||
ownerUserId: string;
|
||||
authorDisplayName: string;
|
||||
worldName: string;
|
||||
subtitle: string;
|
||||
summaryText: string;
|
||||
coverImageSrc: string | null;
|
||||
themeTags: string[];
|
||||
playCount?: number;
|
||||
remixCount?: number;
|
||||
likeCount?: number;
|
||||
recentPlayCount7d?: number;
|
||||
visibility: 'published';
|
||||
publishedAt: string | null;
|
||||
updatedAt: string;
|
||||
themePrompt: string;
|
||||
};
|
||||
|
||||
export type PlatformWoodenFishGalleryCard = {
|
||||
sourceType: 'wooden-fish';
|
||||
workId: string;
|
||||
@@ -294,6 +324,7 @@ export type PlatformPublicGalleryCard =
|
||||
| PlatformMatch3DGalleryCard
|
||||
| PlatformSquareHoleGalleryCard
|
||||
| PlatformPuzzleGalleryCard
|
||||
| PlatformPuzzleClearGalleryCard
|
||||
| PlatformJumpHopGalleryCard
|
||||
| PlatformWoodenFishGalleryCard
|
||||
| PlatformVisualNovelGalleryCard
|
||||
@@ -342,6 +373,12 @@ export function isJumpHopGalleryEntry(
|
||||
return 'sourceType' in entry && entry.sourceType === 'jump-hop';
|
||||
}
|
||||
|
||||
export function isPuzzleClearGalleryEntry(
|
||||
entry: PlatformWorldCardLike,
|
||||
): entry is PlatformPuzzleClearGalleryCard {
|
||||
return 'sourceType' in entry && entry.sourceType === 'puzzle-clear';
|
||||
}
|
||||
|
||||
export function isWoodenFishGalleryEntry(
|
||||
entry: PlatformWorldCardLike,
|
||||
): entry is PlatformWoodenFishGalleryCard {
|
||||
@@ -548,6 +585,68 @@ export function mapJumpHopWorkToPlatformGalleryCard(
|
||||
};
|
||||
}
|
||||
|
||||
function normalizePuzzleClearThemeTags(summary: PuzzleClearWorkSummaryResponse) {
|
||||
const themePrompt = summary.themePrompt.trim();
|
||||
return [
|
||||
'拼消消',
|
||||
...(themePrompt ? [themePrompt] : []),
|
||||
];
|
||||
}
|
||||
|
||||
function getPuzzleClearRecentPlayCount(
|
||||
summary: PuzzleClearGalleryCardResponse | PuzzleClearWorkSummaryResponse,
|
||||
) {
|
||||
if (!('recentPlayCount7d' in summary)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return typeof summary.recentPlayCount7d === 'number'
|
||||
? summary.recentPlayCount7d
|
||||
: 0;
|
||||
}
|
||||
|
||||
export function mapPuzzleClearWorkToPlatformGalleryCard(
|
||||
work:
|
||||
| PuzzleClearGalleryCardResponse
|
||||
| PuzzleClearWorkSummaryResponse
|
||||
| PuzzleClearWorkProfileResponse,
|
||||
): PlatformPuzzleClearGalleryCard {
|
||||
const summary = 'summary' in work ? work.summary : work;
|
||||
return {
|
||||
sourceType: 'puzzle-clear',
|
||||
workId: summary.workId,
|
||||
profileId: summary.profileId,
|
||||
sourceSessionId:
|
||||
'sourceSessionId' in summary ? (summary.sourceSessionId ?? null) : null,
|
||||
publicWorkCode:
|
||||
'publicWorkCode' in summary &&
|
||||
typeof summary.publicWorkCode === 'string' &&
|
||||
summary.publicWorkCode.trim()
|
||||
? summary.publicWorkCode
|
||||
: buildPuzzleClearPublicWorkCode(summary.profileId),
|
||||
ownerUserId: summary.ownerUserId,
|
||||
authorDisplayName:
|
||||
'authorDisplayName' in summary &&
|
||||
typeof summary.authorDisplayName === 'string' &&
|
||||
summary.authorDisplayName.trim()
|
||||
? summary.authorDisplayName
|
||||
: '玩家',
|
||||
worldName: summary.workTitle.trim() || '拼消消',
|
||||
subtitle: '拼消消',
|
||||
summaryText: summary.workDescription,
|
||||
coverImageSrc: summary.coverImageSrc ?? null,
|
||||
themeTags: normalizePuzzleClearThemeTags(summary),
|
||||
playCount: summary.playCount ?? 0,
|
||||
remixCount: 0,
|
||||
likeCount: 0,
|
||||
recentPlayCount7d: getPuzzleClearRecentPlayCount(summary),
|
||||
visibility: 'published',
|
||||
publishedAt: summary.publishedAt ?? null,
|
||||
updatedAt: summary.updatedAt,
|
||||
themePrompt: summary.themePrompt,
|
||||
};
|
||||
}
|
||||
|
||||
export function mapWoodenFishWorkToPlatformGalleryCard(
|
||||
work: WoodenFishGalleryCardResponse | WoodenFishWorkProfileResponse,
|
||||
): PlatformWoodenFishGalleryCard {
|
||||
@@ -708,6 +807,10 @@ export function resolvePlatformWorldFallbackCoverImage(
|
||||
return '/creation-type-references/puzzle.webp';
|
||||
}
|
||||
|
||||
if (isPuzzleClearGalleryEntry(entry)) {
|
||||
return '/creation-type-references/puzzle.webp';
|
||||
}
|
||||
|
||||
if (isMatch3DGalleryEntry(entry)) {
|
||||
return '/creation-type-references/match3d.webp';
|
||||
}
|
||||
@@ -869,6 +972,9 @@ export function resolvePlatformWorkAuthorDisplayName(
|
||||
) {
|
||||
const displayName = authorSummary?.displayName?.trim();
|
||||
const publicUserCode = authorSummary?.publicUserCode?.trim();
|
||||
if (displayName && publicUserCode) {
|
||||
return `${displayName} · ${publicUserCode}`;
|
||||
}
|
||||
|
||||
return displayName || publicUserCode || entry.authorDisplayName.trim() || '玩家';
|
||||
}
|
||||
@@ -889,6 +995,12 @@ export function buildPlatformWorldTags(entry: PlatformWorldCardLike) {
|
||||
return entry.themeTags.length > 0 ? entry.themeTags.slice(0, 3) : ['拼图'];
|
||||
}
|
||||
|
||||
if (isPuzzleClearGalleryEntry(entry)) {
|
||||
return entry.themeTags.length > 0
|
||||
? entry.themeTags.slice(0, 3)
|
||||
: ['拼消消'];
|
||||
}
|
||||
|
||||
if (isMatch3DGalleryEntry(entry)) {
|
||||
return entry.themeTags.length > 0
|
||||
? entry.themeTags.slice(0, 3)
|
||||
@@ -1003,6 +1115,10 @@ export function resolvePlatformPublicWorkCode(
|
||||
return entry.publicWorkCode;
|
||||
}
|
||||
|
||||
if (isPuzzleClearGalleryEntry(entry)) {
|
||||
return entry.publicWorkCode;
|
||||
}
|
||||
|
||||
if (isMatch3DGalleryEntry(entry)) {
|
||||
return entry.publicWorkCode;
|
||||
}
|
||||
@@ -1079,4 +1195,4 @@ function buildBarkBattleThemeTags(work: BarkBattleWorkSummary) {
|
||||
.map((tag) => tag.trim())
|
||||
.filter(Boolean)
|
||||
.slice(0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user