diff options
| author | Gabriel A. Giovanini <mail@gabrielgio.me> | 2025-11-01 17:49:20 +0100 |
|---|---|---|
| committer | Gabriel A. Giovanini <mail@gabrielgio.me> | 2025-11-01 17:49:20 +0100 |
| commit | 5dd940eb52b40c78a2078ed0a02440e84bee0306 (patch) | |
| tree | 81e6b5a148c42a5687a0fde0a77001b5ab81cfb4 | |
| parent | ed1fc6854a634f7fcff7d1a500c40e7502031ea7 (diff) | |
| download | cerrado-5dd940eb52b40c78a2078ed0a02440e84bee0306.tar.gz cerrado-5dd940eb52b40c78a2078ed0a02440e84bee0306.tar.bz2 cerrado-5dd940eb52b40c78a2078ed0a02440e84bee0306.zip | |
feat: Write css dark/light theme on standalone url
This will allow tho write both themes into the same css file.
Also mend with the css generate by chroma so it can be nested.
| -rw-r--r-- | pkg/handler/git/handler.go | 2 | ||||
| -rw-r--r-- | pkg/handler/router.go | 9 | ||||
| -rw-r--r-- | pkg/handler/static/handler.go | 49 | ||||
| -rw-r--r-- | templates/base.qtpl | 2 | ||||
| -rw-r--r-- | templates/base.qtpl.go | 53 |
5 files changed, 88 insertions, 27 deletions
diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go index ffa5dfd..d046d19 100644 --- a/pkg/handler/git/handler.go +++ b/pkg/handler/git/handler.go @@ -349,6 +349,7 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *ext.Request) error { formatter := html.New( html.WithLineNumbers(true), html.WithLinkableLineNumbers(true, "L"), + html.WithClasses(true), ) iterator, err := lexer.Tokenise(nil, string(file)) @@ -440,6 +441,7 @@ func (g *GitHandler) Commit(w http.ResponseWriter, r *ext.Request) error { formatter := html.New( html.WithLineNumbers(true), html.WithLinkableLineNumbers(true, "L"), + html.WithClasses(true), ) iterator, err := lexer.Tokenise(nil, diff) diff --git a/pkg/handler/router.go b/pkg/handler/router.go index fea8827..bc81350 100644 --- a/pkg/handler/router.go +++ b/pkg/handler/router.go @@ -31,6 +31,14 @@ func MountHandler( return nil, err } + cssStaticHandler, err := static.ServeStaticCSSHandler( + configRepo.GetSyntaxHighlight(), + configRepo.GetSyntaxHighlightDark(), + ) + if err != nil { + return nil, err + } + mux := ext.NewRouter() mux.AddMiddleware(ext.Compress) mux.AddMiddleware(ext.Log) @@ -45,6 +53,7 @@ func MountHandler( } mux.HandleFunc("/static/{file}", staticHandler) + mux.HandleFunc("/static/theme", cssStaticHandler) mux.HandleFunc("/{name}/about/{$}", gitHandler.About) mux.HandleFunc("/{name}", gitHandler.Multiplex) mux.HandleFunc("/{name}/{rest...}", gitHandler.Multiplex) diff --git a/pkg/handler/static/handler.go b/pkg/handler/static/handler.go index cdb2ae6..779c786 100644 --- a/pkg/handler/static/handler.go +++ b/pkg/handler/static/handler.go @@ -1,6 +1,8 @@ package static import ( + "fmt" + "io" "io/fs" "mime" "net/http" @@ -8,6 +10,9 @@ import ( "git.gabrielgio.me/cerrado/pkg/ext" "git.gabrielgio.me/cerrado/static" + "github.com/alecthomas/chroma/v2" + "github.com/alecthomas/chroma/v2/formatters/html" + "github.com/alecthomas/chroma/v2/styles" ) func ServeStaticHandler() (ext.ErrorRequestHandler, error) { @@ -28,3 +33,47 @@ func ServeStaticHandler() (ext.ErrorRequestHandler, error) { return nil }, nil } + +func ServeStaticCSSHandler(lightTheme, darkTheme string) (ext.ErrorRequestHandler, error) { + var ( + lightStyle = styles.Get(lightTheme) + darkStyle = styles.Get(darkTheme) + formatter = html.New( + html.WithCSSComments(false), + ) + ) + + return func(w http.ResponseWriter, r *ext.Request) error { + ext.SetMIME(w, "text/css") + + var style *chroma.Style + style = darkStyle + w.Write([]byte("[data-bs-theme=\"dark\"] {\n")) + err := formatter.WriteCSS(&ws{w}, style) + if err != nil { + return err + } + w.Write([]byte("}\n")) + + style = lightStyle + w.Write([]byte("[data-bs-theme=\"light\"] {\n")) + err = formatter.WriteCSS(&ws{w}, style) + if err != nil { + return err + } + w.Write([]byte("\n}")) + + return nil + }, nil +} + +type ws struct { + inner io.Writer +} + +// This is very cursed, and rely on the fact that it writes every css rule at time. +// it adds & to the begging so it can be nested by the ServeStaticCSSHandler. +// This will allow the follow bootstrap data-bs-theme. +func (w *ws) Write(p []byte) (n int, err error) { + return fmt.Fprintf(w.inner, "& %s", string(p)) +} diff --git a/templates/base.qtpl b/templates/base.qtpl index b3df94a..e43fb67 100644 --- a/templates/base.qtpl +++ b/templates/base.qtpl @@ -60,6 +60,8 @@ Page prints a page implementing Page interface. <link rel="icon" href="data:,"> <title>{%= p.Title(ctx) %}</title> <link rel="stylesheet" href="/static/main{%s Slug %}.css"> + <link rel="stylesheet" href="/static/themes/dark"> + <link rel="stylesheet" href="/static/themes/light"> <html data-bs-theme="dark"> <meta content="text/html;charset=utf-8" http-equiv="Content-Type"> <meta name="viewport" content="width=device-width, initial-scale=1" /> diff --git a/templates/base.qtpl.go b/templates/base.qtpl.go index dce4cbc..783de2c 100644 --- a/templates/base.qtpl.go +++ b/templates/base.qtpl.go @@ -8,16 +8,14 @@ package templates //line templates/base.qtpl:3 -import "context" - -//line templates/base.qtpl:4 -import "strconv" +import ( + "context" + "strconv" + "time" //line templates/base.qtpl:4 -//line templates/base.qtpl:5 -import "time" + //line templates/base.qtpl:5 + //line templates/base.qtpl:7 -//line templates/base.qtpl:7 -import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" @@ -112,59 +110,60 @@ func StreamPageTemplate(qw422016 *qt422016.Writer, p Page, ctx context.Context) qw422016.E().S(Slug) //line templates/base.qtpl:62 qw422016.N().S(`.css"> + <link rel="stylesheet" href="/static/theme"> <html data-bs-theme="dark"> <meta content="text/html;charset=utf-8" http-equiv="Content-Type"> <meta name="viewport" content="width=device-width, initial-scale=1" /> </head> <body> `) -//line templates/base.qtpl:68 +//line templates/base.qtpl:70 p.StreamNavbar(qw422016, ctx) -//line templates/base.qtpl:68 +//line templates/base.qtpl:70 qw422016.N().S(` <div class="container"> `) -//line templates/base.qtpl:70 +//line templates/base.qtpl:72 p.StreamContent(qw422016, ctx) -//line templates/base.qtpl:70 +//line templates/base.qtpl:72 qw422016.N().S(` </div> </body> `) -//line templates/base.qtpl:73 +//line templates/base.qtpl:75 p.StreamScript(qw422016, ctx) -//line templates/base.qtpl:73 +//line templates/base.qtpl:75 qw422016.N().S(` <script> function a(){const e=window.matchMedia("(prefers-color-scheme: dark)").matches;document.documentElement.setAttribute("data-bs-theme",e?"dark":"light")}a(),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",a); </script> </html> `) -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 } -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 func WritePageTemplate(qq422016 qtio422016.Writer, p Page, ctx context.Context) { -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 qw422016 := qt422016.AcquireWriter(qq422016) -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 StreamPageTemplate(qw422016, p, ctx) -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 qt422016.ReleaseWriter(qw422016) -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 } -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 func PageTemplate(p Page, ctx context.Context) string { -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 qb422016 := qt422016.AcquireByteBuffer() -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 WritePageTemplate(qb422016, p, ctx) -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 qs422016 := string(qb422016.B) -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 qt422016.ReleaseByteBuffer(qb422016) -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 return qs422016 -//line templates/base.qtpl:78 +//line templates/base.qtpl:80 } |
