aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--config.example.scfg4
-rw-r--r--go.mod43
-rw-r--r--go.sum140
-rw-r--r--pkg/config/config.go38
-rw-r--r--pkg/config/config_test.go32
-rw-r--r--pkg/handler/git/handler.go2
-rw-r--r--pkg/handler/router.go15
-rw-r--r--pkg/handler/static/handler.go59
-rw-r--r--templates/base.qtpl22
-rw-r--r--templates/base.qtpl.go125
11 files changed, 308 insertions, 175 deletions
diff --git a/README.md b/README.md
index 477883d..adb4809 100644
--- a/README.md
+++ b/README.md
@@ -62,9 +62,6 @@ mail@gabrielgio.me
### TODO
- dark theme that does not require js
-- dark theme support for systax highlight configuration
- - we should be able to generate css from both theme and provide as an
- endpoint.
### Ideas
diff --git a/config.example.scfg b/config.example.scfg
index 5e47548..e726c19 100644
--- a/config.example.scfg
+++ b/config.example.scfg
@@ -3,9 +3,9 @@
listen-addr unix://var/run/cerrado.sock
root-readme /srv/git/README.md
-syntax-highlight monokailight
+syntax-highlight monokailight monokai
-# full hostname address plus protocol.
+# full hostname address plus protocol.
# This is going to be used to display full link (e.g.: clone link)
hostname https://domain.tld
diff --git a/go.mod b/go.mod
index 3ba555f..eb6a5c6 100644
--- a/go.mod
+++ b/go.mod
@@ -1,39 +1,42 @@
module git.gabrielgio.me/cerrado
-go 1.22.2
+go 1.24.0
+
+toolchain go1.24.9
require (
git.sr.ht/~emersion/go-scfg v0.0.0-20250102010123-2f3fb2d5d50e
- github.com/alecthomas/chroma/v2 v2.15.0
- github.com/andybalholm/brotli v1.1.1
- github.com/go-git/go-git/v5 v5.13.2
- github.com/gomarkdown/markdown v0.0.0-20250207164621-7a1f277a159e
- github.com/google/go-cmp v0.6.0
- github.com/klauspost/compress v1.17.11
+ github.com/alecthomas/chroma/v2 v2.20.0
+ github.com/andybalholm/brotli v1.2.0
+ github.com/go-git/go-git/v5 v5.16.3
+ github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a
+ github.com/google/go-cmp v0.7.0
+ github.com/klauspost/compress v1.18.1
github.com/valyala/quicktemplate v1.8.0
- golang.org/x/crypto v0.33.0
- golang.org/x/sync v0.11.0
+ golang.org/x/crypto v0.43.0
+ golang.org/x/sync v0.17.0
)
require (
- dario.cat/mergo v1.0.1 // indirect
+ dario.cat/mergo v1.0.2 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
- github.com/ProtonMail/go-crypto v1.1.5 // indirect
- github.com/cloudflare/circl v1.6.0 // indirect
- github.com/cyphar/filepath-securejoin v0.4.1 // indirect
- github.com/dlclark/regexp2 v1.11.4 // indirect
+ github.com/ProtonMail/go-crypto v1.3.0 // indirect
+ github.com/cloudflare/circl v1.6.1 // indirect
+ github.com/cyphar/filepath-securejoin v0.5.0 // indirect
+ github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.6.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
- github.com/kevinburke/ssh_config v1.2.0 // indirect
- github.com/pjbgf/sha1cd v0.3.2 // indirect
- github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
- github.com/skeema/knownhosts v1.3.1 // indirect
+ github.com/kevinburke/ssh_config v1.4.0 // indirect
+ github.com/klauspost/cpuid/v2 v2.3.0 // indirect
+ github.com/pjbgf/sha1cd v0.5.0 // indirect
+ github.com/sergi/go-diff v1.4.0 // indirect
+ github.com/skeema/knownhosts v1.3.2 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
- golang.org/x/net v0.34.0 // indirect
- golang.org/x/sys v0.30.0 // indirect
+ golang.org/x/net v0.46.0 // indirect
+ golang.org/x/sys v0.37.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)
diff --git a/go.sum b/go.sum
index 59c8d96..a8d56e7 100644
--- a/go.sum
+++ b/go.sum
@@ -1,80 +1,63 @@
-dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
-dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
-git.sr.ht/~emersion/go-scfg v0.0.0-20240128091534-2ae16e782082 h1:9Udx5fm4vRtmgDIBjy2ef5QioHbzpw5oHabbhpAUyEw=
-git.sr.ht/~emersion/go-scfg v0.0.0-20240128091534-2ae16e782082/go.mod h1:ybgvEJTIx5XbaspSviB3KNa6OdPmAZqDoSud7z8fFlw=
+dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
+dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
git.sr.ht/~emersion/go-scfg v0.0.0-20250102010123-2f3fb2d5d50e h1:dKdXdn8yhldnz8ynz/HNmLPk40tvTwDBsTdQcHddesg=
git.sr.ht/~emersion/go-scfg v0.0.0-20250102010123-2f3fb2d5d50e/go.mod h1:7eWdbNLaP10M+QMSmmHYmYd8q86NHZy12Cq9TiZ9LC8=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
-github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
-github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
-github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
-github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
-github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
-github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
+github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
+github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
-github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
-github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
-github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
-github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
-github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
-github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
-github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
-github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
+github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
+github.com/alecthomas/chroma/v2 v2.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NTz+9sGw=
+github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA=
+github.com/alecthomas/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg=
+github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
+github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
+github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
-github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
-github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
-github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
-github.com/cyphar/filepath-securejoin v0.3.5 h1:L81NHjquoQmcPgXcttUS9qTSR/+bXry6pbSINQGpjj4=
-github.com/cyphar/filepath-securejoin v0.3.5/go.mod h1:edhVd3c6OXKjUmSrVa/tGJRS9joFTxlslFCAyaxigkE=
-github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
-github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
+github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
+github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
+github.com/cyphar/filepath-securejoin v0.5.0 h1:hIAhkRBMQ8nIeuVwcAoymp7MY4oherZdAxD+m0u9zaw=
+github.com/cyphar/filepath-securejoin v0.5.0/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
-github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
-github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
-github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
-github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM=
+github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
+github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
+github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
-github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
-github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
+github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
-github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
-github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
-github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
-github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
-github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0=
-github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A=
+github.com/go-git/go-git/v5 v5.16.3 h1:Z8BtvxZ09bYm/yYNgPKCzgWtaRqDTgIKRgIRHBfU6Z8=
+github.com/go-git/go-git/v5 v5.16.3/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
-github.com/gomarkdown/markdown v0.0.0-20241205020045-f7e15b2f3e62 h1:pbAFUZisjG4s6sxvRJvf2N7vhpCvx2Oxb3PmS6pDO1g=
-github.com/gomarkdown/markdown v0.0.0-20241205020045-f7e15b2f3e62/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
-github.com/gomarkdown/markdown v0.0.0-20250207164621-7a1f277a159e h1:ESHlT0RVZphh4JGBz49I5R6nTdC8Qyc08vU25GQHzzQ=
-github.com/gomarkdown/markdown v0.0.0-20250207164621-7a1f277a159e/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
-github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
-github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a h1:l7A0loSszR5zHd/qK53ZIHMO8b3bBSmENnQ6eKnUT0A=
+github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
-github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
-github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
-github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
-github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
+github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
+github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
+github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
+github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
+github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
+github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -84,29 +67,24 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
-github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
-github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
-github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
-github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
+github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
+github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
-github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
-github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
-github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
+github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
+github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
+github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
+github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
-github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
-github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
-github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
+github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg=
+github.com/skeema/knownhosts v1.3.2/go.mod h1:bEg3iQAuw+jyiw+484wwFJoKSLwcfd7fqRy+N0QTiow=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k=
@@ -116,39 +94,29 @@ github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
-golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
-golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
-golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
+golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
+golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
-golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
-golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
-golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
-golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
-golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
-golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
+golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
+golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
+golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
-golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
-golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
+golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
-golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
-golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
+golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
+golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
-golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
+golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/pkg/config/config.go b/pkg/config/config.go
index c00586b..ff969ec 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -39,6 +39,11 @@ type (
Public bool
}
+ SyntaxHighlight struct {
+ Dark string
+ Light string
+ }
+
// configuration represents file configuration.
// fields needs to be exported to cmp to work
configuration struct {
@@ -50,7 +55,7 @@ type (
Repositories []*GitRepositoryConfiguration
RootReadme string
Scans []*scan
- SyntaxHighlight string
+ SyntaxHighlight SyntaxHighlight
Hostname string
}
@@ -75,7 +80,7 @@ type (
removeSuffix bool
repositories []*GitRepositoryConfiguration
rootReadme string
- syntaxHighlight string
+ syntaxHighlight SyntaxHighlight
hostname string
}
)
@@ -129,7 +134,11 @@ func (c *ConfigurationRepository) GetOrderBy() OrderBy {
}
func (c *ConfigurationRepository) GetSyntaxHighlight() string {
- return c.syntaxHighlight
+ return c.syntaxHighlight.Light
+}
+
+func (c *ConfigurationRepository) GetSyntaxHighlightDark() string {
+ return c.syntaxHighlight.Dark
}
func (c *ConfigurationRepository) GetListenAddr() string {
@@ -371,9 +380,26 @@ func setAESKey(block scfg.Block, listenAddr *string) error {
return setString(scanDir, listenAddr)
}
-func setSyntaxHighlight(block scfg.Block, listenAddr *string) error {
- scanDir := block.Get("syntax-highlight")
- return setString(scanDir, listenAddr)
+func setSyntaxHighlight(block scfg.Block, sh *SyntaxHighlight) error {
+ shDir := block.Get("syntax-highlight")
+ if shDir == nil {
+ return nil
+ }
+
+ themes := shDir.Params
+ if len(themes) > 2 || len(themes) == 0 {
+ return errors.New("syntax-highlight must contains at most two params and at least one, light then dark theme name")
+ }
+
+ sh.Light = themes[0]
+ if len(themes) > 1 {
+ sh.Dark = themes[1]
+ } else {
+ // if dark is not set use light
+ sh.Dark = sh.Light
+ }
+
+ return nil
}
func setOrderby(block scfg.Block, orderBy *string) error {
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index 31cf1c0..50744b5 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -48,6 +48,21 @@ scan "/srv/git" {
},
},
{
+ name: "themes",
+ config: `
+syntax-highlight light dark`,
+ expectedConfig: &configuration{
+ Scans: defaultScans(),
+ ListenAddr: defaultAddr(),
+ Hostname: defaultHostname(),
+ Repositories: []*GitRepositoryConfiguration{},
+ SyntaxHighlight: SyntaxHighlight{
+ Light: "light",
+ Dark: "dark",
+ },
+ },
+ },
+ {
name: "minimal repository",
config: `repository /srv/git/cerrado.git`,
expectedConfig: &configuration{
@@ -139,13 +154,16 @@ repository /srv/git/cerrado.git {
Path: "/srv/git",
},
},
- ListenAddr: "unix://var/run/cerrado/cerrado.sock",
- Passphrase: "$2a$14$VnB/ZcB1DUDkMnosRA6Y7.dj8h5eroslDxTeXlLwfQX/x86mh6WAq",
- AESKey: "8XHptZxSWCGs1m7QzztX5zNQ7D9NiQevVX0DaUTNMbDpRwFzoJiB0U7K6O/kqIt01jJVgzBUfiR8ES46ZLLb4w==",
- SyntaxHighlight: "monokailight",
- OrderBy: "lastcommit-desc",
- RemoveSuffix: true,
- Hostname: "https://domain.tld",
+ ListenAddr: "unix://var/run/cerrado/cerrado.sock",
+ Passphrase: "$2a$14$VnB/ZcB1DUDkMnosRA6Y7.dj8h5eroslDxTeXlLwfQX/x86mh6WAq",
+ AESKey: "8XHptZxSWCGs1m7QzztX5zNQ7D9NiQevVX0DaUTNMbDpRwFzoJiB0U7K6O/kqIt01jJVgzBUfiR8ES46ZLLb4w==",
+ SyntaxHighlight: SyntaxHighlight{
+ Light: "monokailight",
+ Dark: "monokailight",
+ },
+ OrderBy: "lastcommit-desc",
+ RemoveSuffix: true,
+ Hostname: "https://domain.tld",
Repositories: []*GitRepositoryConfiguration{
{
Name: "linux.git",
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..1fbc4e3 100644
--- a/pkg/handler/router.go
+++ b/pkg/handler/router.go
@@ -1,6 +1,7 @@
package handler
import (
+ "fmt"
"net/http"
serverconfig "git.gabrielgio.me/cerrado/pkg/config"
@@ -10,6 +11,7 @@ import (
"git.gabrielgio.me/cerrado/pkg/handler/git"
"git.gabrielgio.me/cerrado/pkg/handler/static"
"git.gabrielgio.me/cerrado/pkg/service"
+ "git.gabrielgio.me/cerrado/templates"
)
// Mount handler gets the requires service and repository to build the handlers
@@ -31,6 +33,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 +55,11 @@ func MountHandler(
}
mux.HandleFunc("/static/{file}", staticHandler)
+ // add slug and session so css file can be cached forever.
+ // Slug follow commit id, which is update every new version
+ // Session is update every time server restarts, this allows the css to be
+ // cached forever but refresh if the admin updates the server configuration.
+ mux.HandleFunc(fmt.Sprintf("/static/theme.%s%s.css", templates.Session, templates.Slug), 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..6cc884e 100644
--- a/pkg/handler/static/handler.go
+++ b/pkg/handler/static/handler.go
@@ -1,6 +1,9 @@
package static
import (
+ "bytes"
+ "fmt"
+ "io"
"io/fs"
"mime"
"net/http"
@@ -8,6 +11,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 +34,56 @@ 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")
+ w.Header().Add("Cache-Control", "max-age=31536000")
+
+ // use buffer so this function can fail before writing to http.ResponseWriter
+ var buffer bytes.Buffer
+
+ var style *chroma.Style
+ style = darkStyle
+ buffer.Write([]byte("[data-bs-theme=\"dark\"] {\n"))
+ err := formatter.WriteCSS(&ws{&buffer}, style)
+ if err != nil {
+ return err
+ }
+ buffer.Write([]byte("}\n"))
+
+ style = lightStyle
+ buffer.Write([]byte("[data-bs-theme=\"light\"] {\n"))
+ err = formatter.WriteCSS(&ws{&buffer}, style)
+ if err != nil {
+ return err
+ }
+ buffer.Write([]byte("}"))
+
+ _, err = io.Copy(w, &buffer)
+ if err != nil {
+ return err
+ }
+
+ 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..6ff3d53 100644
--- a/templates/base.qtpl
+++ b/templates/base.qtpl
@@ -1,11 +1,28 @@
This is a base page template. All the other template pages implement this interface.
{% import "context" %}
+{% import "crypto/rand" %}
+{% import "encoding/hex" %}
{% import "strconv" %}
{% import "time" %}
-{% code
+{% code
+
var Slug = ""
+ var Session = ""
+
+ func init() {
+ Session = hex.EncodeToString(generateSmallTimeID())
+}
+
+func generateSmallTimeID() []byte {
+ b := make([]byte, 4)
+ _, err := rand.Read(b)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
%}
{% interface
@@ -58,8 +75,9 @@ Page prints a page implementing Page interface.
<head>
<meta charset="utf-8">
<link rel="icon" href="data:,">
- <title>{%= p.Title(ctx) %}</title>
+ <title>{%= p.Title(ctx) %}</title>
<link rel="stylesheet" href="/static/main{%s Slug %}.css">
+ <link rel="stylesheet" href="/static/theme.{%s Session %}{%s Slug %}.css">
<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..db8afec 100644
--- a/templates/base.qtpl.go
+++ b/templates/base.qtpl.go
@@ -11,57 +11,77 @@ package templates
import "context"
//line templates/base.qtpl:4
-import "strconv"
+import "crypto/rand"
//line templates/base.qtpl:5
-import "time"
+import "encoding/hex"
+
+//line templates/base.qtpl:6
+import "strconv"
//line templates/base.qtpl:7
+import "time"
+
+//line templates/base.qtpl:9
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line templates/base.qtpl:7
+//line templates/base.qtpl:9
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line templates/base.qtpl:8
+//line templates/base.qtpl:11
var Slug = ""
+var Session = ""
+
+func init() {
+ Session = hex.EncodeToString(generateSmallTimeID())
+}
+
+func generateSmallTimeID() []byte {
+ b := make([]byte, 4)
+ _, err := rand.Read(b)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
type Page interface {
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
Title(ctx context.Context) string
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
StreamTitle(qw422016 *qt422016.Writer, ctx context.Context)
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
WriteTitle(qq422016 qtio422016.Writer, ctx context.Context)
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
Content(ctx context.Context) string
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
StreamContent(qw422016 *qt422016.Writer, ctx context.Context)
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
WriteContent(qq422016 qtio422016.Writer, ctx context.Context)
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
Script(ctx context.Context) string
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
StreamScript(qw422016 *qt422016.Writer, ctx context.Context)
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
WriteScript(qq422016 qtio422016.Writer, ctx context.Context)
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
Navbar(ctx context.Context) string
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
StreamNavbar(qw422016 *qt422016.Writer, ctx context.Context)
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
WriteNavbar(qq422016 qtio422016.Writer, ctx context.Context)
-//line templates/base.qtpl:12
+//line templates/base.qtpl:29
}
-//line templates/base.qtpl:21
+//line templates/base.qtpl:38
func FromUInttoString(u *uint) string {
if u != nil {
return strconv.FormatUint(uint64(*u), 10)
@@ -69,23 +89,23 @@ func FromUInttoString(u *uint) string {
return ""
}
-//line templates/base.qtpl:31
+//line templates/base.qtpl:48
func TimeFormat(t time.Time) string {
return t.Format("02.01.2006")
}
-//line templates/base.qtpl:36
+//line templates/base.qtpl:53
func Ignore[T any](v T, _ error) T {
return v
}
-//line templates/base.qtpl:42
+//line templates/base.qtpl:59
func IsAuthenticationDisabled(ctx context.Context) bool {
t, ok := ctx.Value("disableAuthentication").(bool)
return ok && t
}
-//line templates/base.qtpl:48
+//line templates/base.qtpl:65
func IsLoggedIn(ctx context.Context) bool {
t, ok := ctx.Value("logged").(bool)
return ok && t
@@ -93,9 +113,9 @@ func IsLoggedIn(ctx context.Context) bool {
// Page prints a page implementing Page interface.
-//line templates/base.qtpl:55
+//line templates/base.qtpl:72
func StreamPageTemplate(qw422016 *qt422016.Writer, p Page, ctx context.Context) {
-//line templates/base.qtpl:55
+//line templates/base.qtpl:72
qw422016.N().S(`
<!DOCTYPE html>
<html lang="en" data-bs-theme="light">
@@ -103,14 +123,21 @@ func StreamPageTemplate(qw422016 *qt422016.Writer, p Page, ctx context.Context)
<meta charset="utf-8">
<link rel="icon" href="data:,">
<title>`)
-//line templates/base.qtpl:61
+//line templates/base.qtpl:78
p.StreamTitle(qw422016, ctx)
-//line templates/base.qtpl:61
- qw422016.N().S(`</title>
+//line templates/base.qtpl:78
+ qw422016.N().S(`</title>
<link rel="stylesheet" href="/static/main`)
-//line templates/base.qtpl:62
+//line templates/base.qtpl:79
qw422016.E().S(Slug)
-//line templates/base.qtpl:62
+//line templates/base.qtpl:79
+ qw422016.N().S(`.css">
+ <link rel="stylesheet" href="/static/theme.`)
+//line templates/base.qtpl:80
+ qw422016.E().S(Session)
+//line templates/base.qtpl:80
+ qw422016.E().S(Slug)
+//line templates/base.qtpl:80
qw422016.N().S(`.css">
<html data-bs-theme="dark">
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
@@ -118,53 +145,53 @@ func StreamPageTemplate(qw422016 *qt422016.Writer, p Page, ctx context.Context)
</head>
<body>
`)
-//line templates/base.qtpl:68
+//line templates/base.qtpl:86
p.StreamNavbar(qw422016, ctx)
-//line templates/base.qtpl:68
+//line templates/base.qtpl:86
qw422016.N().S(`
<div class="container">
`)
-//line templates/base.qtpl:70
+//line templates/base.qtpl:88
p.StreamContent(qw422016, ctx)
-//line templates/base.qtpl:70
+//line templates/base.qtpl:88
qw422016.N().S(`
</div>
</body>
`)
-//line templates/base.qtpl:73
+//line templates/base.qtpl:91
p.StreamScript(qw422016, ctx)
-//line templates/base.qtpl:73
+//line templates/base.qtpl:91
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:96
}
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
func WritePageTemplate(qq422016 qtio422016.Writer, p Page, ctx context.Context) {
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
qw422016 := qt422016.AcquireWriter(qq422016)
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
StreamPageTemplate(qw422016, p, ctx)
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
qt422016.ReleaseWriter(qw422016)
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
}
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
func PageTemplate(p Page, ctx context.Context) string {
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
qb422016 := qt422016.AcquireByteBuffer()
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
WritePageTemplate(qb422016, p, ctx)
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
qs422016 := string(qb422016.B)
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
qt422016.ReleaseByteBuffer(qb422016)
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
return qs422016
-//line templates/base.qtpl:78
+//line templates/base.qtpl:96
}