docs(site-builder): add 5-article Site Builder section (Beta)
All checks were successful
Build and deploy / deploy (push) Successful in 23s

Adds /whp/site-builder/ with overview, getting-started, blocks-and-pages,
styling, and publishing. Wired as a 'Site Builder' sidebar group with a
Beta badge.

- Captured real screenshots via the demo account through a redaction
  step (server names, domain, demo-user all swapped for placeholders)
- New beta-callout partial shared across all 5 articles
- capture-site-builder.ts is local-only (uses tools/screenshots/.env
  for demo creds, never runs in CI)
This commit is contained in:
2026-05-17 18:40:47 -07:00
parent ebbb75d7f5
commit 6a0a461c26
14 changed files with 574 additions and 0 deletions

View File

@@ -45,6 +45,11 @@ export default defineConfig({
label: 'How-to guides', label: 'How-to guides',
items: [{ autogenerate: { directory: 'whp/how-to' } }], items: [{ autogenerate: { directory: 'whp/how-to' } }],
}, },
{
label: 'Site Builder',
badge: { text: 'Beta', variant: 'tip' },
items: [{ autogenerate: { directory: 'whp/site-builder' } }],
},
{ {
label: 'Reference', label: 'Reference',
items: [{ autogenerate: { directory: 'whp/reference' } }], items: [{ autogenerate: { directory: 'whp/reference' } }],

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

View File

@@ -0,0 +1,116 @@
---
title: Blocks & pages
description: The Site Builder block library, plus how to add pages and edit the shared header and footer.
sidebar:
order: 3
---
import { Aside } from '@astrojs/starlight/components';
import Beta from '~/content/partials/beta-callout.mdx';
import Support from '~/content/partials/support-link.mdx';
<Beta />
## The block library
The **Blocks** panel on the left of the editor groups every available content block into five collapsible categories. Drag any block onto the canvas to add it.
![Blocks panel showing the Sections category open](~/assets/screenshots/whp/whp-site-builder-blocks.png)
### Basic
Building-block primitives for any page:
- **Heading** — H1H6, with the size set from the inline toolbar.
- **Text** — paragraph copy. Supports bold, italic, links, and lists.
- **Button** — call-to-action with label, link, and style.
- **Logo** — drop in your site logo from Assets.
- **Menu** — the site's main navigation (most commonly placed in the Header).
- **Footer** — quick footer wrapper (or use the dedicated Footer editor; see below).
- **Divider** — horizontal rule.
- **Spacer** — adjustable vertical whitespace.
- **Icon** — pick from a built-in icon set.
- **Star Rating** — five-star widget for reviews.
- **Social Links** — links to your social profiles with icons.
- **HTML** — drop in raw HTML when nothing else fits.
### Layout
Structural blocks that hold other blocks:
- **Section** — a full-width strip of the page.
- **Container** — a centered, max-width wrapper.
- **1 / 2 / 3 / 4 / 5 / 6 Columns** — pre-set column rows.
- **Sidebar Left / Right** — content area with a sidebar.
### Sections
Pre-composed page sections — Hero, Features, CTA, Accordion, Tabs, Pricing, Gallery, Countdown, and more. Drop one in and edit the placeholder content.
### Media
Image, video, audio, and gallery blocks. Uploaded files live in the **Assets** panel and can be re-used across pages.
### Forms
Contact form, newsletter signup, and similar input blocks.
<Aside type="tip">
Selecting any block on the canvas swaps the right-hand panel from **Styles** to **Block settings**, so you can edit its content, colour, padding, and link target without leaving the editor.
</Aside>
## Editing blocks
Click a block on the canvas to select it. From there:
- **Inline toolbar** — quick text formatting (bold, italic, link, alignment).
- **Right panel** — block-specific settings (colour, padding, link, size, alt text, etc.).
- **Layers panel** (left) — see the block tree, drag to re-parent or re-order.
To delete a block, select it and press **Delete** on your keyboard, or use the trash control in the inline toolbar.
## Pages
Most templates ship as multi-page sites. Manage pages from the **Pages** tab.
![Pages panel with Edit Header / Edit Footer + page list](~/assets/screenshots/whp/whp-site-builder-pages.png)
The **PAGES** list shows every page on the site, with its path (e.g. `Home /index`). The currently-edited page is highlighted.
### Add a page
1. In the Pages tab, click **+ Add Page**.
2. Give the page a name (used in navigation) and confirm the slug (used in the URL).
3. The new page opens, empty, ready for blocks.
### Edit the shared header
The **Edit Header** button at the top of the Pages tab opens the header in isolation. Whatever you put there appears on every page. The same applies to **Edit Footer**.
This is the right place to drop your Menu, Logo, and Social Links blocks — once, instead of once per page.
### Reorder or delete pages
Click a page in the list to edit it. The menu beside the page name lets you rename, change the slug, duplicate, or delete. Deleting a page removes it from the site on the next publish.
<Aside type="caution">
Renaming a slug changes the URL. If the page is already published and indexed, set up a redirect (or hold off until you can update inbound links).
</Aside>
## Layers panel
The **Layers** tab on the left shows the block tree for the current page — useful when blocks are nested inside containers and clicking on the canvas keeps selecting the wrong level. Click any layer to select that block; drag a layer to re-parent it.
## Assets panel
The **Assets** tab is where uploaded images, videos, and other media live. Drag an image directly from this panel into an image block, or use the **Upload** button to add new files.
## Related
- [Getting started](/whp/site-builder/getting-started/)
- [Styling your site](/whp/site-builder/styling/)
- [Publishing & code injection](/whp/site-builder/publishing/)
## Still stuck?
<Support />

View File

@@ -0,0 +1,105 @@
---
title: Getting started
description: Open Site Builder, pick a template or start from scratch, make your first edits, and publish.
sidebar:
order: 2
---
import { Steps, Aside } from '@astrojs/starlight/components';
import Beta from '~/content/partials/beta-callout.mdx';
import SignIn from '~/content/partials/signing-in.mdx';
import Support from '~/content/partials/support-link.mdx';
<Beta />
## Before you start
- A **site** added in WHP that you want Site Builder to manage. Any container type works — Site Builder writes its output to the site's docroot when you publish, so a **Static HTML** site is the cleanest fit.
- About 1015 minutes for your first walkthrough.
## Sign in to WHP
<SignIn />
## Open Site Builder
<Steps>
1. In the sidebar, click **Site Builder**. You'll see a card for each site on your account.
![Site Builder landing — list of your sites](~/assets/screenshots/whp/whp-site-builder-landing.png)
2. Click **Build Site** on the site you want to edit. The visual editor opens.
</Steps>
## Pick a template (or start blank)
The editor opens onto an empty canvas, but the fastest way to get a real-looking site is to start from one of the 16 included templates.
<Steps>
1. Click **Templates** in the top bar.
![Templates picker](~/assets/screenshots/whp/whp-site-builder-templates.png)
2. Browse the categories: **Business**, **Creative**, **Personal**, **Community**, or **All**. Each card shows the template name, a tag (Business / Creative / etc.), a short description, and the page count.
3. Click a template to preview and apply. Most templates ship as multi-page sites with their own header, footer, and a few sample pages so you can see structure right away.
</Steps>
<Aside type="tip">
Applying a template replaces the current site contents. If you've already made edits, save first (or duplicate the site) so you can roll back.
</Aside>
If you'd rather start from scratch, skip Templates — the empty canvas with just a Header placeholder is the right starting point.
## Make your first edit
The editor has three panels:
- **Left:** the **Blocks** panel (also **Pages**, **Layers**, **Assets**).
- **Centre:** the canvas — what your visitors will see.
- **Right:** the **Styles** panel.
<Steps>
1. From the **Blocks** panel, drag a **Heading** block onto the canvas.
2. Click the heading on the canvas. An inline toolbar appears; type to replace the text.
3. Drag a **Text** block underneath and add a sentence or two.
4. Drag a **Button** block next. Click it, set its label and link in the right-side panel.
</Steps>
You've built your first page. The header at the top is the **shared header** — every page on the site uses it.
## Preview the result
The top bar has three device toggles next to the site name: **desktop**, **tablet**, **mobile**. Click each to see how your page looks at that width. The **Preview** button opens a full-window preview without the editor chrome.
## Save vs. publish
Two distinct actions:
- **Save** stores a draft. Your changes are kept on the server but the live site is unchanged.
- **Publish** writes the rendered HTML and assets to the site's docroot. Your visitors see the new version on the next request.
<Aside type="tip">
Save often as you work — every Save is a checkpoint. Publish only when you're happy with what you've built.
</Aside>
## Get back to the Site Builder list
Click **Back to Panel** in the top-left of the editor. You can come back any time and continue from where you left off.
## What's next
- **[Blocks & pages](/whp/site-builder/blocks-and-pages/)** — the rest of the block library, and how to add more pages.
- **[Styling your site](/whp/site-builder/styling/)** — set your colours and fonts in one place.
- **[Publishing & code injection](/whp/site-builder/publishing/)** — add analytics, custom fonts, or global CSS.
## Still stuck?
<Support />

View File

@@ -0,0 +1,52 @@
---
title: Site Builder overview
description: Build a website visually inside WHP — drag-and-drop blocks, ready-made templates, draft / publish workflow.
sidebar:
order: 1
badge:
text: Beta
variant: tip
---
import Beta from '~/content/partials/beta-callout.mdx';
import Support from '~/content/partials/support-link.mdx';
<Beta />
**Site Builder** is a visual editor that lives inside WHP. You don't need to know HTML or CSS to use it — drag content blocks onto a page, tweak text and colours in place, and click **Publish** when you're ready. It builds a real static website that's hosted on the WHP site you point it at, so the published output is fast and works exactly like any other site you'd host with us.
![Site Builder landing page](~/assets/screenshots/whp/whp-site-builder-landing.png)
## What you get
- **50+ drag-and-drop content blocks** across Basic, Layout, Sections, Media, and Forms categories.
- **16 ready-made templates** — restaurant, small business, SaaS landing, agency, medical/dental, portfolio, photography, content creator, event/conference, and more.
- **Multi-page sites** with a shared header and footer that update everywhere at once.
- **Image and video uploads** managed in the **Assets** panel.
- **Mobile-responsive preview** — desktop, tablet, and mobile views from one toggle.
- **Site Design Tokens** — set your primary, secondary, and accent colours plus heading and body fonts once, and they apply across every block on the site.
- **Custom head code injection** for analytics, custom fonts, or global CSS.
- **Save drafts & publish when ready** — your edits don't go live until you click Publish.
## When Site Builder is the right tool
- You want a landing page, marketing site, or small multi-page brochure.
- You don't want to touch HTML/CSS, but you want more flexibility than a one-size template.
- You want to ship a draft to a colleague for review before it goes live.
## When it isn't
- You're running a CMS (WordPress, Drupal, etc.) — those run as regular WHP sites of their own, not inside Site Builder.
- You need server-side dynamic behaviour beyond simple forms — Site Builder produces static pages.
- You already have a build pipeline (Astro, Hugo, Next.js static export) — keep using that; just deploy the output to a regular WHP site.
## In this section
- **[Getting started](/whp/site-builder/getting-started/)** — open the editor, pick a template or start blank, make your first edit, save and publish.
- **[Blocks & pages](/whp/site-builder/blocks-and-pages/)** — the block library, adding pages, editing the shared header and footer.
- **[Styling your site](/whp/site-builder/styling/)** — Site Design Tokens, fonts, advanced styling controls.
- **[Publishing & code injection](/whp/site-builder/publishing/)** — drafts vs. publish, the device previews, adding custom `<head>` code.
## Still stuck?
<Support />

View File

@@ -0,0 +1,79 @@
---
title: Publishing & code injection
description: Drafts vs. publish, device previews, and adding analytics, custom fonts, or global CSS via the custom head code panel.
sidebar:
order: 5
---
import { Aside } from '@astrojs/starlight/components';
import Beta from '~/content/partials/beta-callout.mdx';
import Support from '~/content/partials/support-link.mdx';
<Beta />
## Drafts vs. publish
Site Builder separates "save my edits" from "make these edits live."
- **Save** stores your edits as a draft on the server. You can close the editor and come back; your work is preserved. The live site doesn't change.
- **Publish** renders the site, writes the resulting HTML and assets to the site's docroot, and serves it to visitors on the next request.
The two buttons are in the top right of the editor.
<Aside type="tip">
Treat **Save** as your "ctrl-S" and **Publish** as your release button. Save liberally; publish when you're ready.
</Aside>
## Preview before publishing
Two previews are available, both without affecting the live site:
- **Inline preview** — the desktop/tablet/mobile toggle on the top bar swaps the canvas viewport so you can see how the page reflows.
- **Full-window preview** — click **Preview** at the top to see your draft rendered without the editor chrome. Use this to read the page like a visitor.
If you want to share a preview with someone outside your account, save the draft, then publish to a staging site (a separate WHP site you keep around for review).
## Custom head code
The **Code** button at the top of the editor opens a modal where you can paste content into the `<head>` of every page on the site.
![Custom head code editor](~/assets/screenshots/whp/whp-site-builder-code.png)
Common uses:
- **Google Analytics, Plausible, Fathom, or other analytics** — paste the tracking snippet they give you.
- **Custom fonts** — `<link>` tags pointing at Google Fonts, Fontsource, or your own hosted font.
- **Global CSS overrides** — inline `<style>` blocks for tweaks the Styles panel can't reach.
- **Verification tags** — `<meta>` tags for Google Search Console, Bing Webmaster, etc.
Click **Done** to close the modal. The code is injected on the next publish.
<Aside type="caution">
Whatever you paste here runs on every page. Test analytics in your browser's dev tools before publishing widely, and keep any inline `<script>` content small — slow scripts make every page slower.
</Aside>
## Undo / redo
The two arrows in the top toolbar (left of **Templates**) walk your edit history backwards and forwards. They cover the current editing session — once you close the editor and come back, the undo stack resets.
## Reverting a published version
Site Builder writes a clean copy on each publish, so there's no built-in "rollback" button. If you publish a version you regret:
- Make the corrective edits and publish again — usually the fastest fix.
- For more serious mistakes, restore from a [WHP backup](/whp/how-to/backups/). The site's domain folder is included in your scheduled site backups.
## Submitting feedback
Site Builder is in beta. The top bar has a **Submit feedback** link — please use it for anything weird, missing, or broken. The team reads every report.
## Related
- [Getting started](/whp/site-builder/getting-started/)
- [Blocks & pages](/whp/site-builder/blocks-and-pages/)
- [Styling your site](/whp/site-builder/styling/)
- [Backups](/whp/how-to/backups/)
## Still stuck?
<Support />

View File

@@ -0,0 +1,71 @@
---
title: Styling your site
description: Set colours, fonts, and link styles once with Site Design Tokens; reach for Advanced when you need finer control.
sidebar:
order: 4
---
import { Aside } from '@astrojs/starlight/components';
import Beta from '~/content/partials/beta-callout.mdx';
import Support from '~/content/partials/support-link.mdx';
<Beta />
The **Styles** panel on the right side of the editor controls site-wide design. Set a colour or font here and every block that uses it updates everywhere — no need to edit each page.
![Styles panel — Site Design Tokens](~/assets/screenshots/whp/whp-site-builder-editor.png)
## Site Design Tokens (Basic)
The default **Basic** view exposes the most common controls:
- **Primary Color** — used for buttons, accents, and important highlights.
- **Secondary Color** — used for secondary buttons, hover states, and supporting accents.
- **Accent Color** — used for callouts, badges, and small decorative touches.
- **Heading Font** — applies to all heading blocks (H1H6).
- **Body Font** — applies to paragraph text and other body copy.
- **Link Color** — used for inline links inside text blocks.
Each colour has a hex input plus an eight-swatch quick-pick row (a curated palette of vibrant brand colours). Click a swatch to apply it, or paste your brand hex into the input.
<Aside type="tip">
Tokens are saved with your site, so visiting the editor again preserves your palette and fonts. Changes apply immediately on the canvas — but, like everything else in Site Builder, they go live only when you click **Publish**.
</Aside>
## Advanced
Click **Advanced** in the Site Design Tokens header to expose finer controls:
- Extended palette — backgrounds, surfaces, borders, muted text, and inversions for dark sections.
- Type scale — adjust the relative size between H1H6 and body text.
- Spacing scale — tune the default padding and margin used by sections and containers.
If you make a mess, click **Reset to Defaults** at the bottom of the panel — it restores the original token set without touching your content.
## Per-block overrides
The tokens above are the default for the whole site. When you need a single block to deviate (a one-off red CTA, for instance), select that block on the canvas; its block-settings panel on the right has its own colour controls that take precedence over the site tokens.
Use per-block overrides sparingly. The point of tokens is consistency — if you find yourself overriding the same value on every block, change the token instead.
## Picking fonts
The Heading and Body font dropdowns include a curated list of web fonts. If you need a font that isn't in the list:
1. Add a `<link>` to the font's CSS via [Custom head code](/whp/site-builder/publishing/#custom-head-code).
2. Type the font's exact family name into the font picker.
The dropdown is forgiving about custom names — anything you type will be applied as the `font-family`.
## Live preview at different widths
The desktop / tablet / mobile toggles at the top of the editor switch the canvas viewport. Layout decisions (column counts, padding, font size) often look fine at one width and break at another — switch through all three before publishing.
## Related
- [Blocks & pages](/whp/site-builder/blocks-and-pages/) — what the tokens apply to.
- [Publishing & code injection](/whp/site-builder/publishing/) — add a custom font via `<head>`.
## Still stuck?
<Support />

View File

@@ -0,0 +1,3 @@
<div class="anhh-accent-callout">
**Beta feature.** Site Builder is in active development. Some controls are still being refined and templates are being expanded. We'd love your feedback — use the **Submit feedback** link in the Site Builder header.
</div>

View File

@@ -0,0 +1,143 @@
/**
* Site Builder screenshot capture — local-only. Logs in to the demo account,
* walks through the SB landing + editor, applies the standard redaction step,
* and writes PNGs to src/assets/screenshots/whp/.
*
* Run: WHP_BASE=... WHP_USER=... WHP_PASS=... npx tsx tools/screenshots/capture-site-builder.ts
*/
import { chromium, type Page } from 'playwright';
import { mkdir } from 'node:fs/promises';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const OUT_DIR = resolve(__dirname, '../../src/assets/screenshots/whp');
function need(name: string): string {
const v = process.env[name];
if (!v) throw new Error(`missing env: ${name}`);
return v;
}
const BASE = need('WHP_BASE');
const USER = need('WHP_USER');
const PASS = need('WHP_PASS');
async function login(page: Page) {
await page.goto(`${BASE}/login.php`);
await page.fill('input[name="user"]', USER);
await page.fill('input[name="password"]', PASS);
await page.click('button[type="submit"]');
await page.waitForLoadState('networkidle');
}
/**
* Neutralise server / domain / user identifiers before snapshot.
* Same idea as run.ts redactSensitive, extended for SB's domain pill.
*/
async function redact(page: Page) {
await page.addStyleTag({
content: `
.navbar-text, .brand-full { visibility: hidden !important; }
`,
});
await page.evaluate(() => {
const swaps: [RegExp, string][] = [
[/whp\d+(-[a-z0-9]+)?\.cloud-hosting\.io/gi, '<your-server>.cloud-hosting.io'],
[/mail\d+\.cloud-hosting\.io/gi, '<your-mail-server>.cloud-hosting.io'],
[/whp-demo\.anhh\.co/gi, 'your-site.example.com'],
[/whp\d+(-[a-z0-9]+)?\b/gi, '<your-server>'],
[/WHP\d+(-[A-Z0-9]+)?\b/g, '<YOUR-SERVER>'],
[/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g, '<your-server-IP>'],
[/\/docker\/users\/[a-z0-9-]+/g, '/docker/users/<your-username>'],
[/demo-user/g, 'your-username'],
];
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
const nodes: Text[] = [];
let n: Node | null = walker.nextNode();
while (n) { nodes.push(n as Text); n = walker.nextNode(); }
for (const node of nodes) {
let v = node.nodeValue ?? '';
for (const [re, replacement] of swaps) v = v.replace(re, replacement);
if (v !== node.nodeValue) node.nodeValue = v;
}
});
}
async function shot(page: Page, id: string) {
await redact(page);
const path = resolve(OUT_DIR, `${id}.png`);
await page.screenshot({ path, fullPage: false });
console.log(`captured ${id} -> ${path}`);
}
async function findSiteId(page: Page): Promise<string | null> {
// Open SB landing, click first Build Site, scrape ?site_id=NN from URL
await page.goto(`${BASE}/index.php?page=site-builder`);
await page.waitForLoadState('networkidle');
const build = page.locator('a, button').filter({ hasText: 'Build Site' }).first();
if (await build.count() === 0) return null;
await build.click();
await page.waitForLoadState('networkidle');
const m = page.url().match(/site_id=(\d+)/);
return m ? m[1] : null;
}
async function main() {
await mkdir(OUT_DIR, { recursive: true });
const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({
ignoreHTTPSErrors: true,
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 2,
});
const page = await ctx.newPage();
try {
await login(page);
// 1) SB landing
await page.goto(`${BASE}/index.php?page=site-builder`);
await page.waitForLoadState('networkidle');
await shot(page, 'whp-site-builder-landing');
// 2) Editor — open from the landing
const siteId = await findSiteId(page);
if (!siteId) {
console.error('no site_id found; ensure the demo account has at least one site');
return;
}
await page.goto(`${BASE}/site-builder/?site_id=${siteId}`);
await page.waitForLoadState('networkidle');
await page.waitForTimeout(2500);
await shot(page, 'whp-site-builder-editor');
// 3) Pages tab
await page.locator('button:has-text("PAGES"), button:has-text("Pages")').first().click().catch(() => {});
await page.waitForTimeout(1000);
await shot(page, 'whp-site-builder-pages');
// 4) Blocks: Sections category
await page.locator('button:has-text("BLOCKS"), button:has-text("Blocks")').first().click().catch(() => {});
await page.waitForTimeout(500);
await page.locator('text=SECTIONS').first().click().catch(() => {});
await page.waitForTimeout(800);
await shot(page, 'whp-site-builder-blocks');
// 5) Templates modal
await page.locator('button:has-text("Templates")').first().click().catch(() => {});
await page.waitForTimeout(1500);
await shot(page, 'whp-site-builder-templates');
await page.keyboard.press('Escape').catch(() => {});
await page.waitForTimeout(500);
// 6) Custom head code modal
await page.locator('button:has-text("Code")').first().click().catch(() => {});
await page.waitForTimeout(1500);
await shot(page, 'whp-site-builder-code');
await page.keyboard.press('Escape').catch(() => {});
} finally {
await browser.close();
}
}
main().catch(e => { console.error(e); process.exit(1); });