fix: 稳定推荐页拼图下一关体验

This commit is contained in:
2026-06-05 16:19:35 +08:00
parent 524ad430ab
commit d489488ca2
6 changed files with 299 additions and 34 deletions

View File

@@ -39,6 +39,7 @@ import {
type CSSProperties,
type PointerEvent,
type ReactNode,
Suspense,
useCallback,
useEffect,
useMemo,
@@ -195,6 +196,7 @@ export interface RpgEntryHomeViewProps {
recommendRuntimeContent?: ReactNode;
activeRecommendEntryKey?: string | null;
isStartingRecommendEntry?: boolean;
isRecommendRuntimeReady?: boolean;
recommendRuntimeError?: string | null;
onSelectNextRecommendEntry?: (activeEntryKey?: string | null) => void;
onSelectPreviousRecommendEntry?: (activeEntryKey?: string | null) => void;
@@ -946,6 +948,115 @@ function RecommendRuntimePreviewCard({
);
}
function RecommendRuntimeCover({
entry,
className = '',
}: {
entry: PlatformPublicGalleryCard;
className?: string;
}) {
const coverImage = resolvePlatformWorldCoverImage(entry);
const fallbackCoverImage = resolvePlatformWorldFallbackCoverImage(entry);
return (
<div
className={`platform-recommend-runtime-cover ${className}`}
aria-hidden="true"
>
{coverImage || fallbackCoverImage ? (
<PlatformWorkCoverArtwork
entry={entry}
imageSrc={coverImage}
fallbackSrc={fallbackCoverImage}
alt=""
className="absolute inset-0 h-full w-full object-cover"
/>
) : (
<div className="absolute inset-0 bg-[radial-gradient(circle_at_22%_18%,rgba(255,255,255,0.28),transparent_30%),linear-gradient(135deg,rgba(255,118,117,0.42),rgba(89,164,255,0.34))]" />
)}
<div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(0,0,0,0.05),rgba(0,0,0,0.34))]" />
</div>
);
}
function RecommendRuntimeMountedProbe({
onMounted,
}: {
onMounted: () => void;
}) {
useEffect(() => {
const animationFrameId = window.requestAnimationFrame(onMounted);
return () => window.cancelAnimationFrame(animationFrameId);
}, [onMounted]);
return null;
}
function RecommendRuntimeVisual({
entry,
runtimeContent,
isStarting,
isRuntimeReady,
}: {
entry: PlatformPublicGalleryCard;
runtimeContent?: ReactNode;
isStarting: boolean;
isRuntimeReady: boolean;
}) {
const [isRuntimeMounted, setIsRuntimeMounted] = useState(false);
const activeEntryKey = buildPublicGalleryCardKey(entry);
const previousEntryKeyRef = useRef(activeEntryKey);
useEffect(() => {
if (previousEntryKeyRef.current === activeEntryKey) {
return;
}
previousEntryKeyRef.current = activeEntryKey;
setIsRuntimeMounted((currentValue) => {
// 中文注释:拼图推荐流“下一关”会在同一个 run 内切到相似作品;
// 此时只更新作品信息和分享基准,不应重显封面造成运行态闪跳。
if (currentValue && !isStarting && isRuntimeReady) {
return currentValue;
}
return false;
});
}, [activeEntryKey, isRuntimeReady, isStarting]);
const handleRuntimeMounted = useCallback(() => {
if (!isStarting && isRuntimeReady) {
setIsRuntimeMounted(true);
}
}, [isRuntimeReady, isStarting]);
const shouldShowCover =
!runtimeContent || isStarting || !isRuntimeReady || !isRuntimeMounted;
return (
<div className="platform-recommend-runtime-visual">
{runtimeContent ? (
<Suspense fallback={null}>
<div
className="platform-recommend-runtime-viewport"
aria-hidden={shouldShowCover}
>
{runtimeContent}
</div>
<RecommendRuntimeMountedProbe
key={activeEntryKey}
onMounted={handleRuntimeMounted}
/>
</Suspense>
) : null}
<RecommendRuntimeCover
entry={entry}
className={
shouldShowCover ? '' : 'platform-recommend-runtime-cover--hidden'
}
/>
</div>
);
}
function RecommendSwipeCard({
entry,
authorAvatarUrl,
@@ -4023,6 +4134,7 @@ export function RpgEntryHomeView({
recommendRuntimeContent,
activeRecommendEntryKey = null,
isStartingRecommendEntry = false,
isRecommendRuntimeReady = false,
recommendRuntimeError = null,
onSelectNextRecommendEntry,
onSelectPreviousRecommendEntry,
@@ -5687,10 +5799,6 @@ export function RpgEntryHomeView({
{recommendRuntimeError}
</button>
</section>
) : isStartingRecommendEntry ? (
<section className="platform-recommend-runtime-panel">
<div className="platform-recommend-runtime-state">...</div>
</section>
) : activeRecommendEntry ? (
<div
ref={recommendCardStageRef}
@@ -5732,9 +5840,12 @@ export function RpgEntryHomeView({
)}
isActive
visual={
<div className="platform-recommend-runtime-viewport">
{recommendRuntimeContent}
</div>
<RecommendRuntimeVisual
entry={activeRecommendEntry}
runtimeContent={recommendRuntimeContent}
isStarting={isStartingRecommendEntry}
isRuntimeReady={isRecommendRuntimeReady}
/>
}
onDragPointerDown={beginRecommendDrag}
onDragPointerMove={moveRecommendDrag}