"use client"; import { useEffect, useMemo, useState } from "react"; import { buildWidgetQuery, parseWidgetConfig, type WidgetConfig, } from "../lib/config"; import { LayoutBoard } from "../builder/components/LayoutBoard"; import { GlobalOptions } from "./WidgetFields"; import { PresetsRow, type PresetsPayload } from "./PresetsRow"; // THE configuration surface. One component, two places: the /widget/builder // page renders it above the preview iframe, and the widget's own settings gear // renders it inside the overlay. // // There used to be two — a drag board for the builder and a narrow list form for // the gear — and the only reason for the second was that the board didn't fold. // It does now (its own @container, not viewport media queries, so it behaves the // same inside a 320px overlay as on a wide page), so the second is gone. One // surface is what makes a preset mean the same thing wherever you load it. export function WidgetMenu({ config, onChange, initialPresets, previewWidth, compact = false, }: { config: WidgetConfig; onChange: (patch: Partial) => void; // SSR seed for the preset row (builder page only). initialPresets?: PresetsPayload; // The width the widget will render at, for the board's track readouts. The // builder passes its preview size; inside the widget we measure the widget. previewWidth?: number; // Inside the widget's own overlay: no fieldset chrome, tighter gaps. compact?: boolean; }) { const query = useMemo(() => buildWidgetQuery(config), [config]); const [selfWidth, setSelfWidth] = useState(undefined); // In the gear the widget IS the preview, so the honest width is its own. // Measured after mount; the overlay only ever renders client-side. useEffect(() => { if (!compact || previewWidth !== undefined) return; const measure = () => setSelfWidth(window.innerWidth); measure(); window.addEventListener("resize", measure); return () => window.removeEventListener("resize", measure); }, [compact, previewWidth]); // Loading a preset REPLACES the config rather than merging into it: a preset // is a whole link, and parseWidgetConfig returns every field, so passing it as // the patch resets anything the preset didn't mention to its default. Merging // would leave whatever you had switched on stuck on. function loadPreset(presetQuery: string) { const params = Object.fromEntries(new URLSearchParams(presetQuery)); onChange(parseWidgetConfig(params)); } return (
{compact ? (
Whole widget
) : (
Whole widget
)}
); }