fix wooden fish author and title display
This commit is contained in:
@@ -187,6 +187,7 @@ const authServiceMocks = vi.hoisted(() => ({
|
||||
async (publicUserCode: string): Promise<PublicUserSummary> => ({
|
||||
id: `public-user-${publicUserCode}`,
|
||||
publicUserCode,
|
||||
username: 'author_user',
|
||||
displayName: '公开作者',
|
||||
avatarUrl: null,
|
||||
}),
|
||||
@@ -195,6 +196,7 @@ const authServiceMocks = vi.hoisted(() => ({
|
||||
async (userId: string): Promise<PublicUserSummary> => ({
|
||||
id: userId,
|
||||
publicUserCode: `code-${userId}`,
|
||||
username: 'author_user',
|
||||
displayName: '公开作者',
|
||||
avatarUrl: null,
|
||||
}),
|
||||
|
||||
@@ -328,6 +328,7 @@ const {
|
||||
async (code: string): Promise<PublicUserSummary> => ({
|
||||
id: `id-${code}`,
|
||||
publicUserCode: code,
|
||||
username: 'author_user',
|
||||
displayName: '公开作者',
|
||||
avatarUrl: null,
|
||||
}),
|
||||
@@ -336,6 +337,7 @@ const {
|
||||
async (userId: string): Promise<PublicUserSummary> => ({
|
||||
id: userId,
|
||||
publicUserCode: `code-${userId}`,
|
||||
username: 'author_user',
|
||||
displayName: '公开作者',
|
||||
avatarUrl: null,
|
||||
}),
|
||||
@@ -3285,6 +3287,7 @@ test('mobile recommend meta loads real author avatar from public user summary',
|
||||
mockGetPublicAuthUserById.mockResolvedValueOnce({
|
||||
id: 'user-2',
|
||||
publicUserCode: 'SY-00000002',
|
||||
username: 'puzzle_user',
|
||||
displayName: '拼图玩家',
|
||||
avatarUrl: 'data:image/png;base64,AUTHOR',
|
||||
});
|
||||
|
||||
@@ -611,6 +611,7 @@ function WorldCard({
|
||||
onClick,
|
||||
className,
|
||||
authorAvatarUrl,
|
||||
authorUsername,
|
||||
feedCardKey,
|
||||
enableCoverCarousel = false,
|
||||
isCoverCarouselActive = false,
|
||||
@@ -620,6 +621,7 @@ function WorldCard({
|
||||
onClick: () => void;
|
||||
className?: string;
|
||||
authorAvatarUrl?: string | null;
|
||||
authorUsername?: string | null;
|
||||
feedCardKey?: string;
|
||||
enableCoverCarousel?: boolean;
|
||||
isCoverCarouselActive?: boolean;
|
||||
@@ -653,7 +655,10 @@ function WorldCard({
|
||||
const remixCount = getPlatformWorldRemixCount(entry);
|
||||
const likeCount = getPlatformWorldLikeCount(entry);
|
||||
const typeLabel = describePublicGalleryCardKind(entry);
|
||||
const authorName = entry.authorDisplayName.trim() || '玩家';
|
||||
const authorName = resolvePublicEntryAuthorDisplayText(
|
||||
entry,
|
||||
authorUsername,
|
||||
);
|
||||
const authorAvatarLabel = getPublicAuthorAvatarLabel(authorName);
|
||||
const normalizedAuthorAvatarUrl = authorAvatarUrl?.trim() ?? '';
|
||||
const cardLabel = `${entry.worldName},${typeLabel},${formatCompactCount(playCount)}游玩,${formatCompactCount(remixCount)}改造,${formatCompactCount(likeCount)}点赞`;
|
||||
@@ -935,6 +940,7 @@ function RecommendRuntimePreviewCard({
|
||||
function RecommendSwipeCard({
|
||||
entry,
|
||||
authorAvatarUrl,
|
||||
authorUsername,
|
||||
isActive,
|
||||
visual,
|
||||
shareState,
|
||||
@@ -948,6 +954,7 @@ function RecommendSwipeCard({
|
||||
}: {
|
||||
entry: PlatformPublicGalleryCard;
|
||||
authorAvatarUrl?: string | null;
|
||||
authorUsername?: string | null;
|
||||
isActive: boolean;
|
||||
visual: ReactNode;
|
||||
shareState?: 'idle' | 'copied' | 'failed';
|
||||
@@ -972,6 +979,7 @@ function RecommendSwipeCard({
|
||||
<RecommendRuntimeMeta
|
||||
entry={entry}
|
||||
authorAvatarUrl={authorAvatarUrl}
|
||||
authorUsername={authorUsername}
|
||||
isActive={isActive}
|
||||
shareState={shareState}
|
||||
onDragPointerDown={onDragPointerDown}
|
||||
@@ -990,6 +998,7 @@ function RecommendSwipeCard({
|
||||
function RecommendRuntimeMeta({
|
||||
entry,
|
||||
authorAvatarUrl,
|
||||
authorUsername,
|
||||
onDragPointerDown,
|
||||
onDragPointerMove,
|
||||
onDragPointerUp,
|
||||
@@ -1002,6 +1011,7 @@ function RecommendRuntimeMeta({
|
||||
}: {
|
||||
entry: PlatformPublicGalleryCard;
|
||||
authorAvatarUrl?: string | null;
|
||||
authorUsername?: string | null;
|
||||
onDragPointerDown?: (event: PointerEvent<HTMLElement>) => void;
|
||||
onDragPointerMove?: (event: PointerEvent<HTMLElement>) => void;
|
||||
onDragPointerUp?: (event: PointerEvent<HTMLElement>) => void;
|
||||
@@ -1014,7 +1024,10 @@ function RecommendRuntimeMeta({
|
||||
}) {
|
||||
const likeCount = getPlatformWorldLikeCount(entry);
|
||||
const remixCount = getPlatformWorldRemixCount(entry);
|
||||
const authorName = entry.authorDisplayName.trim() || '玩家';
|
||||
const authorName = resolvePublicEntryAuthorDisplayText(
|
||||
entry,
|
||||
authorUsername,
|
||||
);
|
||||
const authorAvatarLabel = getPublicAuthorAvatarLabel(authorName);
|
||||
const normalizedAuthorAvatarUrl = authorAvatarUrl?.trim() ?? '';
|
||||
const displayName = formatPlatformWorkDisplayName(entry.worldName);
|
||||
@@ -1890,28 +1903,28 @@ async function getPublicWorkAuthorSummary(
|
||||
|
||||
function describePublicGalleryCardKind(entry: PlatformPublicGalleryCard) {
|
||||
if (isBigFishGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag('??');
|
||||
return formatPlatformWorkDisplayTag('大鱼吃小鱼');
|
||||
}
|
||||
if (isPuzzleGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag('??');
|
||||
return formatPlatformWorkDisplayTag('拼图');
|
||||
}
|
||||
if (isMatch3DGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag('??');
|
||||
return formatPlatformWorkDisplayTag('抓大鹅');
|
||||
}
|
||||
if (isSquareHoleGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag('??');
|
||||
return formatPlatformWorkDisplayTag('方洞挑战');
|
||||
}
|
||||
if (isJumpHopGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag('???');
|
||||
return formatPlatformWorkDisplayTag('跳一跳');
|
||||
}
|
||||
if (isWoodenFishGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag('???');
|
||||
return formatPlatformWorkDisplayTag('敲木鱼');
|
||||
}
|
||||
if (isVisualNovelGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag('??');
|
||||
return formatPlatformWorkDisplayTag('视觉小说');
|
||||
}
|
||||
if (isBarkBattleGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag('??');
|
||||
return formatPlatformWorkDisplayTag('汪汪声浪');
|
||||
}
|
||||
if (isEdutainmentGalleryEntry(entry)) {
|
||||
return formatPlatformWorkDisplayTag(entry.templateName);
|
||||
@@ -1922,6 +1935,17 @@ function getPublicAuthorAvatarLabel(authorDisplayName: string) {
|
||||
return Array.from(authorDisplayName.trim() || '玩')[0] ?? '玩';
|
||||
}
|
||||
|
||||
function resolvePublicEntryAuthorDisplayText(
|
||||
entry: PlatformPublicGalleryCard,
|
||||
authorUsername?: string | null,
|
||||
) {
|
||||
if (isWoodenFishGalleryEntry(entry)) {
|
||||
return authorUsername?.trim() || entry.authorDisplayName.trim() || '玩家';
|
||||
}
|
||||
|
||||
return entry.authorDisplayName.trim() || '玩家';
|
||||
}
|
||||
|
||||
function getPlatformWorldLikeCount(entry: PlatformWorldCardLike) {
|
||||
return Math.max(0, Math.round(entry.likeCount ?? 0));
|
||||
}
|
||||
@@ -4178,6 +4202,17 @@ export function RpgEntryHomeView({
|
||||
},
|
||||
[publicAuthorSummariesByKey],
|
||||
);
|
||||
const getPublicEntryAuthorUsername = useCallback(
|
||||
(entry: PlatformPublicGalleryCard) => {
|
||||
const authorLookupKey = buildPublicWorkAuthorLookupKey(entry);
|
||||
if (!authorLookupKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return publicAuthorSummariesByKey[authorLookupKey]?.username?.trim() || null;
|
||||
},
|
||||
[publicAuthorSummariesByKey],
|
||||
);
|
||||
const activeCategoryGroup =
|
||||
categoryGroups.find((group) => group.tag === selectedCategoryTag) ??
|
||||
categoryGroups[0] ??
|
||||
@@ -5523,6 +5558,9 @@ export function RpgEntryHomeView({
|
||||
authorAvatarUrl={getPublicEntryAuthorAvatarUrl(
|
||||
previousRecommendEntry,
|
||||
)}
|
||||
authorUsername={getPublicEntryAuthorUsername(
|
||||
previousRecommendEntry,
|
||||
)}
|
||||
isActive={false}
|
||||
visual={
|
||||
<RecommendRuntimePreviewCard
|
||||
@@ -5540,6 +5578,9 @@ export function RpgEntryHomeView({
|
||||
authorAvatarUrl={getPublicEntryAuthorAvatarUrl(
|
||||
activeRecommendEntry,
|
||||
)}
|
||||
authorUsername={getPublicEntryAuthorUsername(
|
||||
activeRecommendEntry,
|
||||
)}
|
||||
isActive
|
||||
visual={
|
||||
<div className="platform-recommend-runtime-viewport">
|
||||
@@ -5564,6 +5605,9 @@ export function RpgEntryHomeView({
|
||||
authorAvatarUrl={getPublicEntryAuthorAvatarUrl(
|
||||
nextRecommendEntry,
|
||||
)}
|
||||
authorUsername={getPublicEntryAuthorUsername(
|
||||
nextRecommendEntry,
|
||||
)}
|
||||
isActive={false}
|
||||
visual={
|
||||
<RecommendRuntimePreviewCard
|
||||
@@ -5717,6 +5761,7 @@ export function RpgEntryHomeView({
|
||||
onClick={() => onOpenGalleryDetail(entry)}
|
||||
className="w-full"
|
||||
authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
|
||||
authorUsername={getPublicEntryAuthorUsername(entry)}
|
||||
feedCardKey={cardKey}
|
||||
/>
|
||||
);
|
||||
@@ -5782,6 +5827,7 @@ export function RpgEntryHomeView({
|
||||
onClick={() => onOpenGalleryDetail(entry)}
|
||||
className="w-full"
|
||||
authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
|
||||
authorUsername={getPublicEntryAuthorUsername(entry)}
|
||||
feedCardKey={cardKey}
|
||||
enableCoverCarousel={mobileFeedCarouselEnabled}
|
||||
isCoverCarouselActive={
|
||||
@@ -5888,6 +5934,7 @@ export function RpgEntryHomeView({
|
||||
onClick={() => openRecommendGalleryDetail(entry)}
|
||||
className="w-full min-w-0"
|
||||
authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
|
||||
authorUsername={getPublicEntryAuthorUsername(entry)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -5915,6 +5962,7 @@ export function RpgEntryHomeView({
|
||||
onClick={() => openRecommendGalleryDetail(entry)}
|
||||
className="w-full min-w-0"
|
||||
authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
|
||||
authorUsername={getPublicEntryAuthorUsername(entry)}
|
||||
/>
|
||||
))}
|
||||
{onOpenChildMotionDemo ? (
|
||||
@@ -5975,6 +6023,7 @@ export function RpgEntryHomeView({
|
||||
onClick={() => openRecommendGalleryDetail(entry)}
|
||||
className="w-full min-w-0"
|
||||
authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
|
||||
authorUsername={getPublicEntryAuthorUsername(entry)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -6490,6 +6539,7 @@ export function RpgEntryHomeView({
|
||||
onClick={() => openRecommendGalleryDetail(entry)}
|
||||
className="w-full min-w-0"
|
||||
authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
|
||||
authorUsername={getPublicEntryAuthorUsername(entry)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -6660,6 +6710,7 @@ export function RpgEntryHomeView({
|
||||
onClick={() => openRecommendGalleryDetail(entry)}
|
||||
className="w-full min-w-0"
|
||||
authorAvatarUrl={getPublicEntryAuthorAvatarUrl(entry)}
|
||||
authorUsername={getPublicEntryAuthorUsername(entry)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -219,6 +219,7 @@ export type PlatformWoodenFishGalleryCard = {
|
||||
sourceSessionId?: string | null;
|
||||
publicWorkCode: string;
|
||||
ownerUserId: string;
|
||||
authorUsername?: string | null;
|
||||
authorDisplayName: string;
|
||||
worldName: string;
|
||||
subtitle: string;
|
||||
@@ -562,6 +563,10 @@ export function mapWoodenFishWorkToPlatformGalleryCard(
|
||||
? summary.publicWorkCode
|
||||
: buildWoodenFishPublicWorkCode(summary.profileId),
|
||||
ownerUserId: summary.ownerUserId,
|
||||
authorUsername:
|
||||
'authorUsername' in summary && typeof summary.authorUsername === 'string'
|
||||
? summary.authorUsername
|
||||
: null,
|
||||
authorDisplayName:
|
||||
'authorDisplayName' in summary ? summary.authorDisplayName : '玩家',
|
||||
worldName: summary.workTitle,
|
||||
|
||||
@@ -40,7 +40,6 @@ type WoodenFishWorkspaceFormState = {
|
||||
floatingWords: string[];
|
||||
};
|
||||
|
||||
const DEFAULT_WORK_TITLE = '今日敲木鱼';
|
||||
const DEFAULT_THEME_TAGS = ['敲木鱼', '解压'];
|
||||
const DEFAULT_FLOATING_WORDS = ['幸运'];
|
||||
const MAX_FLOATING_WORD_COUNT = 8;
|
||||
@@ -309,8 +308,9 @@ export function WoodenFishWorkspace({
|
||||
try {
|
||||
const payload: WoodenFishWorkspaceCreateRequest = {
|
||||
templateId: 'wooden-fish',
|
||||
workTitle: DEFAULT_WORK_TITLE,
|
||||
workDescription: '',
|
||||
workTitle: '',
|
||||
workDescription:
|
||||
formState.hitObjectPrompt.trim() || WOODEN_FISH_DEFAULT_HIT_OBJECT_PROMPT,
|
||||
themeTags: DEFAULT_THEME_TAGS,
|
||||
hitObjectPrompt:
|
||||
formState.hitObjectPrompt.trim() || WOODEN_FISH_DEFAULT_HIT_OBJECT_PROMPT,
|
||||
|
||||
Reference in New Issue
Block a user