# Multi-page site with shared header and nav

A small business site with several pages — Home, About, Services,
Contact — that share a header and navigation. The content is mostly
static, so most pages don't need metadata. The trick is keeping the
nav and footer consistent without server-side templating.

This is the right pattern when:

- The user wants more than one page but doesn't need data-driven content
- They want a "real website" feel with a sticky nav
- Each page is mostly hand-written content

For one-page sites, see `simple-page.md`. For data-driven listings,
see `property-listings.md`.

## Strategy: shared markup as a JS snippet

There's no server-side templating, so each page contains its own copy
of the header and nav. To make this manageable, define them once as
a JS snippet in `/assets/layout.js` and call it from each page. When
you update the layout, you update one file.

## The script

```python
import requests
import time

API = "https://api.uat-beam.page"
TOKEN = "<your-token>"
H = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}

slug = "north-coast-bakery"

# 1. Create the project
requests.post(f"{API}/projects", headers=H, json={
    "slug": slug,
    "context": "A small bakery in Cornwall with several pages: home, about, what we bake, find us. Static content, no daily updates.",
})
time.sleep(2)

# 2. Brand it
requests.put(f"{API}/projects/{slug}/assets/tailwind-config.js", headers=H, json={
    "content": (
        'tailwind.config = { theme: { extend: { '
        'colors: { brand: "#3a5a40", cream: "#fbf6ec" }, '
        'fontFamily: { serif: ["Lora", "serif"] } '
        '} } }'
    ),
})

requests.put(f"{API}/projects/{slug}/assets/styles.css", headers=H, json={
    "content": "@import url('https://fonts.googleapis.com/css2?family=Lora:wght@400;500;600;700&display=swap');",
})

# 3. Define the shared header + footer as a JS snippet. Each page
# loads /assets/layout.js and calls window.beamLayout.render().
layout_js = """
window.beamLayout = {
  render() {
    const path = window.location.pathname.replace(/\\/$/, '');
    const linkClass = (href) =>
      'hover:text-cream transition' + (path === href ? ' text-cream font-bold' : ' text-white/80');

    document.body.insertAdjacentHTML('afterbegin', `
      <header class="bg-brand text-white sticky top-0 z-50">
        <div class="max-w-4xl mx-auto px-6 py-4 flex justify-between items-center">
          <a href="/" class="font-serif text-2xl font-bold hover:text-cream transition">North Coast Bakery</a>
          <nav class="flex gap-6 text-sm uppercase tracking-wider">
            <a href="/" class="${linkClass('')}">Home</a>
            <a href="/about" class="${linkClass('/about')}">About</a>
            <a href="/what-we-bake" class="${linkClass('/what-we-bake')}">What we bake</a>
            <a href="/find-us" class="${linkClass('/find-us')}">Find us</a>
          </nav>
        </div>
      </header>
    `);

    document.body.insertAdjacentHTML('beforeend', `
      <footer class="bg-brand text-white/70 py-8 px-6 text-center text-sm mt-24">
        <p class="font-serif text-lg text-white mb-1">North Coast Bakery</p>
        <p>The Square, Padstow, Cornwall PL28 8AT</p>
        <p>Open Tue–Sun, 7am – 4pm</p>
      </footer>
    `);
  }
};
window.addEventListener('DOMContentLoaded', () => window.beamLayout.render());
"""

requests.put(
    f"{API}/projects/{slug}/assets/layout.js",
    headers=H,
    json={"content": layout_js},
)

# 4. A page-builder helper that wraps the unique content in a
# consistent shell. The shell loads Tailwind, the brand config, the
# shared layout JS, and styles.css.
def page(title, body_html, page_slug=None):
    base_tag = f'  <base href="/{page_slug}/">\n' if page_slug else ''
    return f"""<!DOCTYPE html>
<html lang="en">
<head>
{base_tag}  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{title} — North Coast Bakery</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="/assets/tailwind-config.js"></script>
  <link rel="stylesheet" href="/assets/styles.css">
  <script src="/assets/layout.js" defer></script>
</head>
<body class="bg-cream text-stone-900 font-serif">
  <main class="max-w-3xl mx-auto px-6 py-16">
{body_html}
  </main>
</body>
</html>
"""

# 5. Build each page

# Home
home_html = page("Home", '''
    <h1 class="text-5xl font-bold text-brand mb-6">Real bread, by the sea.</h1>
    <p class="text-xl text-stone-700 leading-relaxed mb-8">
      A small bakery in the heart of Padstow, baking sourdough,
      pastries, and pies from local Cornish flour. Open Tuesday to
      Sunday from 7am.
    </p>
    <a href="/what-we-bake" class="inline-block bg-brand text-cream px-6 py-3 rounded font-sans text-sm uppercase tracking-wider hover:bg-opacity-90">
      See what we bake
    </a>
''')
requests.put(f"{API}/projects/{slug}/pages/_root/files/index.html", headers=H, json={"content": home_html})

# About
about_html = page("About", '''
    <h1 class="text-4xl font-bold text-brand mb-6">About us</h1>
    <p class="text-lg text-stone-700 leading-relaxed mb-4">
      We started baking in a converted fisherman's cottage in 2018.
      Two of us, one wood-fired oven, no plan beyond making bread we
      wanted to eat.
    </p>
    <p class="text-lg text-stone-700 leading-relaxed mb-4">
      Eight years later, we're still in the same cottage, still using
      the same oven. We bake six days a week, from flour milled by a
      friend twenty miles inland.
    </p>
''', page_slug="about")
# About page needs to be created first
requests.post(f"{API}/projects/{slug}/pages", headers=H, json={"slug": "about", "notes": "About us"})
time.sleep(1)
requests.put(f"{API}/projects/{slug}/pages/about/files/index.html", headers=H, json={"content": about_html})

# What we bake
bake_html = page("What we bake", '''
    <h1 class="text-4xl font-bold text-brand mb-6">What we bake</h1>
    <ul class="space-y-4 text-lg text-stone-700">
      <li><strong class="text-brand">Sourdough loaves</strong> — country, rye, seeded.</li>
      <li><strong class="text-brand">Pastries</strong> — croissants, pain au chocolat, fruit Danishes.</li>
      <li><strong class="text-brand">Pasties</strong> — beef, vegetable, smoked fish.</li>
      <li><strong class="text-brand">Cakes</strong> — Victoria sponge, lemon drizzle, seasonal fruit.</li>
    </ul>
    <p class="text-stone-500 mt-8 text-sm">
      We bake fresh every morning. When it's gone, it's gone — turn up early.
    </p>
''', page_slug="what-we-bake")
requests.post(f"{API}/projects/{slug}/pages", headers=H, json={"slug": "what-we-bake", "notes": "Bread and pastries"})
time.sleep(1)
requests.put(f"{API}/projects/{slug}/pages/what-we-bake/files/index.html", headers=H, json={"content": bake_html})

# Find us
find_html = page("Find us", '''
    <h1 class="text-4xl font-bold text-brand mb-6">Find us</h1>
    <p class="text-lg text-stone-700 mb-2">The Square, Padstow, Cornwall PL28 8AT</p>
    <p class="text-stone-600 mb-8">Open Tuesday to Sunday, 7am–4pm. Closed Monday.</p>

    <h2 class="text-2xl font-bold text-brand mb-4">Getting here</h2>
    <ul class="space-y-2 text-stone-700">
      <li><strong>By car:</strong> 5 minutes from the A389. Free parking on the harbour.</li>
      <li><strong>By bus:</strong> Western Greyhound 555 from Bodmin Parkway.</li>
      <li><strong>On foot:</strong> 2 minutes from the harbour, behind the church.</li>
    </ul>
''', page_slug="find-us")
requests.post(f"{API}/projects/{slug}/pages", headers=H, json={"slug": "find-us", "notes": "Address and directions"})
time.sleep(1)
requests.put(f"{API}/projects/{slug}/pages/find-us/files/index.html", headers=H, json={"content": find_html})

print(f"Done. Live at https://{slug}.uat-beam.page")
```

## Why a JS snippet for the layout?

The simplest alternative is to copy-paste the header and footer into
every page. That works but creates a maintenance problem — change the
nav and you have to update every file.

The JS snippet approach:

- One source of truth at `/assets/layout.js`
- Every page loads it via `<script src="/assets/layout.js" defer>`
- The script injects the header at the top of `<body>` and the footer
  at the bottom on `DOMContentLoaded`
- Updating the layout = one PUT to `/assets/layout.js`
- The current page is highlighted in the nav by reading `window.location.pathname`

The downside: if a visitor has JS disabled, they see no nav. For most
brochure sites that's fine; if you need progressive enhancement, just
duplicate the markup.

## Variations

- **Server-render the nav** by computing it at build time in your
  Python script and injecting it into each page's HTML directly.
  Slightly more work upfront, no JS dependency.
- **Use a JS framework** like Alpine.js to render the nav declaratively.
  But for a 4-page bakery site, the snippet approach is plenty.
