Files
kontra/app/src/main.go

62 lines
1.5 KiB
Go

// Kontra — news-opinion site. Single static binary.
// Serves markdown content as HTML per request (GOTH stack).
package main
import (
"embed"
"log"
"mime"
"net/http"
"os"
)
// bundled static assets + admin UI (served under /web/)
//go:embed web
var web embed.FS
func main() {
// Decap CMS requires config.yml served as a YAML content type (it checks the header).
_ = mime.AddExtensionType(".yml", "application/yaml")
_ = mime.AddExtensionType(".yaml", "application/yaml")
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)
}
}