1package static
2
3import (
4 "fmt"
5 "io"
6 "io/fs"
7 "mime"
8 "net/http"
9 "path/filepath"
10
11 "git.gabrielgio.me/cerrado/pkg/ext"
12 "git.gabrielgio.me/cerrado/static"
13 "github.com/alecthomas/chroma/v2"
14 "github.com/alecthomas/chroma/v2/formatters/html"
15 "github.com/alecthomas/chroma/v2/styles"
16)
17
18func ServeStaticHandler() (ext.ErrorRequestHandler, error) {
19 staticFs, err := fs.Sub(static.Static, ".")
20 if err != nil {
21 return nil, err
22 }
23
24 return func(w http.ResponseWriter, r *ext.Request) error {
25 var (
26 f = r.PathValue("file")
27 e = filepath.Ext(f)
28 m = mime.TypeByExtension(e)
29 )
30 ext.SetMIME(w, m)
31 w.Header().Add("Cache-Control", "max-age=31536000")
32 http.ServeFileFS(w, r.Request, staticFs, f)
33 return nil
34 }, nil
35}
36
37func ServeStaticCSSHandler(lightTheme, darkTheme string) (ext.ErrorRequestHandler, error) {
38 var (
39 lightStyle = styles.Get(lightTheme)
40 darkStyle = styles.Get(darkTheme)
41 formatter = html.New(
42 html.WithCSSComments(false),
43 )
44 )
45
46 return func(w http.ResponseWriter, r *ext.Request) error {
47 ext.SetMIME(w, "text/css")
48
49 var style *chroma.Style
50 style = darkStyle
51 w.Write([]byte("[data-bs-theme=\"dark\"] {\n"))
52 err := formatter.WriteCSS(&ws{w}, style)
53 if err != nil {
54 return err
55 }
56 w.Write([]byte("}\n"))
57
58 style = lightStyle
59 w.Write([]byte("[data-bs-theme=\"light\"] {\n"))
60 err = formatter.WriteCSS(&ws{w}, style)
61 if err != nil {
62 return err
63 }
64 w.Write([]byte("\n}"))
65
66 return nil
67 }, nil
68}
69
70type ws struct {
71 inner io.Writer
72}
73
74// This is very cursed, and rely on the fact that it writes every css rule at time.
75// it adds & to the begging so it can be nested by the ServeStaticCSSHandler.
76// This will allow the follow bootstrap data-bs-theme.
77func (w *ws) Write(p []byte) (n int, err error) {
78 return fmt.Fprintf(w.inner, "& %s", string(p))
79}