A community based topic aggregation platform built on atproto
1// Package web provides HTTP handlers and templates for the Coves web interface.
2// This includes the landing page and static file serving for the coves.social website.
3package web
4
5import (
6 "embed"
7 "fmt"
8 "html/template"
9 "net/http"
10 "path/filepath"
11)
12
13//go:embed templates/*.html
14var templatesFS embed.FS
15
16// Templates holds the parsed HTML templates for the web interface.
17type Templates struct {
18 templates *template.Template
19}
20
21// NewTemplates creates a new Templates instance by parsing all embedded templates.
22func NewTemplates() (*Templates, error) {
23 tmpl, err := template.ParseFS(templatesFS, "templates/*.html")
24 if err != nil {
25 return nil, fmt.Errorf("failed to parse templates: %w", err)
26 }
27 return &Templates{templates: tmpl}, nil
28}
29
30// Render renders a named template with the provided data to the response writer.
31// Returns an error if the template doesn't exist or rendering fails.
32func (t *Templates) Render(w http.ResponseWriter, name string, data interface{}) error {
33 // Set content type before writing
34 w.Header().Set("Content-Type", "text/html; charset=utf-8")
35
36 // Check if template exists
37 tmpl := t.templates.Lookup(name)
38 if tmpl == nil {
39 return fmt.Errorf("template %q not found", name)
40 }
41
42 // Execute template
43 if err := tmpl.Execute(w, data); err != nil {
44 return fmt.Errorf("failed to execute template %q: %w", name, err)
45 }
46
47 return nil
48}
49
50// ProjectStaticFileServer returns an http.Handler that serves static files from the project root.
51// This is used for files that live outside the web package (e.g., /static/images/).
52func ProjectStaticFileServer(staticDir string) http.Handler {
53 absPath, err := filepath.Abs(staticDir)
54 if err != nil {
55 panic(fmt.Sprintf("failed to get absolute path for static directory: %v", err))
56 }
57 return http.StripPrefix("/static/", http.FileServer(http.Dir(absPath)))
58}