We’ll drop a font grid inside the Text tool that matches your screenshots: searchable header, (optional) “Generate” button, and the card grid with selected state. Here’s a safe, drop-in component plus a 2-line integration snippet.

1) New component: components/logo/TextFontPicker.tsx

Search input + (optional) filter/right-side button

Scrollable card grid (same look as your mock)

Uses your existing Google Fonts setup

No global style changes, no breakage

import { useMemo, useState } from "react";
import { cn } from "@/lib/utils";

// Reuse your known list (you can expand this)
const FONT_OPTIONS = [
  { label: "Inter", weight: 800 },
  { label: "Manrope", weight: 700 },
  { label: "Montserrat", weight: 700 },
  { label: "Poppins", weight: 600 },
  { label: "Roboto", weight: 700 },
  { label: "Open Sans", weight: 700 },
  { label: "Lato", weight: 700 },
  { label: "Work Sans", weight: 700 },
  { label: "Nunito", weight: 700 },
  { label: "Raleway", weight: 700 },
  { label: "Rubik", weight: 700 },
  { label: "Barlow", weight: 700 },
  { label: "Playfair Display", weight: 600 }, // serif
  // …add the rest of your 55
];

export function TextFontPicker({
  value,
  onChange,
  sampleText = "Sample Text",
  showGenerate = false,
  onGenerate,
}: {
  value?: string;
  onChange: (font: string) => void;
  sampleText?: string;
  showGenerate?: boolean;
  onGenerate?: () => void;
}) {
  const [query, setQuery] = useState("");

  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    return q
      ? FONT_OPTIONS.filter((f) => f.label.toLowerCase().includes(q))
      : FONT_OPTIONS;
  }, [query]);

  return (
    <div className="space-y-3">
      {/* Header row: search + (optional) Generate button */}
      <div className="flex items-center gap-2">
        <input
          type="text"
          placeholder="Search fonts…"
          className="w-full h-10 rounded-md border px-3 text-sm outline-none focus:ring-2 focus:ring-primary"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
        />
        {showGenerate && (
          <button
            type="button"
            onClick={onGenerate}
            className="whitespace-nowrap h-10 rounded-md bg-emerald-500 hover:bg-emerald-600 text-white px-3 text-sm"
          >
            Generate
          </button>
        )}
      </div>

      {/* Info line (optional) */}
      <div className="text-xs text-muted-foreground">
        Showing {filtered.length} of {FONT_OPTIONS.length} fonts
      </div>

      {/* Grid */}
      <div className="max-h-72 overflow-auto rounded-lg border p-2">
        <div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
          {filtered.map((f) => {
            const selected = value === f.label;
            return (
              <button
                type="button"
                key={f.label}
                onClick={() => onChange(f.label)}
                className={cn(
                  "rounded-md border p-3 text-left transition bg-background",
                  selected
                    ? "border-primary ring-1 ring-primary"
                    : "border-border hover:bg-muted"
                )}
                data-testid={`font-card-${f.label.toLowerCase().replace(/\s+/g, "-")}`}
                aria-pressed={selected}
              >
                <div className="text-xs text-muted-foreground mb-1">{f.label}</div>
                <div
                  className="text-xl leading-7"
                  style={{
                    fontFamily: `'${f.label}', system-ui, sans-serif`,
                    fontWeight: f.weight as any,
                  }}
                >
                  {sampleText}
                </div>
              </button>
            );
          })}
        </div>
      </div>

      {/* Tip */}
      <div className="text-[11px] text-muted-foreground">
        Tip: This list uses Google Fonts. Ensure these families are linked in{" "}
        <code>index.html</code> so they render correctly.
      </div>
    </div>
  );
}

2) Integrate inside your Text tool panel

Wherever your Text tool renders (the right-hand sheet/modal in your screenshot), drop this in:

import { TextFontPicker } from "@/components/logo/TextFontPicker";

// inside Text tool UI:
<label className="block text-sm font-medium mb-2">Font</label>
<TextFontPicker
  value={textStyle.fontFamily}
  onChange={(font) => setTextStyle((s) => ({ ...s, fontFamily: font }))}
  sampleText={brandName || "Sample Text"}
/>


Your existing Size / Rotation / Skew sliders sit below this block—no other changes needed.

3) Make sure the canvas & exports use it

On the SVG <text> nodes, set:

style={{ fontFamily: `'${textStyle.fontFamily}', system-ui, sans-serif` }}


Before rasterizing PNG/JPEG/PDF, wait for fonts to load (if you’re not already):

// minimal safe guard; skip if you don’t use FontFaceObserver
await (document as any)?.fonts?.ready?.catch?.(() => {});