How a blank document begins — the few shapes offered on a page with nothing on it yet.
Why this exists
A page had to arrive with markup already in it. The "Add Page" form demanded a template before it
would save, so the only way to reach the visual editor was to first write HEEx by hand — which is
the one thing the visual editor is for not having to do. blank/0 is what a page is created with
instead: one centred container, wide enough to be a target, empty enough to be nothing.
From there the canvas offers these structures. Picking one inserts it and the author is building.
Why it is not called a layout
Runtime already has Layouts: templates that wrap a page and declare which components they use. Borrowing the word here would mean two unrelated things called the same thing in the same editor. A starter is the first thing in an empty document and is thrown away the moment it is edited; a layout outlives every page that uses it.
Why the structures are plain HTML
Same reason as the editor's blocks: a starter that reached for a kit
component would fail on an install without that kit. Every structure here is div and utility
classes, so it renders anywhere and every node inside it is an ordinary element the Inspector
already knows how to style.
These are deliberately emptier than Blocks. A block is a finished section with real copy in it; a starter is scaffolding — columns to drop things into, no words to delete first.
Summary
Functions
Every starter structure, in the order the chooser lists them.
The markup a document is created with when the author gave none.
Whether a document is empty enough to be offered a starter.
One structure by id, or nil — an unknown id is a no-op, never a crash.
The tree and the spot {parent, index} a placement is made against.
The one element a page started from scratch begins with.
Types
@type structure() :: %{ id: String.t(), title: String.t(), description: String.t(), columns: pos_integer(), template: String.t() }
Functions
@spec all() :: [structure()]
Every starter structure, in the order the chooser lists them.
@spec blank(:page | :layout) :: String.t()
The markup a document is created with when the author gave none.
One centred container — somewhere to put the first thing, and nothing else. A :layout gets the
same container with @inner_content inside it, because a layout that does not render the page it
wraps is not empty, it is broken.
@spec empty?(MishkaCmsCore.Runtime.Authoring.Tree.t() | nil) :: boolean()
Whether a document is empty enough to be offered a starter.
Two ways to be empty, and both have to count:
- nothing at all — a document whose content was removed;
- the container
blank/0makes, with nothing in it — which is what a page created with no markup arrives as, becausepages.templateis NOT NULL with a length check and a truly empty string would fail at the database. A page whose only content is the container it was born with has not been started, whatever the row says.
A page with anything else on it is a page someone is already working on, and dropping a chooser
over it would be an interruption rather than a help. That includes one empty box of any other
kind: scratch/0 is one, and it is what the author asked for when they declined the chooser.
One structure by id, or nil — an unknown id is a no-op, never a crash.
@spec landing( MishkaCmsCore.Runtime.Authoring.Tree.t(), String.t() | :root | nil, non_neg_integer() ) :: {MishkaCmsCore.Runtime.Authoring.Tree.t(), String.t() | :root | nil, non_neg_integer()}
The tree and the spot {parent, index} a placement is made against.
On a page nobody has started — the container blank/0 makes and nothing in it, see empty?/1 —
the container is taken away and the spot is the top of the document, wherever the placement was
aimed: beside the container or inside it. Anything else comes back as it is.
THE BORN CONTAINER IS A PLACEHOLDER, NOT CONTENT. It is only there because pages.template will
not store an empty string. A component dropped straight onto a page born blank landed beside it,
and the container stayed on the published page as an empty py-12 band, 96px of nothing above
the component; placed inside it, the component got a width and a padding nobody chose. A starter
and Start from scratch already replace it, so the first thing placed does the same.
@spec scratch() :: String.t()
The one element a page started from scratch begins with.