Kontra: GOTH app (Go+templ+htmx+Tailwind tokens), markdown content, Decap admin, media shortcodes. Phase 3 build complete + verified locally.

This commit is contained in:
sam
2026-09-08 17:11:21 +10:00
commit 31e9a708cc
46 changed files with 4178 additions and 0 deletions

57
app/src/main.go Normal file
View File

@@ -0,0 +1,57 @@
// Kontra — news-opinion site. Single static binary.
// Serves markdown content as HTML per request (GOTH stack).
package main
import (
"embed"
"log"
"net/http"
"os"
)
// bundled static assets + admin UI (served under /web/)
//go:embed web
var web embed.FS
func main() {
root := os.Getenv("KONTRA_CONTENT")
if root == "" {
root = "content"
}
mediaBase := os.Getenv("KONTRA_MEDIA")
if mediaBase == "" {
mediaBase = "/media"
}
c, err := NewContent(root, mediaBase)
if err != nil {
log.Fatalf("failed to load content from %s: %v", root, err)
}
log.Printf("loaded %d articles across %d subjects", len(c.Articles), len(c.Subjects))
s := NewSite(c)
// Routes — register specific paths BEFORE the catch-all.
http.HandleFunc("/subjects/{slug}", func(w http.ResponseWriter, r *http.Request) {
s.subject(w, r, r.PathValue("slug"))
})
http.HandleFunc("/articles/{slug}", func(w http.ResponseWriter, r *http.Request) {
s.article(w, r, r.PathValue("slug"))
})
http.Handle("/web/", http.FileServerFS(web))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
s.home(w, r)
})
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
addr := ":" + port
log.Printf("Kontra listening on %s (content: %s)", addr, root)
if err := http.ListenAndServe(addr, nil); err != nil {
log.Fatalf("server error: %v", err)
}
}