"use client"; import { useEffect, useRef, useState } from "react"; import { Check, ChevronDown, Search } from "lucide-react"; import { captionFonts, captionFont } from "@/lib/video-canvas/smart-edit/fonts"; import type { CaptionStyle } from "@/lib/video-canvas/smart-edit/contract"; const loaded = new Map>(); export function loadCaptionFont(id: string) { const font = captionFont(id); if (!font) return Promise.resolve(); if (!loaded.has(id)) { const face = new FontFace(font.family, `url(/fonts/smart-edit/${font.file})`, { weight: "400", }); loaded.set( id, face .load() .then((loadedFace) => { document.fonts.add(loadedFace); return loadedFace; }) .catch((error) => { loaded.delete(id); throw error; }), ); } return loaded.get(id)!; } export function CaptionFontPicker({ value, onChange, onError, }: { value: CaptionStyle["fontFamily"]; onChange: (id: NonNullable) => void; onError: (message: string) => void; }) { const [open, setOpen] = useState(false), [query, setQuery] = useState(""), [category, setCategory] = useState("全部"), [busy, setBusy] = useState(false); const root = useRef(null); useEffect(() => { const close = (e: globalThis.PointerEvent) => { if (!root.current?.contains(e.target as Node)) setOpen(false); }; document.addEventListener("pointerdown", close); return () => document.removeEventListener("pointerdown", close); }, []); const options = captionFonts.filter( (font) => font.name.toLowerCase().includes(query.toLowerCase()) && (category === "全部" || (category === "常用" && font.common) || (category === "推荐" && font.recommended) || (category === "Google" && font.google)), ); return (
{open && (
setQuery(e.target.value)} />
{["全部", "常用", "推荐", "Google"].map((name) => ( ))}
{options.map((font) => ( ))}
{!options.length &&
没有匹配的字体
} {busy &&
正在加载字体…
}
)}
); }