layout.go
⎇
Raw
1// Package views renders the server-side HTML with gomponents.
2// Every function returns a g.Node. Handlers pass the result to Render.
3package views
4
5import (
6 "net/http"
7
8 "hearthforge/internal/highlight"
9
10 "hearthforge/internal/config"
11 "hearthforge/internal/db"
12 "hearthforge/internal/util"
13
14 g "maragu.dev/gomponents"
15 . "maragu.dev/gomponents/html"
16)
17
18// Page carries the data the page shell needs.
19type Page struct {
20 Title string
21 User *db.SessionUser
22 Cfg *config.Config
23}
24
25// Layout renders the full HTML document around the body nodes.
26func Layout(p Page, body ...g.Node) g.Node {
27 pageTitle := "Hearthforge"
28 if p.Title != "" {
29 pageTitle = p.Title + " — Hearthforge"
30 }
31 owner := ""
32 if p.Cfg != nil {
33 owner = p.Cfg.OwnerDisplayName
34 }
35 return HTML(Lang("en"),
36 Head(
37 Meta(Charset("UTF-8")),
38 Meta(Name("viewport"), Content("width=500")),
39 TitleEl(g.Text(pageTitle)),
40 Script(Src("/assets/theme.js")),
41 Link(Rel("icon"), Type("image/svg+xml"), Href("/assets/favicon.svg")),
42 Link(Rel("stylesheet"), Href("/assets/css/main.css")),
43 Link(Rel("stylesheet"), Href("/assets/code-theme.css?v="+highlight.CSSVersion())),
44 Script(Src("/assets/app.js"), Defer()),
45 ),
46 Body(
47 Header(Class("site-header"),
48 Nav(Class("site-nav"),
49 A(Href("/"), Class("site-logo"),
50 Img(Src("/assets/favicon.svg"), Class("logo-icon"), Alt(""), Aria("hidden", "true")),
51 Span(Class("logo-text"), g.Text("Hearthforge")),
52 ),
53 Div(Class("nav-links"),
54 g.Iff(p.User != nil, func() g.Node {
55 return g.Group{
56 A(Href("/settings"), Class("nav-user"),
57 Avatar(&p.User.ID, &p.User.AvatarVersion, 24),
58 Span(g.Text(util.DisplayName(p.User.Username, owner))),
59 ),
60 Form(Method("POST"), Action("/logout"), Class("inline-form"),
61 Button(Type("submit"), Class("btn btn-sm"), g.Text("Sign out")),
62 ),
63 }
64 }),
65 g.If(p.User == nil, g.Group{
66 A(Href("/login"), Class("btn btn-sm"), g.Text("Sign in")),
67 A(Href("/register"), Class("btn btn-sm btn-primary"), g.Text("Register")),
68 }),
69 ),
70 ),
71 ),
72 Main(Class("site-main"), g.Group(body)),
73 Footer(Class("site-footer"),
74 P(g.Text("Hearthforge — hosted by "+owner)),
75 ),
76 ),
77 )
78}
79
80// Render writes a full HTML document to the response.
81func Render(w http.ResponseWriter, status int, node g.Node) {
82 w.Header().Set("Content-Type", "text/html; charset=utf-8")
83 w.Header().Set("Cache-Control", "no-store")
84 w.WriteHeader(status)
85 _ = Doctype(node).Render(w)
86}
87