import { ArrowLeft, ChevronLeft, ChevronRight, CircleHelp, Clock3, Copy, Gamepad2, GitFork, Heart, PencilLine, Play, Share2, } from 'lucide-react'; import { useEffect, useMemo, useState } from 'react'; import { buildPublicWorkDetailUrl } from '../../routing/appPageRoutes'; import { copyTextToClipboard } from '../../services/clipboard'; import { ResolvedAssetImage } from '../ResolvedAssetImage'; import { buildPlatformWorldDisplayTags, formatPlatformWorkDisplayName, formatPlatformWorkDisplayTags, formatPlatformWorldTime, type PlatformPublicGalleryCard, resolvePlatformPublicWorkCode, resolvePlatformWorldCoverSlides, resolvePlatformWorldStats, } from '../rpg-entry/rpgEntryWorldPresentation'; export interface PlatformWorkDetailViewProps { entry: PlatformPublicGalleryCard; authorAvatarUrl?: string | null; authorDisplayName?: string | null; isBusy: boolean; error: string | null; visibleCoverCount?: number; onBack: () => void; onLike: () => void; onStart: () => void; onRemix: () => void; actionMode?: 'remix' | 'edit'; } function formatCompactCount(value: number) { if (value >= 10000) { const normalized = value / 10000; return `${Number.isInteger(normalized) ? normalized.toFixed(0) : normalized.toFixed(1)}万`; } return `${value}`; } function getSourceLabel(entry: PlatformPublicGalleryCard) { if ('sourceType' in entry && entry.sourceType === 'puzzle') { return '拼图'; } if ('sourceType' in entry && entry.sourceType === 'big-fish') { return '大鱼吃小鱼'; } if ('sourceType' in entry && entry.sourceType === 'match3d') { return '抓大鹅'; } return 'RPG'; } function getAuthorAvatarLabel(authorDisplayName: string) { return Array.from(authorDisplayName.trim() || '作')[0] ?? '作'; } const PLATFORM_WORK_COVER_CAROUSEL_INTERVAL_MS = 4200; export function PlatformWorkDetailView({ entry, authorAvatarUrl, authorDisplayName, isBusy, error, visibleCoverCount = 1, onBack, onLike, onStart, onRemix, actionMode = 'remix', }: PlatformWorkDetailViewProps) { const coverSlides = useMemo( () => resolvePlatformWorldCoverSlides(entry), [entry], ); const [activeCoverIndex, setActiveCoverIndex] = useState(0); const activeCoverSlide = coverSlides[activeCoverIndex] ?? coverSlides[0] ?? null; const coverImage = activeCoverSlide?.imageSrc ?? ''; const unlockedCoverCount = Math.max(1, Math.floor(visibleCoverCount)); const isActiveCoverVisible = activeCoverIndex < unlockedCoverCount; const appIconImage = coverSlides[0]?.imageSrc ?? ''; const hasCoverCarousel = coverSlides.length > 1; const publicWorkCode = resolvePlatformPublicWorkCode(entry); const normalizedAuthorAvatarUrl = authorAvatarUrl?.trim() ?? ''; const resolvedAuthorDisplayName = authorDisplayName?.trim() || entry.authorDisplayName; const [copyState, setCopyState] = useState<'idle' | 'copied' | 'failed'>( 'idle', ); const [shareState, setShareState] = useState<'idle' | 'copied' | 'failed'>( 'idle', ); const displayName = formatPlatformWorkDisplayName(entry.worldName); const tags = useMemo( () => formatPlatformWorkDisplayTags( [getSourceLabel(entry), ...buildPlatformWorldDisplayTags(entry, 3)], 4, ), [entry], ); const stats = resolvePlatformWorldStats(entry); const workActionLabel = actionMode === 'edit' ? '作品编辑' : '作品改造'; const WorkActionIcon = actionMode === 'edit' ? PencilLine : GitFork; const statItems = [ { label: '游玩', value: formatCompactCount(stats.playCount), unit: '次', icon: Gamepad2, tone: 'play', }, { label: '改造', value: formatCompactCount(stats.remixCount), unit: '次', icon: GitFork, tone: 'remix', }, { label: '点赞', value: formatCompactCount(stats.likeCount), unit: '赞', icon: Heart, tone: 'like', }, { label: '日期', value: formatPlatformWorldTime(stats.updatedAt ?? stats.publishedAt), icon: Clock3, tone: 'time', isTime: true, }, ]; useEffect(() => { setActiveCoverIndex(0); }, [entry.profileId, coverSlides.length]); useEffect(() => { setActiveCoverIndex((current) => coverSlides.length > 0 ? Math.min(current, coverSlides.length - 1) : 0, ); }, [coverSlides.length]); useEffect(() => { if (!hasCoverCarousel) { return undefined; } const timerId = window.setInterval(() => { setActiveCoverIndex((current) => (current + 1) % coverSlides.length); }, PLATFORM_WORK_COVER_CAROUSEL_INTERVAL_MS); return () => { window.clearInterval(timerId); }; }, [coverSlides.length, hasCoverCarousel]); const showPreviousCover = () => { if (!hasCoverCarousel) { return; } setActiveCoverIndex( (current) => (current - 1 + coverSlides.length) % coverSlides.length, ); }; const showNextCover = () => { if (!hasCoverCarousel) { return; } setActiveCoverIndex((current) => (current + 1) % coverSlides.length); }; const copyPublicWorkCode = () => { if (!publicWorkCode) { return; } void copyTextToClipboard(publicWorkCode).then((copied) => { setCopyState(copied ? 'copied' : 'failed'); window.setTimeout(() => setCopyState('idle'), 1400); }); }; const sharePublicWork = () => { if (!publicWorkCode) { return; } const shareText = `邀请你来玩《${entry.worldName}》\n作品号:${publicWorkCode}\n${buildPublicWorkDetailUrl(publicWorkCode)}`; void copyTextToClipboard(shareText).then((copied) => { setShareState(copied ? 'copied' : 'failed'); window.setTimeout(() => setShareState('idle'), 1400); }); }; return (
详情
{coverImage ? ( <>
{appIconImage ? (
{displayName}
{normalizedAuthorAvatarUrl ? ( {resolvedAuthorDisplayName}
{statItems.map((item) => (
{item.label}
{item.value} {item.unit ? ( {item.unit} ) : null}
))}
{tags.map((tag) => ( {tag} ))}

{entry.summaryText}

{publicWorkCode ? ( ) : null} {shareState !== 'idle' ? (
{shareState === 'copied' ? '分享内容已复制' : '分享失败'}
) : null} {error ? (
{error}
) : null}
); }