# Site (/docs/components/site)

> Spec: written ahead of the package. Not in the published packages: site, sitemap

> A Site's Pages, navigation and Brand, rendered as a folder of Page records under one Theme, with its 404, contact and terms pages.

> A Site is a website as a Thing: its Pages, navigation, and Brand, served on one or more Domains.
>
> startupbuilder.dev, [Site](https://startupbuilder.dev/business/nouns/site)

## What mdxui renders

A Site is a folder of [Page](https://next.mdxui.dev/docs/components/page) records that all name one Theme, plus a 404 record. Each worked Site below is one, rendered whole by `@mdxui/site`.

| Part | Comes from | Built by |
| --- | --- | --- |
| Every Page under the origin | One [Page](https://next.mdxui.dev/docs/components/page) record each, all naming one Theme | `renderPage` per record, or `site.ts`'s `render` under your own Theme |
| The header on every Page | One `nav` section, the same on each Page | the [`nav`](https://next.mdxui.dev/docs/sections/nav) Section type |
| The footer on every Page | One `footer` section, the same on each Page | the [`footer`](https://next.mdxui.dev/docs/sections/footer) Section type |
| A 404 page | `pages/harbor/404.json`, the `article` Template | `ship.ts`, as `dist/404.html` |
| A contact page | `pages/harbor/contact.json`, the `contact` Template | the [`cta-form`](https://next.mdxui.dev/docs/sections/cta-form) Section type, and `worker.ts` on `/contact/send` |
| A terms page | `pages/harbor/terms.json`, the `article` Template | `renderPage` |
| `sitemap.xml` and `robots.txt` | The Pages, less the 404 and any record marked `noindex` | `ship.ts`; `@mdxui/site#sitemap`, intended |
| Share images | One per Page, from its `meta.image` | `renderPage` writes the tags; the images are drawn by hand, and generated images are intended |

## How it maps

  - **Pages** (alpha): One Page record per address, `pages/<site>/<path>.json`, rendered by `renderPage`
  - **navigation** (alpha): A `nav` and a `footer` section in each record
  - **Brand** (alpha): The record's `theme`: one of five Themes, the same on every Page
  - **Domains** (host): The host serves the files; [Ship a Site](https://next.mdxui.dev/docs/start/ship) deploys them to a Worker
  - **sites/[site]/** (alpha): A folder of JSON records in place of MDX Page files
  - **layout.mdx** (gap): No shared layout: each record repeats its `nav` and `footer` sections
  - **[key]/ routes** (gap): No Collection route: each member is a record of its own
  - **not-found.mdx** (alpha): `404.json`, an `article` record, written as `404.html`
  - **Portal** (study): The signed-in part belongs to the App; see [App types](https://next.mdxui.dev/docs/app)
  - **the whole Site in one call** (spec): `site({ origin, theme, pages })`
  - **sitemap and robots** (spec): `sitemap(pages)`; [Ship a Site](https://next.mdxui.dev/docs/start/ship) writes both by hand

## Status

Every Page of a Site renders today, one `renderPage` call per record. A Site renders whole or not at all, so [Ship a Site](https://next.mdxui.dev/docs/start/ship) refuses a folder with no 404 record or with a second Theme.

**Spec · site() and sitemap().**

`site()` builds a whole Site in one call and refuses the same two cases. Neither it nor `sitemap()` is in `@mdxui/site@7.0.0-alpha.0`.

```ts title="site(), as specified"
// path → file: every Page as HTML, then 404.html, sitemap.xml and robots.txt
const files: Map<string, string> = site({ origin, theme, pages });
// theme: a bundled name or a Theme entry, the shape THEMES holds each Theme in
// pages: path → Page record; '/404' and '/terms' are required
// refused: a missing 404 or terms page, or a record under a second Theme
```

## Intended Noun

The record a Site needs, drafted where today's folder of records has a gap: one header, one footer and one logo, written once.

```yaml title="intended Noun: Site record (mdxui.dev namespace)"
noun: Site record
projects: startupbuilder.dev Site, quoted above; defines nothing new
fields:
  origin: { type: URL, required: true }
  theme: { type: Theme, required: true, note: one Theme for every Page }
  pages: { type: Page, count: 1 or more, required: true }
  header: { type: section, holds: nav, required: true, note: written once, drawn on every Page }
  footer: { type: section, holds: footer, required: true, note: written once, drawn on every Page }
  logo: { type: SVG asset path, required: false, note: drawn at the brand mark's size in the Theme's ink }
  contact: { type: URL, required: false, note: the address /contact/send forwards to }
  terms: { type: Page, template: article, required: true }
  notFound: { type: Page, template: article, required: true }
```

## Related

  - [Page](https://next.mdxui.dev/docs/components/page): One record, one address.
  - [Brand and Theme](https://next.mdxui.dev/docs/components/brand-and-theme): The one line every Page shares.
  - [Ship a Site](https://next.mdxui.dev/docs/start/ship): Every record to one served Site.

