package main import ( "bytes" "log" "net/http" "os" chromahtml "github.com/alecthomas/chroma/v2/formatters/html" "github.com/alecthomas/chroma/v2/styles" "ridgwaysystems.org/website/internal/blog" "ridgwaysystems.org/website/internal/handler" ) func main() { port := getenv("PORT", "8080") contentDir := getenv("CONTENT_DIR", "content") dataDir := getenv("DATA_DIR", "data") // Generate syntax.css at startup (light + dark via media query) if err := generateSyntaxCSS("static/css/syntax.css"); err != nil { log.Printf("warning: could not generate syntax.css: %v", err) } store, err := blog.NewStore(contentDir + "/posts") if err != nil { log.Fatal("store:", err) } h := handler.New(store, dataDir) mux := http.NewServeMux() // Static files (includes robots.txt via static/robots.txt) mux.Handle("GET /static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) // robots.txt at root mux.HandleFunc("GET /robots.txt", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "static/robots.txt") }) // Public routes mux.HandleFunc("GET /{$}", h.Index) mux.HandleFunc("GET /blog", h.BlogList) mux.HandleFunc("GET /blog/feed.xml", h.Feed) mux.HandleFunc("GET /blog/{slug}", h.BlogPost) mux.HandleFunc("GET /infrastructure", h.Infrastructure) mux.HandleFunc("GET /status", h.Status) mux.HandleFunc("GET /about", h.About) mux.HandleFunc("GET /hire", h.Hire) mux.HandleFunc("POST /hire", h.HirePost) mux.HandleFunc("GET /resume", h.Resume) mux.HandleFunc("GET /sitemap.xml", h.Sitemap) // Admin routes (auth handled per-handler) mux.HandleFunc("/admin", h.AdminDashboard) mux.HandleFunc("/admin/", h.AdminRouter) srv := handler.Chain(mux, handler.LoggingMiddleware, handler.SecurityHeadersMiddleware, ) log.Printf("ridgwaysystems.org starting on :%s (DEV=%s)", port, os.Getenv("DEV")) log.Fatal(http.ListenAndServe(":"+port, srv)) } // generateSyntaxCSS writes a chroma CSS file with light and dark themes. func generateSyntaxCSS(path string) error { formatter := chromahtml.New(chromahtml.WithClasses(true)) var buf bytes.Buffer // Light theme (github) buf.WriteString("/* Auto-generated by chroma at server startup. Do not edit. */\n\n") if err := formatter.WriteCSS(&buf, styles.Get("github")); err != nil { return err } // Dark theme wrapped in prefers-color-scheme media query buf.WriteString("\n@media (prefers-color-scheme: dark) {\n") var dark bytes.Buffer if err := formatter.WriteCSS(&dark, styles.Get("github-dark")); err != nil { return err } buf.Write(dark.Bytes()) buf.WriteString("}\n") return os.WriteFile(path, buf.Bytes(), 0644) } func getenv(key, def string) string { if v := os.Getenv(key); v != "" { return v } return def }