# `MishkaCmsCore.Runtime.Authoring.PageStarter`
[🔗](https://github.com/mishka-group/mishka_cms_core/blob/v0.0.3/lib/mishka_cms_core/runtime/authoring/page_starter.ex#L5)

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.

# `structure`

```elixir
@type structure() :: %{
  id: String.t(),
  title: String.t(),
  description: String.t(),
  columns: pos_integer(),
  template: String.t()
}
```

# `all`

```elixir
@spec all() :: [structure()]
```

Every starter structure, in the order the chooser lists them.

# `blank`

```elixir
@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.

# `empty?`

```elixir
@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/0` makes, with nothing in it — which is what a page created with no
    markup arrives as, because `pages.template` is 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.

# `fetch`

```elixir
@spec fetch(String.t()) :: structure() | nil
```

One structure by id, or `nil` — an unknown id is a no-op, never a crash.

# `landing`

```elixir
@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.

# `scratch`

```elixir
@spec scratch() :: String.t()
```

The one element a page started from scratch begins with.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
