89 lines
2.7 KiB
TypeScript
89 lines
2.7 KiB
TypeScript
import { useCallback, useEffect } from 'react';
|
|
import { CloudHeader } from '../components/CloudHeader';
|
|
import { FullscreenButton } from '../components/FullscreenButton';
|
|
import { QRPanel } from '../components/QRPanel';
|
|
import { WordCloudCanvas } from '../components/WordCloudCanvas';
|
|
import { CloudLoadingState } from '../components/CloudLoadingState';
|
|
import { CloudUnavailableState } from '../components/CloudUnavailableState';
|
|
import { useFocusQueue } from '../hooks/useFocusQueue';
|
|
import { useCloud } from '../hooks/useCloud';
|
|
import { useWordCloudChannel } from '../hooks/useWordCloudChannel';
|
|
import { useWordCloudFocus } from '../hooks/useWordCloudFocus';
|
|
import { TitleFrost } from '../components/TitleFrost';
|
|
import type { FocusEvent } from '../types/channel';
|
|
import styles from './PublicDisplayPage.module.css';
|
|
|
|
interface PublicDisplayPageProps {
|
|
productId: string;
|
|
}
|
|
|
|
export function PublicDisplayPage({ productId }: PublicDisplayPageProps) {
|
|
const cloudState = useCloud(productId);
|
|
const cloud = cloudState.cloud;
|
|
const queue = useFocusQueue();
|
|
const focus = useWordCloudFocus({
|
|
words: cloud?.words ?? [],
|
|
autoReturn: true,
|
|
onComplete: queue.advance,
|
|
});
|
|
|
|
const receiveMessage = useCallback(
|
|
(message: FocusEvent) => {
|
|
queue.enqueue(message);
|
|
},
|
|
[queue],
|
|
);
|
|
useWordCloudChannel(productId, receiveMessage);
|
|
|
|
useEffect(() => {
|
|
if (!queue.current || focus.phase !== 'idle' || !cloud) {
|
|
return;
|
|
}
|
|
|
|
const found = focus.focusName(queue.current.name, queue.current.targetIndex ?? 0);
|
|
|
|
if (!found) {
|
|
queue.advance();
|
|
}
|
|
}, [cloud, focus, queue]);
|
|
|
|
if (cloudState.status === 'loading') {
|
|
return <CloudLoadingState />;
|
|
}
|
|
|
|
if (!cloud) {
|
|
return <CloudUnavailableState />;
|
|
}
|
|
|
|
return (
|
|
<main className={styles.page} aria-label="大屏展示词云">
|
|
<WordCloudCanvas
|
|
words={cloud.words}
|
|
phase={focus.phase}
|
|
transform={focus.transform}
|
|
activeIds={focus.activeIds}
|
|
cloudRef={focus.cloudRef}
|
|
onPointerDown={focus.handlePointerDown}
|
|
onPointerMove={focus.handlePointerMove}
|
|
onPointerUp={focus.handlePointerUp}
|
|
onWheel={focus.handleWheel}
|
|
onKeyDown={focus.handleKeyDown}
|
|
sourceCanvas={cloud.sourceCanvas}
|
|
sourceSvg={cloud.sourceSvg}
|
|
viewport={focus.viewport}
|
|
/>
|
|
<TitleFrost />
|
|
<CloudHeader
|
|
eyebrow={cloud.eyebrow}
|
|
title={cloud.title}
|
|
subtitle={cloud.subtitle}
|
|
dimmed={focus.phase !== 'idle'}
|
|
layered
|
|
/>
|
|
<p className={styles.caption}>{cloud.caption}</p>
|
|
<QRPanel productId={productId} />
|
|
<FullscreenButton />
|
|
</main>
|
|
);
|
|
}
|