cerrado @ 5dd940eb52b40c78a2078ed0a02440e84bee0306

 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}