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

Copy Markdown View Source

The Studio's snippet list, over MishkaCmsCore.Runtime.Snippet.

What the panel needs beyond the stored row — how many blocks a snippet holds, how big it is, what colour its swatch is — is DERIVED from the markup here rather than stored beside it, so a snippet can never claim three blocks while holding one.

Saving takes a serialised subtree. MishkaCmsCore.Runtime.PageBuilder.EditorSession already knows how to cut one out (Tree.subtree/2 + Serializer.to_heex/1) for the clipboard; a snippet is that same string kept past the session.

Summary

Functions

Deletes one snippet by id, as actor.

The snippets one editor should offer: this site's plus the global ones, for this section, filtered by the Studio's chip. Read as opts[:actor], who sees only the sections whose builder they may open.

One stored snippet as the panel draws it.

Saves source under name, as opts[:actor].

The editor sections a snippet can belong to.

One snippet's markup, or nil — what the insert path needs and nothing more.

Functions

delete(id, actor)

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

Deletes one snippet by id, as actor.

A site user may delete only its own site's snippets: not a global one, and not another site's. The id alone is not authority, because it travels in a phx-value-id that anyone can type — a snippet the actor cannot read is {:error, :not_found}, whether it is gone or someone else's.

list(opts)

@spec list(map()) :: [map()]

The snippets one editor should offer: this site's plus the global ones, for this section, filtered by the Studio's chip. Read as opts[:actor], who sees only the sections whose builder they may open.

filter is "all", "page" or "global" — the chips as they are written in the panel.

row(snippet)

@spec row(struct()) :: map()

One stored snippet as the panel draws it.

Public because the Studio's list is a Gervaz table now: the table hands its template Ash records, and every value the row shows beyond name is read off source rather than stored beside it. One derivation site, whether the caller came through list/1 or through the table.

save(opts)

@spec save(map()) :: {:ok, map()} | {:error, term()}

Saves source under name, as opts[:actor].

Refuses markup that does not parse: a snippet that cannot be inserted is worse than no snippet, because the failure surfaces later and somewhere else. A master names the site (nil offers it to every site); a site user saves into their own site.

sections()

@spec sections() :: [atom()]

The editor sections a snippet can belong to.

source(id, actor)

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

One snippet's markup, or nil — what the insert path needs and nothing more.

Read as actor: a site user inserts its own site's snippets and the global ones, which is what list/1 offers it. Another site's stays invisible.