9 Commits
Author SHA1 Message Date
Florian.Walther a08b30b02f updated README for pre-build container
Docker Release Build / push_to_registry (push) Successful in 52s
2026-05-02 15:54:18 +02:00
Florian.Walther ae0c2639cb added table support in markdown
Docker Release Build / push_to_registry (push) Successful in 1m1s
2026-05-02 15:44:48 +02:00
Florian.Walther 496dba4281 known working version from web-password used
Docker Release Build / push_to_registry (push) Successful in 1m10s
2026-05-02 13:58:05 +02:00
Florian.Walther 3be8a0b757 .gitea/workflows/docker-publish.yml aktualisiert
Docker Publish / build-and-push (push) Failing after 17s
Login to Gitea Abschnitt aus Web-Password action übernommen.
2026-05-02 13:51:35 +02:00
Florian Walther d1c6b64241 adding dark-/light-mode 2026-05-01 22:09:09 +02:00
Florian Walther 5ec92f1a7c fixing runner tag from docker to ubuntu-latest
Docker Publish / build-and-push (push) Failing after 9s
2026-05-01 19:20:24 +02:00
Florian Walther 205f664ac0 more fixing the workflow
Docker Publish / build-and-push (push) Has been cancelled
2026-05-01 19:19:17 +02:00
Florian Walther ee2c2231b1 fixing runner tag from docker to ubuntu-latest
Docker Publish / build-and-push (push) Failing after 9s
2026-05-01 19:16:06 +02:00
Florian Walther d305aa313a more workflow fixing
Docker Publish / build-and-push (push) Has been cancelled
2026-05-01 19:13:24 +02:00
5 changed files with 136 additions and 52 deletions
+21 -18
View File
@@ -1,29 +1,32 @@
name: Docker Publish name: Docker Release Build
on: on:
push: push:
tags: tags:
- 'v[0-9]+.[0-9]+.[0-9]+' - 'v*' # Reagiert auf Tags die mit 'v' beginnen, z.B. v1.0.2
jobs: jobs:
build-and-push: push_to_registry:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@main uses: actions/checkout@v4
- name: Set up Docker Buildx - name: Login to Gitea
run: | uses: docker/login-action@v3
docker buildx create --use with:
registry: ${{ vars.REGISTRY_URL }} # gitea.scu.si
- name: Login to Gitea Container Registry username: ${{ secrets.REGISTRY_USER }}
run: | password: ${{ secrets.REGISTRY_PASSWORD }}
echo "${{ secrets.GITEA_TOKEN }}" | docker login -u "${{ env.ACTOR }}" --password-stdin gitea.scu.si
- name: Build and push - name: Build and push
run: | uses: docker/build-push-action@v5
docker buildx build \ with:
--platform linux/amd64,linux/arm64 \ context: .
--push \ push: true
-t gitea.scu.si/${{ env.REPOSITORY }}/mdhost:latest \ # Hier wird die Git-Referenz automatisch als Docker-Tag genutzt
-t gitea.scu.si/${{ env.REPOSITORY }}/mdhost:${{ env.REF_NAME }} \ #tags: gitea.scu.si/florianwalther/mdhost:${{ gitea.ref_name }}
. build-args: |
APP_VERSION=${{ gitea.ref_name }}
tags: |
gitea.scu.si/florian.walther/mdhost:${{ gitea.ref_name }}
gitea.scu.si/florian.walther/mdhost:latest
+2
View File
@@ -119,6 +119,8 @@ The creation timestamp is stored in the file's `CreatedAt` field and persists ac
## Docker ## Docker
A pre-built Docker image is available from `gitea.scu.si/florian.walther/mdhost:latest`.
### Build the Image ### Build the Image
```bash ```bash
+6 -4
View File
@@ -3,10 +3,12 @@ module mdhost
go 1.26.2 go 1.26.2
require ( require (
github.com/yuin/goldmark v1.8.2
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594
golang.org/x/crypto v0.50.0
)
require (
github.com/alecthomas/chroma v0.10.0 // indirect github.com/alecthomas/chroma v0.10.0 // indirect
github.com/alecthomas/chroma/v2 v2.24.1 // indirect
github.com/dlclark/regexp2 v1.12.0 // indirect github.com/dlclark/regexp2 v1.12.0 // indirect
github.com/yuin/goldmark v1.8.2 // indirect
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 // indirect
golang.org/x/crypto v0.50.0 // indirect
) )
+4 -2
View File
@@ -1,14 +1,15 @@
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/alecthomas/chroma/v2 v2.24.1 h1:m5ffpfZbIb++k8AqFEKy9uVgY12xIQtBsQlc6DfZJQM=
github.com/alecthomas/chroma/v2 v2.24.1/go.mod h1:l+ohZ9xRXIbGe7cIW+YZgOGbvuVLjMps/FYN/CwuabI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8= github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8=
github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE= github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE=
@@ -18,4 +19,5 @@ github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594/go.mod
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+101 -26
View File
@@ -16,6 +16,7 @@ import (
"time" "time"
"github.com/yuin/goldmark" "github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark-highlighting" "github.com/yuin/goldmark-highlighting"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@@ -83,9 +84,12 @@ var (
func newMarkdownRenderer() goldmark.Markdown { func newMarkdownRenderer() goldmark.Markdown {
return goldmark.New( return goldmark.New(
goldmark.WithExtensions(highlighting.NewHighlighting( goldmark.WithExtensions(
extension.Table,
highlighting.NewHighlighting(
highlighting.WithStyle("github"), highlighting.WithStyle("github"),
)), ),
),
) )
} }
@@ -174,6 +178,7 @@ func loadData() error {
} }
func getNavBar(r *http.Request) string { func getNavBar(r *http.Request) string {
themeToggle := `<button id="theme-toggle" aria-label="Toggle dark mode">🌓</button>`
if isAuthenticated(r) { if isAuthenticated(r) {
username := "" username := ""
userID := getCurrentUserID(r) userID := getCurrentUserID(r)
@@ -183,9 +188,9 @@ func getNavBar(r *http.Request) string {
break break
} }
} }
return fmt.Sprintf(`<nav><a href="/home">home</a> | <a href="/">list</a> | <a href="/add">add</a> | <a href="/edit">edit</a> | <span class="logged-in">Logged in as %s</span> | <a href="/logout">logout</a></nav>`, username) return fmt.Sprintf(`<nav><a href="/home">home</a> | <a href="/">list</a> | <a href="/add">add</a> | <a href="/edit">edit</a> | <span class="logged-in">Logged in as %s</span> | <a href="/logout">logout</a> | %s</nav>`, username, themeToggle)
} }
return `<nav><a href="/home">home</a> | <a href="/">list</a> | <a href="/add">add</a> | <a href="/edit">edit</a> | <a href="/login">login</a> | <a href="/register">register</a></nav>` return `<nav><a href="/home">home</a> | <a href="/">list</a> | <a href="/add">add</a> | <a href="/edit">edit</a> | <a href="/login">login</a> | <a href="/register">register</a> | ` + themeToggle + `</nav>`
} }
// Session helpers - all access sessions map under dataMu lock // Session helpers - all access sessions map under dataMu lock
@@ -450,43 +455,113 @@ func main() {
} }
const css = `<style> const css = `<style>
:root{
--bg-color:#fafafa;
--text-color:#333;
--heading-color:#2c3e50;
--nav-bg:#2c3e50;
--nav-text:#ecf0f1;
--link-color:#3498db;
--code-bg:#f6f8fa;
--code-text:#333;
--input-border:#ddd;
--button-bg:#3498db;
--delete-bg:#e74c3c;
--blockquote-border:#3498db;
--blockquote-text:#555;
--private-color:#95a5a6;
--table-border:#ddd;
--table-bg:#fafafa;
--table-header-bg:#f0f0f0;
--table-row-alt:#f5f5f5;
}
.dark{
--bg-color:#1e1e1e;
--table-border:#444;
--table-bg:#2a2a2a;
--table-header-bg:#333;
--table-row-alt:#252525;
--text-color:#e0e0e0;
--heading-color:#e0e0e0;
--nav-bg:#2c3e50;
--nav-text:#ffffff;
--link-color:#58a6ff;
--code-bg:#1a1a1a;
--code-text:#ffffff;
--input-border:#444;
--button-bg:#0d6efd;
--delete-bg:#da3633;
--blockquote-border:#58a6ff;
--blockquote-text:#aaa;
--private-color:#8892b0;
}
*:before,*:after{box-sizing:border-box} *:before,*:after{box-sizing:border-box}
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;line-height:1.6;color:#333;background:#fafafa} body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;line-height:1.6;color:var(--text-color);background:var(--bg-color);transition:background .3s,color .3s}
nav{background:#2c3e50;padding:.5rem;position:sticky;top:0;z-index:100} nav{background:var(--nav-bg);padding:.5rem;position:sticky;top:0;z-index:100}
nav a{color:#ecf0f1;text-decoration:none;margin:0 .5rem;padding:.25rem .5rem;border-radius:4px;transition:background .2s} nav a{color:var(--nav-text);text-decoration:none;margin:0 .5rem;padding:.25rem .5rem;border-radius:4px;transition:background .2s}
nav a:hover{background:rgba(255,255,255,.1)} nav a:hover{background:rgba(255,255,255,.1)}
nav .logged-in{color:#ecf0f1;font-weight:600;margin:0 .5rem;padding:.25rem .5rem} nav .logged-in{color:var(--nav-text);font-weight:600;margin:0 .5rem;padding:.25rem .5rem}
main{padding:1rem;max-width:800px;margin:0 auto} main{padding:1rem;max-width:800px;margin:0 auto}
h1,h2{color:#2c3e50;margin-top:0} h1,h2{color:var(--heading-color);margin-top:0}
ul,ol{padding-left:1.5rem} ul,ol{padding-left:1.5rem}
li{margin:.5rem 0} li{margin:.5rem 0}
form{margin:1rem 0} form{margin:1rem 0}
label{display:block;margin:.5rem 0 .25rem;font-weight:600} label{display:block;margin:.5rem 0 .25rem;font-weight:600;color:var(--text-color)}
input[type="text"],input[type="password"]{width:100%;padding:.5rem;font-size:1rem;border:1px solid #ddd;border-radius:4px;font-family:inherit} input[type="text"],input[type="password"]{width:100%;padding:.5rem;font-size:1rem;border:1px solid var(--input-border);border-radius:4px;font-family:inherit;background:var(--bg-color);color:var(--text-color)}
textarea{width:100%;padding:.75rem;font-size:1rem;border:1px solid #ddd;border-radius:4px;font-family:inherit;min-height:400px} textarea{width:100%;padding:.75rem;font-size:1rem;border:1px solid var(--input-border);border-radius:4px;font-family:inherit;min-height:400px;background:var(--bg-color);color:var(--text-color)}
@media(min-height:700px){textarea{min-height:500px}} @media(min-height:700px){textarea{min-height:500px}}
button{background:#3498db;color:#fff;border:none;padding:.5rem 1rem;border-radius:4px;cursor:pointer;font-size:1rem;transition:background .2s} button{background:var(--button-bg);color:#fff;border:none;padding:.5rem 1rem;border-radius:4px;cursor:pointer;font-size:1rem;transition:background .2s}
button:hover{background:#2980b9} button:hover{background:var(--link-color)}
.delete-btn{background:#e74c3c;color:#fff;padding:.1rem .3rem;font-size:.7rem;border-radius:3px;cursor:pointer;transition:background .2s} .delete-btn{background:var(--delete-bg);color:#fff;padding:.1rem .3rem;font-size:.7rem;border-radius:3px;cursor:pointer;transition:background .2s}
.delete-btn:hover{background:#c0392b} .delete-btn:hover{background:var(--delete-bg)}
.private-indicator{color:#95a5a6;font-size:.8rem;vertical-align:middle} .private-indicator{color:var(--private-color);font-size:.8rem;vertical-align:middle}
.markdown-body{line-height:1.7} .markdown-body{line-height:1.7;color:var(--text-color)}
.markdown-body h1,.markdown-body h2,.markdown-body h3{margin-top:1.5rem} .markdown-body h1,.markdown-body h2,.markdown-body h3{margin-top:1.5rem;color:var(--heading-color)}
.markdown-body p{margin:.75rem 0} .markdown-body p{margin:.75rem 0}
.markdown-body pre{background:#f6f8fa;padding:1rem;border-radius:4px;overflow-x:auto} .markdown-body pre{background:var(--code-bg);padding:1rem;border-radius:4px;overflow-x:auto;color:var(--code-text)}
.markdown-body code{background:#f6f8fa;padding:.1rem .3rem;border-radius:3px;font-family:monospace;font-size:.9rem} .markdown-body code{background:var(--code-bg);padding:.1rem .3rem;border-radius:3px;font-family:monospace;font-size:.9rem;color:var(--code-text)}
.markdown-body blockquote{border-left:3px solid #3498db;padding-left:1rem;margin-left:0;color:#555} .markdown-body blockquote{border-left:3px solid var(--blockquote-border);padding-left:1rem;margin-left:0;color:var(--blockquote-text)}
.markdown-body table{border-collapse:collapse;width:100%;margin:1rem 0;background:var(--table-bg);border:1px solid var(--table-border)}
.markdown-body th{padding:.75rem;text-align:left;border:1px solid var(--table-border);background:var(--table-header-bg);color:var(--heading-color);font-weight:600}
.markdown-body td{padding:.75rem;text-align:left;border:1px solid var(--table-border);color:var(--text-color)}
.markdown-body tr:nth-child(even) td{background:var(--table-row-alt)}
.markdown-body tr:nth-child(odd) td{background:var(--table-bg)}
.markdown-body pre code{background:transparent;padding:0;font-size:inherit} .markdown-body pre code{background:transparent;padding:0;font-size:inherit}
@media(max-width:600px){nav{padding:.5rem;flex-wrap:wrap;display:flex;gap:.5rem}nav a{padding:.25rem .5rem;font-size:.9rem}main{padding:.75rem}}.edit-link{color:#7f8c8d;font-size:.8rem;text-decoration:none} .dark .chroma{color:var(--code-text)!important;background-color:var(--code-bg)!important}
.edit-link:hover{color:#3498db} .dark .chroma .lnt{color:var(--private-color)!important}
</style><meta name="viewport" content="width=device-width,initial-scale=1">` .dark .chroma .ln{color:var(--private-color)!important}
.dark pre{background-color:var(--code-bg)!important}
@media(max-width:600px){nav{padding:.5rem;flex-wrap:wrap;display:flex;gap:.5rem}nav a{padding:.25rem .5rem;font-size:.9rem}main{padding:.75rem}}
.edit-link{color:var(--private-color);font-size:.8rem;text-decoration:none}
.edit-link:hover{color:var(--link-color)}
#theme-toggle{background:none;border:none;cursor:pointer;padding:.25rem .4rem;color:var(--nav-text);font-size:1.1rem;border-radius:4px}
#theme-toggle:hover{background:rgba(255,255,255,.1)}
</style>
<script>
document.addEventListener('DOMContentLoaded',function(){
const html = document.documentElement;
const saved = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme:dark)').matches;
if(saved === 'dark' || (!saved && prefersDark)){
html.classList.add('dark');
}
const toggle = document.getElementById('theme-toggle');
if(toggle){
toggle.addEventListener('click',function(){
html.classList.toggle('dark');
localStorage.setItem('theme', html.classList.contains('dark') ? 'dark' : 'light');
});
}
});
</script>
<meta name="viewport" content="width=device-width,initial-scale=1">`
const chromaCSS = `<style> const chromaCSS = `<style>
.lntd{vertical-align:top;padding:0;margin:0;border:0}.lntable-busy{opacity:.5}.chroma{color:#383a42;background-color:#f6f8fa}.chroma .x{}.chroma .err{color:#a61717;background-color:#e3d2d2}.chroma .lnt{color:#383a42}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable-busy{opacity:.5}.chroma .hl{display:block;width:100%;background-color:#ffdd40}.chroma .lnt{color:#383a42}.chroma .ln{color:#383a42}.chroma .k{color:#000;font-weight:bold}.chroma .kc{color:#000;font-weight:bold}.chroma .kd{color:#000;font-weight:bold}.chroma .kn{color:#000;font-weight:bold}.chroma .kp{color:#000;font-weight:bold}.chroma .kr{color:#000;font-weight:bold}.chroma .kt{color:#445588;font-weight:bold}.chroma .na{color:#008080}.chroma .nb{color:#008080}.chroma .nc{color:#445588;font-weight:bold}.chroma .no{color:#008080}.chroma .nd{color:#3c5d5b;font-weight:bold}.chroma .ni{color:#800080;font-weight:bold}.chroma .ne{color:#800080;font-weight:bold}.chroma .nf{color:#008080}.chroma .nl{color:#008080}.chroma .nn{color:#005580}.chroma .nx{color:#008080}.chroma .nt{color:#000;font-weight:bold}.chroma .vc{color:#008080}.chroma .vg{color:#008080}.chroma .vi{color:#008080}.chroma .nv{color:#008080}.chroma .va{color:#008080}.chroma .vd{color:#008080}.chroma .ve{color:#008080}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .s{color:#d14}.chroma .sa{color:#d14}.chroma .sb{color:#d14}.chroma .sc{color:#d14}.chroma .dl{color:#d14}.chroma .sd{color:#d14}.chroma .s2{color:#d14}.chroma .se{color:#d14}.chroma .sh{color:#d14}.chroma .si{color:#d14}.chroma .sx{color:#d14}.chroma .sr{color:#d14}.chroma .s1{color:#d14}.chroma .ss{color:#d14}.chroma .m{color:#009999}.chroma .mb{color:#009999}.chroma .mf{color:#009999}.chroma .mh{color:#009999}.chroma .mi{color:#009999}.chroma .mo{color:#009999}.chroma .il{color:#009999}.chroma .c{color:#999988;font-style:italic}.chroma .ch{color:#999988;font-style:italic}.chroma .cm{color:#999988;font-style:italic}.chroma .c1{color:#999988;font-style:italic}.chroma .cs{color:#999988;font-style:italic}.chroma .cp{color:#999988;font-style:italic}.chroma .cpf{color:#999988;font-style:italic}.chroma .gd{color:#000;font-style:italic}.chroma .ge{font-style:italic}.chroma .gr{color:#ff0000}.chroma .gh{color:#999999}.chroma .gi{color:#000;font-style:italic}.chroma .gs{font-weight:bold}.chroma .gu{color:#000;font-style:italic}.chroma .gp{color:#000;font-style:italic}.chroma .go{color:#888888}.chroma .gt{color:#0044dd}.chroma .gd{color:#000;font-style:italic}.chroma .ge{font-style:italic}.chroma .gc{color:#999988;font-style:italic}.chroma .gb{color:#000;font-weight:bold}.chroma .ga{color:#000;font-style:italic}.chroma .gn{color:#000;font-weight:bold}.chroma .gm{color:#000;font-style:italic}.chroma .gp{color:#000;font-style:italic}.chroma .gs{font-weight:bold} .lntd{vertical-align:top;padding:0;margin:0;border:0}.lntable-busy{opacity:.5}.chroma{color:#383a42;background-color:#f6f8fa}.chroma .x{}.chroma .err{color:#a61717;background-color:#e3d2d2}.chroma .lnt{color:#383a42}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable-busy{opacity:.5}.chroma .hl{display:block;width:100%;background-color:#ffdd40}.chroma .lnt{color:#383a42}.chroma .ln{color:#383a42}.chroma .k{color:#000;font-weight:bold}.chroma .kc{color:#000;font-weight:bold}.chroma .kd{color:#000;font-weight:bold}.chroma .kn{color:#000;font-weight:bold}.chroma .kp{color:#000;font-weight:bold}.chroma .kr{color:#000;font-weight:bold}.chroma .kt{color:#445588;font-weight:bold}.chroma .na{color:#008080}.chroma .nb{color:#008080}.chroma .nc{color:#445588;font-weight:bold}.chroma .no{color:#008080}.chroma .nd{color:#3c5d5b;font-weight:bold}.chroma .ni{color:#800080;font-weight:bold}.chroma .ne{color:#800080;font-weight:bold}.chroma .nf{color:#008080}.chroma .nl{color:#008080}.chroma .nn{color:#005580}.chroma .nx{color:#008080}.chroma .nt{color:#000;font-weight:bold}.chroma .vc{color:#008080}.chroma .vg{color:#008080}.chroma .vi{color:#008080}.chroma .nv{color:#008080}.chroma .va{color:#008080}.chroma .vd{color:#008080}.chroma .ve{color:#008080}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .s{color:#d14}.chroma .sa{color:#d14}.chroma .sb{color:#d14}.chroma .sc{color:#d14}.chroma .dl{color:#d14}.chroma .sd{color:#d14}.chroma .s2{color:#d14}.chroma .se{color:#d14}.chroma .sh{color:#d14}.chroma .si{color:#d14}.chroma .sx{color:#d14}.chroma .sr{color:#d14}.chroma .s1{color:#d14}.chroma .ss{color:#d14}.chroma .m{color:#009999}.chroma .mb{color:#009999}.chroma .mf{color:#009999}.chroma .mh{color:#009999}.chroma .mi{color:#009999}.chroma .mo{color:#009999}.chroma .il{color:#009999}.chroma .c{color:#999988;font-style:italic}.chroma .ch{color:#999988;font-style:italic}.chroma .cm{color:#999988;font-style:italic}.chroma .c1{color:#999988;font-style:italic}.chroma .cs{color:#999988;font-style:italic}.chroma .cp{color:#999988;font-style:italic}.chroma .cpf{color:#999988;font-style:italic}.chroma .gd{color:#000;font-style:italic}.chroma .ge{font-style:italic}.chroma .gr{color:#ff0000}.chroma .gh{color:#999999}.chroma .gi{color:#000;font-style:italic}.chroma .gs{font-weight:bold}.chroma .gu{color:#000;font-style:italic}.chroma .gp{color:#000;font-style:italic}.chroma .go{color:#888888}.chroma .gt{color:#0044dd}.chroma .gd{color:#000;font-style:italic}.chroma .ge{font-style:italic}.chroma .gc{color:#999988;font-style:italic}.chroma .gb{color:#000;font-weight:bold}.chroma .ga{color:#000;font-style:italic}.chroma .gn{color:#000;font-weight:bold}.chroma .gm{color:#000;font-style:italic}.chroma .gp{color:#000;font-style:italic}.chroma .gs{font-weight:bold}
</style>` </style>`
func renderPage(w http.ResponseWriter, r *http.Request, title, body string) { func renderPage(w http.ResponseWriter, r *http.Request, title, body string) {
fmt.Fprintf(w, "<html><head><title>%s</title>%s%s</head><body>%s<main>%s</main></body></html>", title, css, chromaCSS, getNavBar(r), body) fmt.Fprintf(w, "<html><head><title>%s</title>%s%s</head><body>%s<main>%s</main></body></html>", title, chromaCSS, css, getNavBar(r), body)
} }
func listHandler(w http.ResponseWriter, r *http.Request) { func listHandler(w http.ResponseWriter, r *http.Request) {