Files
wordcloud-board/src/pages/PersonalSearchPage.tsx
T
broccoli 293e346f0a
Build, Push and Deploy / build (push) Successful in 7s
Build, Push and Deploy / deploy (push) Successful in 18s
Add product source job resolver
2026-09-13 18:00:35 +08:00

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>
);
}