Files
readest/apps/readest-app/src/app/reader/components/annotator/DictionarySheet.tsx
T
Huang Xin a272ba892a feat(reader): replace dictionary tabs with stacked result cards (#4071)
Redesign the dictionary lookup UI as a single scrolling list of
expandable cards — one per provider that has a result — instead of
a tab strip with one active provider at a time.

Behavior:
- All enabled dictionaries are queried in parallel; cards render in
  user-defined order. Cards whose provider returns no result, an
  unsupported format, or an error are removed entirely.
- Cards default to expanded when 3 or fewer providers have results,
  collapsed (4-line preview) otherwise. Manual taps are sticky
  across re-renders; the auto-decision is reset only when a new
  word is looked up.
- Web-search providers (Google, Urban, Merriam-Webster, custom
  templates) appear in a separate "Search the web" section as
  tappable rows. On the web build they use native target="_blank"
  anchors; on Tauri the click is routed through openUrl since
  target="_blank" doesn't open externally there.
- The header carries a back arrow (when in-content link navigation
  has pushed onto the history stack), the looked-up word, and a
  gear that deep-links to Settings → Language → Dictionaries.

Mobile / narrow viewports (<sm) get the same UX as a bottom sheet
(Dialog with snapHeight 0.75); sm+ viewports keep the anchored
popup with triangle pointer. Both share useDictionaryResults +
DictionaryResultsHeader/Body.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 04:30:30 +02:00

43 lines
925 B
TypeScript

'use client';
import React from 'react';
import Dialog from '@/components/Dialog';
import {
useDictionaryResults,
DictionaryResultsHeader,
DictionaryResultsBody,
} from './DictionaryResultsView';
interface DictionarySheetProps {
word: string;
lang?: string;
onDismiss: () => void;
onManage?: () => void;
}
const DictionarySheet: React.FC<DictionarySheetProps> = ({ word, lang, onDismiss, onManage }) => {
const state = useDictionaryResults({ word, lang });
return (
<Dialog
isOpen
snapHeight={0.75}
dismissible
header={
<DictionaryResultsHeader
currentWord={state.currentWord}
canGoBack={state.canGoBack}
goBack={state.goBack}
onManage={onManage}
/>
}
contentClassName='!px-0'
onClose={onDismiss}
>
<DictionaryResultsBody {...state} />
</Dialog>
);
};
export default DictionarySheet;