Add dedicated edition pages (server, workstation, cloud)
- Add /server, /workstation, /cloud routes with per-page SEO titles - Extract shared nav, footer, and waitlist form into partials - Nav links to edition pages with active-state highlighting; swap About/Security order - Waitlist form pre-checks the current edition and adds a Cloud option - Add page-hero variant, edition switcher, and active-nav styles - Responsive fixes: nav wraps at 540px, waitlist checkboxes wrap on narrow screens
This commit is contained in:
64
main.go
64
main.go
@@ -14,6 +14,22 @@ import (
|
||||
|
||||
var templates = make(map[string]*template.Template)
|
||||
|
||||
// pageTitles maps each edition page to its SEO title.
|
||||
var pageTitles = map[string]string{
|
||||
"server": "Arcline Server — Hardened SOC / Production Host",
|
||||
"workstation": "Arcline Workstation — Security Analyst / Blue-Team Desktop",
|
||||
"cloud": "Arcline Cloud — Security-First Cloud Images",
|
||||
}
|
||||
|
||||
// mustParse parses a template set and fails fast at startup on any error.
|
||||
func mustParse(name string, files ...string) *template.Template {
|
||||
t, err := template.ParseFiles(files...)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to parse %s template: %v", name, err)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// contextKey is used to pass per-request log extras from handlers to the logging middleware.
|
||||
type contextKey struct{}
|
||||
type logContext struct{ extra string }
|
||||
@@ -25,11 +41,23 @@ func main() {
|
||||
}
|
||||
|
||||
// Parse templates once at startup.
|
||||
index, err := template.ParseFiles("templates/base.html", "templates/index.html")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to parse index template: %v", err)
|
||||
templates["index"] = mustParse("index",
|
||||
"templates/base.html",
|
||||
"templates/index.html",
|
||||
"templates/partials/nav.html",
|
||||
"templates/partials/footer.html",
|
||||
"templates/partials/waitlist_form.html",
|
||||
)
|
||||
|
||||
for _, name := range []string{"server", "workstation", "cloud"} {
|
||||
templates[name] = mustParse(name,
|
||||
"templates/base.html",
|
||||
"templates/"+name+".html",
|
||||
"templates/partials/nav.html",
|
||||
"templates/partials/footer.html",
|
||||
"templates/partials/waitlist_form.html",
|
||||
)
|
||||
}
|
||||
templates["index"] = index
|
||||
|
||||
waitlist, err := template.ParseFiles("templates/partials/waitlist_confirmation.html")
|
||||
if err != nil {
|
||||
@@ -45,6 +73,9 @@ func main() {
|
||||
|
||||
// Page routes
|
||||
mux.HandleFunc("/", handleIndex)
|
||||
mux.HandleFunc("/server", handlePage("server"))
|
||||
mux.HandleFunc("/workstation", handlePage("workstation"))
|
||||
mux.HandleFunc("/cloud", handlePage("cloud"))
|
||||
mux.HandleFunc("/healthz", handleHealthz)
|
||||
|
||||
// HTMX partial routes
|
||||
@@ -163,7 +194,9 @@ func handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
data := map[string]interface{}{
|
||||
"Title": "Arcline OS — Hardened Linux for Security Practitioners",
|
||||
"Title": "Arcline OS — Hardened Linux for Security Practitioners",
|
||||
"Active": "",
|
||||
"Edition": "server",
|
||||
}
|
||||
if err := templates["index"].ExecuteTemplate(w, "base", data); err != nil {
|
||||
log.Printf("render error: %v", err)
|
||||
@@ -171,6 +204,27 @@ func handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// handlePage renders one of the edition pages (server, workstation, cloud).
|
||||
func handlePage(page string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/"+page {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
data := map[string]interface{}{
|
||||
"Title": pageTitles[page],
|
||||
"Active": page,
|
||||
"Edition": page,
|
||||
}
|
||||
if err := templates[page].ExecuteTemplate(w, "base", data); err != nil {
|
||||
log.Printf("render error: %v", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleWaitlist(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||
|
||||
Reference in New Issue
Block a user