From 8db3bead13441a5882d8689dfc6a9f09c82375d9 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 25 Mar 2026 16:47:22 +0100 Subject: feat: masks, properties refactor, shaders, storage migrations, and more --- apps/web/src/components/ui/font-picker.tsx | 107 ++++++++--------------------- 1 file changed, 28 insertions(+), 79 deletions(-) (limited to 'apps/web/src/components/ui/font-picker.tsx') diff --git a/apps/web/src/components/ui/font-picker.tsx b/apps/web/src/components/ui/font-picker.tsx index 09ba0a9a..77d8ab7f 100644 --- a/apps/web/src/components/ui/font-picker.tsx +++ b/apps/web/src/components/ui/font-picker.tsx @@ -1,13 +1,6 @@ "use client"; -import { - useState, - useMemo, - useRef, - useEffect, - useCallback, - type CSSProperties, -} from "react"; +import { useState, useMemo, useRef, useEffect, useCallback, type CSSProperties } from "react"; import { List, type RowComponentProps } from "react-window"; import { Popover, @@ -16,28 +9,24 @@ import { } from "@/components/ui/popover"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; -import { - getCachedFontAtlas, - loadFullFont, - prefetchFontAtlas, - clearFontAtlasCache, -} from "@/lib/fonts/google-fonts"; -import type { FontAtlas, FontAtlasEntry } from "@/types/fonts"; +import { loadFullFont } from "@/lib/fonts/google-fonts"; +import { SYSTEM_FONTS } from "@/constants/font-constants"; +import type { FontAtlas, FontAtlasEntry } from "@/lib/fonts/types"; +import { useFontAtlas } from "@/hooks/use-font-atlas"; import { cn } from "@/utils/ui"; -import { ChevronDown, Search, Upload } from "lucide-react"; +import { ChevronDown, Search } from "lucide-react"; import { HugeiconsIcon } from "@hugeicons/react"; import { TextIcon } from "@hugeicons/core-free-icons"; const FONT_TABS = [ { key: "all", label: "All fonts" }, - { key: "favorites", label: "Favorites" }, { key: "my-fonts", label: "My fonts" }, + { key: "favorites", label: "Favorites" }, ] as const; type FontTab = (typeof FONT_TABS)[number]["key"]; const ROW_HEIGHT = 40; -const SPRITE_ROW_HEIGHT = 40; const PREVIEW_SCALE = 0.8; const LIST_WIDTH = 288; const MAX_LIST_HEIGHT = 288; @@ -57,18 +46,8 @@ export function FontPicker({ const [open, setOpen] = useState(false); const [search, setSearch] = useState(""); const [activeTab, setActiveTab] = useState("all"); - const [atlas, setAtlas] = useState(() => - getCachedFontAtlas(), - ); - const [status, setStatus] = useState<"idle" | "loading" | "error">(() => - getCachedFontAtlas() ? "idle" : "loading", - ); const searchInputRef = useRef(null); - - const fontNames = useMemo(() => { - if (!atlas) return []; - return Object.keys(atlas.fonts).sort(); - }, [atlas]); + const { atlas, status, fontNames, retry: handleRetry } = useFontAtlas({ open }); const filteredFonts = useMemo(() => { if (!search) return fontNames; @@ -83,32 +62,19 @@ export function FontPicker({ const handleSelect = useCallback( async ({ family }: { family: string }) => { - try { - await loadFullFont({ family }); - onValueChange?.(family); - } catch { - onValueChange?.(family); + if (!SYSTEM_FONTS.has(family)) { + try { + await loadFullFont({ family }); + } catch { + // ignore load failure, font will fall back to system default + } } + onValueChange?.(family); setOpen(false); }, [onValueChange], ); - // Load atlas on first open if cache is empty (fallback when prefetch hasn't completed) - useEffect(() => { - if (!open || atlas) return; - - setStatus("loading"); - prefetchFontAtlas().then((data) => { - if (data) { - setAtlas(data); - setStatus("idle"); - } else { - setStatus("error"); - } - }); - }, [open, atlas]); - useEffect(() => { if (!open) { setSearch(""); @@ -116,18 +82,8 @@ export function FontPicker({ } }, [open]); - const handleRetry = useCallback(() => { - clearFontAtlasCache(); - setStatus("loading"); - prefetchFontAtlas().then((data) => { - if (data) { - setAtlas(data); - setStatus("idle"); - } else { - setStatus("error"); - } - }); - }, []); + const activeTabLabel = + FONT_TABS.find((t) => t.key === activeTab)?.label.toLowerCase() ?? ""; return ( @@ -164,11 +120,11 @@ export function FontPicker({ setSearch(event.target.value)} size="xs" - className="w-full pl-5 bg-transparent !border-none !shadow-none" + className="w-full pl-5 bg-transparent border-none! shadow-none!" />
@@ -225,20 +181,6 @@ export function FontPicker({ style={{ height: listHeight, width: LIST_WIDTH }} /> )} -
- -
); @@ -250,7 +192,7 @@ function FontSpritePreview({ entry }: { entry: FontAtlasEntry }) { className="shrink-0" style={{ width: entry.w, - height: SPRITE_ROW_HEIGHT, + height: ROW_HEIGHT, backgroundColor: "currentColor", WebkitMaskImage: `url(/fonts/font-chunk-${entry.ch}.avif)`, WebkitMaskPosition: `-${entry.x}px -${entry.y}px`, @@ -283,6 +225,7 @@ function FontRow({ const fontName = filteredFonts[index]; const entry = atlas.fonts[fontName]; const isSelected = fontName === selectedFont; + const isSystemFont = SYSTEM_FONTS.has(fontName); return ( ); -- cgit v1.3.1