- templates/layout.templ: base HTML shell per UI-SPEC §Base Layout Contract (max-w-5xl container, slate-50 header, slate-200 borders, footer copy, /static/tailwind.css in <head>, /static/htmx.min.js deferred at body end — D-10: HTMX never loaded from a CDN) - templates/index.templ: root page consuming @ui.Card and @ui.Button for the canonical HTMX demo (UI-SPEC §Component Library Contract canonical block) - templates/fragments.templ: TimeFragment renders <span> with RFC3339 UTC timestamp; templ auto-escapes interpolation (T-01-13) - internal/web/handlers.go: HealthzHandler (200 ok / 503 degraded per D-20, 2s Ping timeout), IndexHandler, DemoTimeHandler with injected clock - internal/web/router.go: Pinger interface; NewRouter wires RequestIDMiddleware → RealIP → SlogLoggerMiddleware → Recoverer (D-08 + Pitfall 6 — chi middleware.Logger deliberately NOT registered) and routes /, /healthz, /demo/time, /static/* via http.FileServer (T-01-08 path traversal blocked by http.Dir) All six handler tests + ui package tests are GREEN under default go test.
44 lines
1.5 KiB
Text
44 lines
1.5 KiB
Text
package templates
|
|
|
|
import "backend/internal/web/ui"
|
|
|
|
// Index renders the Phase 1 root page: page title, H1, muted subtitle, and
|
|
// an @ui.Card containing the canonical HTMX demo (per UI-SPEC §Component
|
|
// Library Contract / §HTMX Interaction Pattern). The demo CTA is rendered
|
|
// via @ui.Button — pages MUST NOT inline raw Tailwind classes for primitives
|
|
// that already exist in the ui package.
|
|
templ Index() {
|
|
@Layout("Xtablo — Foundation") {
|
|
<h1 class="text-[28px] font-semibold leading-tight">Xtablo</h1>
|
|
<p class="mt-2 text-base text-slate-600">
|
|
Go + HTMX foundation. Sign-in and the Tablos workflow ship in later phases.
|
|
</p>
|
|
<div class="mt-8">
|
|
@ui.Card(nil) {
|
|
<h2 class="text-xl font-semibold leading-snug">HTMX demo</h2>
|
|
<p class="mt-2 text-base text-slate-600">
|
|
Click the button to fetch the server time as an HTML fragment.
|
|
</p>
|
|
<div class="mt-4 flex items-center gap-4">
|
|
@ui.Button(ui.ButtonProps{
|
|
Label: "Fetch server time",
|
|
Variant: ui.ButtonVariantDefault,
|
|
Tone: ui.ButtonToneSolid,
|
|
Size: ui.SizeMD,
|
|
Type: "button",
|
|
Attrs: templ.Attributes{
|
|
"hx-get": "/demo/time",
|
|
"hx-target": "#demo-out",
|
|
"hx-swap": "innerHTML",
|
|
"hx-indicator": "#demo-spinner",
|
|
},
|
|
})
|
|
<span id="demo-spinner" class="htmx-indicator text-sm text-slate-600">Loading…</span>
|
|
</div>
|
|
<div id="demo-out" class="mt-4 text-base text-slate-600">
|
|
No time fetched yet.
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
}
|