1
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import {
|
||||
ArrowLeft,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Clock3,
|
||||
Copy,
|
||||
Gamepad2,
|
||||
@@ -8,7 +10,7 @@ import {
|
||||
Play,
|
||||
Share2,
|
||||
} from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { buildPublicWorkDetailUrl } from '../../routing/appPageRoutes';
|
||||
import { copyTextToClipboard } from '../../services/clipboard';
|
||||
@@ -20,7 +22,7 @@ import {
|
||||
formatPlatformWorldTime,
|
||||
type PlatformPublicGalleryCard,
|
||||
resolvePlatformPublicWorkCode,
|
||||
resolvePlatformWorldCoverImage,
|
||||
resolvePlatformWorldCoverSlides,
|
||||
resolvePlatformWorldStats,
|
||||
} from '../rpg-entry/rpgEntryWorldPresentation';
|
||||
|
||||
@@ -58,6 +60,8 @@ function getAuthorAvatarLabel(authorDisplayName: string) {
|
||||
return Array.from(authorDisplayName.trim() || '作')[0] ?? '作';
|
||||
}
|
||||
|
||||
const PLATFORM_WORK_COVER_CAROUSEL_INTERVAL_MS = 4200;
|
||||
|
||||
export function PlatformWorkDetailView({
|
||||
entry,
|
||||
authorAvatarUrl,
|
||||
@@ -69,7 +73,15 @@ export function PlatformWorkDetailView({
|
||||
onStart,
|
||||
onRemix,
|
||||
}: PlatformWorkDetailViewProps) {
|
||||
const coverImage = resolvePlatformWorldCoverImage(entry);
|
||||
const coverSlides = useMemo(
|
||||
() => resolvePlatformWorldCoverSlides(entry),
|
||||
[entry],
|
||||
);
|
||||
const [activeCoverIndex, setActiveCoverIndex] = useState(0);
|
||||
const activeCoverSlide =
|
||||
coverSlides[activeCoverIndex] ?? coverSlides[0] ?? null;
|
||||
const coverImage = activeCoverSlide?.imageSrc ?? '';
|
||||
const hasCoverCarousel = coverSlides.length > 1;
|
||||
const publicWorkCode = resolvePlatformPublicWorkCode(entry);
|
||||
const normalizedAuthorAvatarUrl = authorAvatarUrl?.trim() ?? '';
|
||||
const resolvedAuthorDisplayName =
|
||||
@@ -121,6 +133,46 @@ export function PlatformWorkDetailView({
|
||||
},
|
||||
];
|
||||
|
||||
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;
|
||||
@@ -184,6 +236,46 @@ export function PlatformWorkDetailView({
|
||||
alt={entry.worldName}
|
||||
className="platform-work-detail__cover-image"
|
||||
/>
|
||||
{hasCoverCarousel ? (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
className="platform-work-detail__cover-nav platform-work-detail__cover-nav--prev"
|
||||
onClick={showPreviousCover}
|
||||
aria-label="上一张关卡图"
|
||||
title="上一张关卡图"
|
||||
>
|
||||
<ChevronLeft className="h-5 w-5" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="platform-work-detail__cover-nav platform-work-detail__cover-nav--next"
|
||||
onClick={showNextCover}
|
||||
aria-label="下一张关卡图"
|
||||
title="下一张关卡图"
|
||||
>
|
||||
<ChevronRight className="h-5 w-5" />
|
||||
</button>
|
||||
<div className="platform-work-detail__cover-dots">
|
||||
{coverSlides.map((slide, index) => (
|
||||
<button
|
||||
key={slide.id}
|
||||
type="button"
|
||||
className={`platform-work-detail__cover-dot${
|
||||
index === activeCoverIndex
|
||||
? ' platform-work-detail__cover-dot--active'
|
||||
: ''
|
||||
}`}
|
||||
onClick={() => setActiveCoverIndex(index)}
|
||||
aria-label={`查看${slide.label || `第 ${index + 1} 关`}`}
|
||||
aria-current={
|
||||
index === activeCoverIndex ? 'true' : undefined
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
<div className="platform-work-detail__cover-fallback" />
|
||||
|
||||
Reference in New Issue
Block a user