MishkaCmsCore.Runtime.PageBuilder.Presets (Mishka CMS Core v0.0.1)

Copy Markdown View Source

What a component should look like the moment it lands on a page — this site's answer, not the kit's.

A kit ships one default per component and it is the same default for everyone. A site almost always has its own: every button here is outlined, every alert is danger, every card is large. Without somewhere to say so, that is retyped in the inspector after every single drop, and the one that gets forgotten is the one that ships.

What a preset is

Exactly the wizard's choices — %{"variant" => "outline", "size" => "large"} — kept per site and per component, and handed to MishkaCmsCore.Runtime.PageBuilder.Wizard.compose/3 when the component is placed. So a preset can only ever say things the kit already understands: an option the component does not declare is dropped by the wizard rather than written into the page as markup nothing can render.

Where it lives

In MishkaCmsCore.Settings, under builder:preset:<component>, scoped to the site. That buys the RAM cache, the per-site override, the authorization and the audit trail without a resource of its own — and a preset is exactly what settings are for: a small, site-wide preference that changes what the software does next time.

Global components are keyed by name like any other. Two sites therefore keep separate presets for the same shared component, which is the point of them.

Summary

Functions

Forgets this site's preset for a component.

Every preset for a list of palette entries, as %{name => choices} — one assign, one render.

This site's preset for a component, or %{} when it has none.

The setting key one component's preset is stored under.

Records the choices a component should start from on this site.

The HEEx to place for a component, with this site's preset applied.

Functions

clear(actor, site_id, name)

@spec clear(map(), String.t() | nil, String.t()) :: {:ok, map()} | {:error, term()}

Forgets this site's preset for a component.

for_entries(entries, site_id)

@spec for_entries([map()], String.t() | nil) :: map()

Every preset for a list of palette entries, as %{name => choices} — one assign, one render.

get(site_id, name)

@spec get(String.t() | nil, String.t()) :: map()

This site's preset for a component, or %{} when it has none.

Never raises and never returns anything but a map: a hand-edited setting holding a list, a number or malformed JSON reads as "no preset", because placing a component must not depend on a settings row being well formed.

key(name)

@spec key(String.t()) :: String.t()

The setting key one component's preset is stored under.

put(actor, site_id, name, choices)

@spec put(map(), String.t() | nil, String.t(), map()) ::
  {:ok, map()} | {:error, term()}

Records the choices a component should start from on this site.

An empty map CLEARS it rather than storing "nothing chosen" — pressing the button with everything back at its kit default plainly means "forget my default", and a stored empty map would answer every later read with a preset that does nothing.

template(entry, site_name, site_id_or_presets, components \\ [])

@spec template(map(), String.t() | nil, String.t() | nil | map(), [map()]) ::
  String.t()

The HEEx to place for a component, with this site's preset applied.

The one place that decides what a drop produces. Wizard.compose/3 is what writes the attributes, so a preset goes through the same validation an author's own wizard choice does — and a component with no preset, or one the wizard has nothing to say about, falls back to the plain template.

components is the palette, which decides whether a component calling another owns a form.