astwerk

3. A layout

A real page wants <html>/<head>/ <body> and a nav — the wrong thing to repeat per page. Give the shell its own component that takes children, pages/layout.templ:

templ
package pages

// Layout is the shell every page wraps: html/head/body, the nav, and
// { children... } where the page's own content goes.
templ Layout(title string, path string, prefix string) {
	<!DOCTYPE html>
	<html lang={ lang(prefix) }>
		<head>
			<meta charset="utf-8"/>
			<meta name="viewport" content="width=device-width, initial-scale=1"/>
			<title>{ title }</title>
		</head>
		<body>
			<nav>
				<a href={ prefix + "/" }>My Site</a>
				<a href={ prefix + "/projects/" }>Projects</a>
				<a href={ prefix + "/about/" }>About</a>
			</nav>
			<main>
				{ children... }
			</main>
		</body>
	</html>
}

// lang maps the locale prefix to an html lang attribute.
func lang(prefix string) string {
	if prefix == "" {
		return "en"
	}
	return prefix[1:] // "/de" -> "de"
}

is templ's children mechanism: a caller wraps the component instead of passing content in as a parameter. Every link goes through prefix, so the same layout works in every locale. The home page now wraps it:

templ
package pages

templ Home(title string, path string, prefix string) {
	@Layout(title, path, prefix) {
		<h1>My Site</h1>
		<p>A portfolio built with astwerk.</p>
	}
}

Try it. Add a <footer> to the layout and rebuild.

What you should see

Every page gains the footer — build/index.html changes and no new files appear. The layout is the shell, shared by all pages.

How does a component receive the page's own content?

Why does the layout build every link through prefix?