Louise Settings
Inline editing covers text on the page. For structured, back-office work — lists you reorder, records you create, media you manage — Louise gives you Louise Settings: a SolidJS overlay summoned in edit mode and rendered over the live site under the editor theme.
As of louise@0.3.0 Louise Settings is a package-provided shell, not a pattern
you hand-assemble. You call mountSettings
with a config, and the shell renders the chrome, the fixed framework panels, and
your registered collection tabs. It pairs with the louise-toolkit/editor
handlers on the server, which back the framework panels.
Mounting
Section titled “Mounting”Louise Settings opens from the edit bar’s Settings button, which dispatches the
louise:open-settings event mountLouise fires. Mount both in your edit-mode
entry point:
import { mountLouise } from "louise-toolkit/client";import { mountSettings, OPEN_SETTINGS_EVENT } from "louise-toolkit/client/settings";import { ProductsPanel } from "./products-panel";import { InquiriesPanel } from "louise-toolkit/client/settings";
export function mountEditMode(userName: string) { mountSettings({ userName, // Bottom group — your own collections, registered as tabs. tabs: [ { id: "products", label: "Products", panel: () => <ProductsPanel /> }, { id: "inquiries", label: "Inquiries", panel: () => <InquiriesPanel /> }, ], }); mountLouise({ onOpenSettings: () => window.dispatchEvent(new CustomEvent(OPEN_SETTINGS_EVENT)), });}mountSettings injects the shared stylesheet, creates one QueryClient for every
panel, applies data-theme="louise" to its root (so the chrome never inherits
the site’s theme), and is idempotent under Astro view-transition re-runs.
Two groups
Section titled “Two groups”The layout has a first-class split, encoded in the config type so a site can’t collapse it:
- Top strip — fixed framework panels. Pages, Media, and Settings,
rendered as icon buttons. These are near-identical on every Louise site, so the
shell owns them; you don’t register or reorder them. They talk to the generic
louise-toolkit/editorendpoints (/api/louise/pages,/api/louise/media,/api/louise/settings). - Bottom tabs — your collections. Everything whose shape and display vary per
site: your bespoke record types, registered as
CollectionTabs viatabs.
Inquiries is a Louise base table, but how a submission is shown varies too
much to fix in the shell — so it ships as a registerable tab (the default
InquiriesPanel, customizable via renderRow), not a fixed framework panel. Add
it to tabs like any other collection.
Extending Settings
Section titled “Extending Settings”The Settings panel (the gear tab in the top strip) is framework-owned, but its
contents are the common base (mapped 1:1 to
siteSettingsColumns — identity, appearance, navigation,
contact, SEO) plus your additions. Declare extra fields with
settingsExtension; they render in the same panel and persist to the
site_settings.custom JSON via the settings handler’s
site-declared keys:
mountSettings({ userName, settingsExtension: [ { title: "Coffee", fields: [ { key: "roastNote", label: "Default roast note" }, { key: "showClub", label: "Show the club banner", type: "toggle" }, ], }, ], // Escape hatch for bespoke sections that self-persist (e.g. passkey enrollment). settingsExtras: () => <PasskeySection />,});Field type is one of text (default), textarea, color, toggle, image
(with a media-library picker), or links (a label/href list editor); for
anything else, give a field a render function. A key you didn’t declare is
ignored server-side — never written — because the handler’s allowlist is
authoritative.
A site whose settings don’t map to siteSettingsColumns (and keeps its own
storage + settings route) can replace the framework base groups entirely with
settingsBaseGroups — pass [] to show none, so only your settingsExtension
fields render:
mountSettings({ userName, settingsBaseGroups: [], // hide the framework base fields this site doesn't use settingsExtension: [ /* the site's own settings groups */ ],});Building a collection panel
Section titled “Building a collection panel”A CollectionTab’s panel is any Solid component. Reuse the Louise Settings
data layer and the shared field
primitives so your panels match the framework ones:
import { useQuery } from "@tanstack/solid-query";import { apiGet, louiseQueryKey, Section } from "louise-toolkit/client/settings";import { Icon, RichText } from "louise-toolkit/client";
function ProductsPanel() { const query = useQuery(() => ({ queryKey: louiseQueryKey("products"), queryFn: () => apiGet<{ products: Product[] }>("/api/louise/products"), })); // …render your list, reusing Icon / RichText / Section / the louise-* classes.}Icon renders the same Phosphor set as the toolbar, and RichText is the exact
editor inline fields use — so a Settings form and an inline field edit prose
identically. See the client reference for the full
export list.
Built-in pages
Section titled “Built-in pages”If your site has code-defined routes (Home, About…) that aren’t pages rows but
belong in the Pages panel list, pass them as builtInPages — each gets an
“Edit on page” deep link into inline edit mode:
mountSettings({ userName, builtInPages: [ { key: "home", title: "Home", path: "/" }, { key: "about", title: "About", path: "/about" }, ],});