Layouts

Greenwood defines two types of layouts that can be used to wrap your pages with common HTML

Greenwood will handle merging the <body> and <head> tag contents when building up your pages and layouts.

Usage

Layouts should be placed in a layouts/ directory within your workspace.

src/
  pages/
    index.html
    blog/
      first-post.md
      second-post.md
  layouts/
    app.html
    blog.html

Note: You can use either relative (../) or absolute (/) paths in your layouts since using ../ will allow for IDE autocomplete on your filesystem, but is marginally slower than using /.

Page Layout

Pages in your project will generally want a layout so you can control the output of the HTML and include all your own custom components and styles to wrap your content; think of a shared layout for all blog posts, which might be distinct from your home or docs pages. By default all pages will default to looking for a page.html in the layouts/ directory. A placeholder of <content-outlet></content-outlet> can be used to position where the content from the incoming page will go.

Dynamic layouts are also supported.

Below is an example of a page.html layout:

<!doctype html>
<html lang="en" prefix="og:http://ogp.me/ns#">
  <body>
    <header>
      <h1>Welcome to my site!</h1>
    </header>

    <content-outlet></content-outlet>
  </body>
</html>

You can create more layouts and use them for pages with the following steps:

  1. Create a new layout, e.g. layouts/blog.html

  2. In your frontmatter, specify that layout's filename

    ---
    layout: blog
    ---
    
    # My First Post
    
    Lorum Ipsum
    

Frontmatter is also supported for HTML files:

---
layout: blog
---

<html>
  <body>
    <h1>My First Post</h1>
    <p>Lorum Ipsum</p>
  </body>
<html>

App Layout

To customize the outer most wrapping HTML of all your pages, create an app.html file. This is most useful for global page elements like headers, navigation, and footers. Like a page layout, this will just be another HTML document (or JS / TS file) with a <page-outlet></page-outlet> placeholder that can be used to position where the content from the processed page layout will appear.

Below is an HTML example of an app layout:

<!doctype html>
<html lang="en" prefix="og:http://ogp.me/ns#">
  <body>
    <header>
      <h1>Welcome to My Site!</h1>
    </header>

    <section>
      <page-outlet></page-outlet>
    </section>

    <footer>
      <h4>&copy; My Site</h4>
    </footer>
  </body>
</html>

In general, you will want to start with an app layout, then create page specific layouts as needed for more specific custom layout needs.

Server Rendering

Server rendered layouts can also be authored using Web Components:

export default class PageLayout extends HTMLElement {
  constructor({ compilation, page }) {
    super();
    this.route = page.route;
    this.numPages = compilation.graph.length;
  }

  async connectedCallback() {
    this.innerHTML = `
      <html>
        <head>
          <title>My App</title>
        </head>
        <body>
          <h2>Page Layout for ${this.route}</h2>
          <span>Number of pages ${this.numPages}</span>
          <content-outlet></content-outlet>
        </body>
      </html>
    `;
  }
}

⚠ This layout component will only run once at build time. Dynamic "runtime" layouts are planned (opens in a new window).