Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 41 additions & 30 deletions src/pages/docs/pages/layouts.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@ src/

> **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 _/_.

## Pages
## 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 the content. 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 processed content from the incoming page will go.
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](/docs/pages/server-rendering/#layouts).

Below is an example of a _page.html_ layout:

<!-- prettier-ignore-start -->

<app-ctc-block variant="snippet">
<app-ctc-block variant="snippet" heading="src/pages/layouts/page.html">

```html
<!doctype html>
Expand Down Expand Up @@ -81,15 +83,15 @@ You can create more layouts and use them for pages with the following steps:

<!-- prettier-ignore-end -->

## App
## App Layout

To customize the outer most wrapping HTML of your layouts, create an _app.html_ file. Like a page layout, this will just be another HTML document and a `<page-outlet></page-outlet>` placeholder that can be used to position where the content from the processed page layout will appear.
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.

As with Page layouts, App layouts are just HTML:
Below is an HTML example of an app layout:

<!-- prettier-ignore-start -->

<app-ctc-block variant="snippet">
<app-ctc-block variant="snippet" heading="src/pages/layouts/app.html">

```html
<!doctype html>
Expand All @@ -114,34 +116,43 @@ As with Page layouts, App layouts are just HTML:

<!-- prettier-ignore-end -->

> When an app layout is present, Greenwood will merge the `<head>` and `<body>` tags for both app and page layouts into one HTML document structure for you.
> 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:

```js
// src/layouts/app.js
export default class AppLayout extends HTMLElement {
async connectedCallback() {
const year = new Date().getFullYear();

this.innerHTML = `
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
</head>

<body>
<h1>My App</h1>
<page-outlet></page-outlet>
<footer>&copy; ${year}</footer>
</body>
</html>
`;
<!-- prettier-ignore-start -->

<app-ctc-block variant="snippet" heading="src/pages/layouts/page.js">

```js
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>
`;
}
}
}
```
```

</app-ctc-block>

<!-- prettier-ignore-end -->

> ⚠ This layout component will _only run once at build time_. Dynamic "runtime" layouts are [planned](https://github.com/ProjectEvergreen/greenwood/issues/1248).
2 changes: 2 additions & 0 deletions src/pages/docs/pages/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ src/
index.html
```

> [SPA based projects](/docs/pages/routing/#spa) do **not** support layouts or (active) frontmatter.

## Not Found

As is a [common convention with most hosting providers](https://docs.netlify.com/routing/redirects/redirect-options/#custom-404-page-handling) and web servers, you can create a `404` page in your _pages/_ directory which will be used as the default **Not Found** page for your site.
Expand Down
20 changes: 11 additions & 9 deletions src/pages/docs/pages/server-rendering.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ This is the recommended pattern for SSR in Greenwood:

<!-- prettier-ignore-start -->

<app-ctc-block variant="snippet" heading="src/pages/api/greeting.js">
<app-ctc-block variant="snippet" heading="src/pages/user.js">

```js
import "../components/card/card.js"; // <x-card></x-card>
Expand Down Expand Up @@ -106,6 +106,8 @@ A couple of notes:
- WSCs run only on the server, thus you have full access to any APIs of the runtime, with the ability to perform one time `async` operations for [data loading](/docs/pages/server-rendering/#request-data) in `connectedCallback`.
- Keep in mind that for these "page" components, you will likely want to _avoid_ rendering into a shadow root, as then your content and styles will be encapsulated.

> You can also author [dynamic layouts](/docs/pages/layouts/#server-rendering) in this way as well!

### Body

To return just the body of the page, you can use the `getBody` API. You will get access to the [compilation](/docs/reference/appendix/#compilation), page specific data, and the incoming request.
Expand All @@ -114,7 +116,7 @@ In this example, we return a list of users from an API as HTML:

<!-- prettier-ignore-start -->

<app-ctc-block variant="snippet">
<app-ctc-block variant="snippet" heading="src/pages/my-page.js">

```js
export async function getBody(/* compilation, page, request */) {
Expand All @@ -124,11 +126,11 @@ In this example, we return a list of users from an API as HTML:
const { name, imageUrl } = user;

return `
<tr>
<td>${name}</td>
<td><img src="${imageUrl}"/></td>
</tr>
`;
<tr>
<td>${name}</td>
<td><img src="${imageUrl}"/></td>
</tr>
`;
});

return `
Expand Down Expand Up @@ -159,7 +161,7 @@ You can pull in data from Greenwood's [compilation](/docs/reference/appendix/#co

<!-- prettier-ignore-start -->

<app-ctc-block variant="snippet">
<app-ctc-block variant="snippet" heading="src/pages/my-page.js">

```js
export async function getLayout(compilation, route) {
Expand Down Expand Up @@ -200,7 +202,7 @@ Any Greenwood [supported frontmatter](/docs/resources/markdown/#frontmatter) can

<!-- prettier-ignore-start -->

<app-ctc-block variant="snippet">
<app-ctc-block variant="snippet" heading="src/pages/my-page.js">

```js
export async function getFrontmatter(compilation, route) {
Expand Down