package main import ( "embed" "fmt" "log" "net/http" "strconv" "strings" "git.valxntine.dev/valxntine/blog/models" "git.valxntine.dev/valxntine/blog/templates" ) //go:embed static/* var staticFS embed.FS func main() { mux := http.NewServeMux() staticHandler := http.FileServer(http.FS(staticFS)) mux.Handle("/static/", staticHandler) mux.HandleFunc("/", handleHome) mux.HandleFunc("/posts/", handlePost) mux.HandleFunc("/tags/", handleTag) handler := loggingMiddleware(mux) log.Println("Serving on :8080") log.Fatal(http.ListenAndServe(":8080", handler)) } func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Printf("%s %s %s", r.Method, r.URL.Path, r.RemoteAddr) next.ServeHTTP(w, r) }) } func handleHome(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r) return } page := 1 if p := r.URL.Query().Get("page"); p != "" { if parsed, err := strconv.Atoi(p); err == nil && parsed > 0 { page = parsed } } posts := GetPaginatedPosts(page, 5) total := GetTotalPages(5) d := models.Data{ Title: "~/valxntine/blog", Subtitle: "Thoughts from the Forge", Posts: posts, CurrentPage: page, TotalPages: total, } if r.Header.Get("HX-Request") == "true" { w.Header().Set("Content-Type", "text/html") err := templates.PostList( d.Posts, d.CurrentPage, d.TotalPages, ).Render(r.Context(), w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } return } w.Header().Set("Content-Type", "text/html") err := templates.HomePage(d).Render(r.Context(), w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func handlePost(w http.ResponseWriter, r *http.Request) { slug := strings.TrimPrefix(r.URL.Path, "/posts/") if slug == "" { http.NotFound(w, r) return } post := GetPostBySlug(slug) if post == nil { http.NotFound(w, r) return } if r.Header.Get("HX-Request") == "true" { w.Header().Set("Content-Type", "text/html") err := templates.PostDetail(*post).Render(r.Context(), w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } return } w.Header().Set("Content-Type", "text/html") err := templates.PostPageFull(*post).Render(r.Context(), w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func handleTag(w http.ResponseWriter, r *http.Request) { tag := strings.TrimPrefix(r.URL.Path, "/tags/") if tag == "" { http.NotFound(w, r) return } page := 1 if p := r.URL.Query().Get("page"); p != "" { if parsed, err := strconv.Atoi(p); err == nil && parsed > 0 { page = parsed } } posts := GetPostsByTag(tag, page, 5) total := GetTotalPagesByTag(tag, 5) d := models.Data{ Title: "~/valxntine/blog", Subtitle: fmt.Sprintf("Posts tagged with '%s'", tag), Posts: posts, CurrentPage: page, TotalPages: total, } if r.Header.Get("HX-Request") == "true" { w.Header().Set("Content-Type", "text/html") err := templates.PostList(d.Posts, d.CurrentPage, d.TotalPages).Render(r.Context(), w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } return } w.Header().Set("Content-Type", "text/html") err := templates.HomePage(d).Render(r.Context(), w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }