91 lines
2.8 KiB
TypeScript
91 lines
2.8 KiB
TypeScript
import { useState } from 'react';
|
|
import type { FormEvent } from 'react';
|
|
import { CloudHeader } from '../components/CloudHeader';
|
|
import { FloatingSearchDock } from '../components/FloatingSearchDock';
|
|
import { WordCloudCanvas } from '../components/WordCloudCanvas';
|
|
import { CloudLoadingState } from '../components/CloudLoadingState';
|
|
import { CloudUnavailableState } from '../components/CloudUnavailableState';
|
|
import { TitleFrost } from '../components/TitleFrost';
|
|
import { useCloud } from '../hooks/useCloud';
|
|
import { useWordCloudFocus } from '../hooks/useWordCloudFocus';
|
|
import styles from './PersonalSearchPage.module.css';
|
|
|
|
interface PersonalSearchPageProps {
|
|
productId: string;
|
|
}
|
|
|
|
export function PersonalSearchPage({ productId }: PersonalSearchPageProps) {
|
|
const cloudState = useCloud(productId);
|
|
const cloud = cloudState.cloud;
|
|
const [query, setQuery] = useState('');
|
|
const [hasNotFound, setHasNotFound] = useState(false);
|
|
const focus = useWordCloudFocus({ words: cloud?.words ?? [] });
|
|
|
|
if (cloudState.status === 'loading') {
|
|
return <CloudLoadingState />;
|
|
}
|
|
|
|
if (!cloud) {
|
|
return <CloudUnavailableState />;
|
|
}
|
|
|
|
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
|
|
event.preventDefault();
|
|
|
|
if (!query.trim()) {
|
|
setHasNotFound(false);
|
|
return;
|
|
}
|
|
|
|
const found = focus.focusName(query);
|
|
setHasNotFound(!found);
|
|
};
|
|
|
|
const handleReset = () => {
|
|
focus.reset();
|
|
setQuery('');
|
|
setHasNotFound(false);
|
|
};
|
|
|
|
return (
|
|
<main className={styles.page} data-cloud={cloud.id} 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
|
|
/>
|
|
<FloatingSearchDock
|
|
name={query}
|
|
status={focus.searchResult ? 'found' : hasNotFound ? 'not-found' : 'idle'}
|
|
targetCount={focus.searchResult?.targets.length ?? 0}
|
|
selectedTargetIndex={focus.searchResult?.selectedTargetIndex ?? 0}
|
|
onChange={(name) => {
|
|
setQuery(name);
|
|
setHasNotFound(false);
|
|
}}
|
|
onSubmit={handleSubmit}
|
|
onReset={handleReset}
|
|
onSelectTarget={focus.selectTarget}
|
|
/>
|
|
</main>
|
|
);
|
|
}
|