import type { WordInfo } from '../../api/client' import { speak, speechSupported } from '../../audio/speech' // WordCard is the right-click popover for any word: its dictionary definition(s) // on top and tappable synonym pills below. Clicking a synonym replaces the word // in place. Both datasets are offline, so this opens instantly and fills in as // the (local) lookup returns. Labels are bilingual (zh-first, en subtitle) to // match the rest of Petal's chrome — the writer uses Mandarin and English. interface Props { word: string info: WordInfo | null loading: boolean // Whether the word is in the vocabulary garden (auto-saved on lookup). The // heart toggles it; `onToggleSave` removes/re-adds it. saved: boolean onToggleSave: () => void style: React.CSSProperties onReplace: (synonym: string) => void } export function WordCard({ word, info, loading, saved, onToggleSave, style, onReplace }: Props) { const definitions = info?.definitions ?? [] const synonyms = info?.synonyms ?? [] const gloss = info?.gloss ?? '' const phonetic = info?.phonetic ?? '' const empty = !loading && !gloss && definitions.length === 0 && synonyms.length === 0 return (
词语 · Word {word}
{!empty && !loading && ( )} {speechSupported() && ( )}
{/* How to say it — the pronunciation aid for an English learner, paired with the 🔊 button above. */} {phonetic && (

/{phonetic}/

)} {/* Chinese gloss first — it's what the Mandarin-speaking writer reaches for. */} {gloss && (

{gloss}

)} {loading && (
查找中… · Looking up…
)} {definitions.length > 0 && (

释义 · Definition

    {definitions.map((m, i) => (
  1. {m.part_of_speech && ( {m.part_of_speech} )} {m.definition} {m.example && ( “{m.example}” )}
  2. ))}
)} {synonyms.length > 0 && (

近义词 · Synonyms (点击替换 · tap to swap)

{synonyms.map((s) => ( ))}
)} {empty && (

没有找到这个词 · Nothing found for this word

)}
) }