Pick a layout per page in Stati 2

Layout names are looked up from the page's folder now, the same way as includes. And a typo finally gets a warning.

SNP 151 #594 Filed stati eta

yaml
---
# site/blog/hello.md
title: Hello
layout: home
---
Front matter Renders site/blog/hello.md with
layout: home site/blog/home.eta, or site/home.eta when the blog has none
layout: /home site/home.eta, whatever the blog has
layout: layouts/post the nearest layouts/post.eta, from site/blog/ up
layout: hmoe the folder's usual layout, and a warning
text
! site/blog/hello.md: front matter layout "hmoe" names no template; using site/blog/layout.eta. Did you mean "home"?

It's the lookup stati.include() uses, which changes one thing for a Stati 1 site: on a page in a folder with its own layout.eta, layout: layout now means that one. Write layout: /layout for the root one.

Without a layout, nothing changed. Stati takes the nearest layout.eta from the page's folder up, and for index pages an index.eta first. A folder's layout still replaces the one above it, but it doesn't have to be a whole document anymore. It names a shell with stati.layout(), and the shell prints it as stati.body:

eta
<% /* site/blog/layout.eta */ %>
<% stati.layout('base', { bodyClass: 'post' }) %>
<main><%~ stati.content %></main>
eta
<% /* site/base.eta */ %>
<!DOCTYPE html>
<html lang="en">
  <head><title><%= stati.page.title %></title></head>
  <body class="<%= stati.propValue('site', stati.props?.bodyClass) %>">
    <%~ stati.include('partials/header') %>
    <%~ stati.body %>
  </body>
</html>

The shell gets the props as stati.props. Discovery only ever picks layout.eta and index.eta, so base.eta never turns into a page's layout by accident, and each template calls stati.layout() once at most.

In the Stati docs: Template resolution order, Sharing a shell and Check front matter layout values.