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