Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3eb944a5a5 | ||
|
|
218a5029fb | ||
|
|
13660e0aa4 | ||
|
|
e215b1d3b6 | ||
|
|
a08b30b02f | ||
|
|
ae0c2639cb | ||
|
|
496dba4281 |
@@ -1,18 +1,15 @@
|
|||||||
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
|
|
||||||
run: docker buildx create --use
|
|
||||||
|
|
||||||
- name: Login to Gitea
|
- name: Login to Gitea
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
@@ -22,10 +19,14 @@ jobs:
|
|||||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
|
|
||||||
- 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/${GITEA_REPOSITORY}/mdhost:latest \
|
# Hier wird die Git-Referenz automatisch als Docker-Tag genutzt
|
||||||
-t gitea.scu.si/${GITEA_REPOSITORY}/mdhost:$GITEA_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
|
||||||
|
|||||||
+3
-2
@@ -11,8 +11,9 @@ RUN go mod download
|
|||||||
# Copy source code
|
# Copy source code
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build statically
|
# Build statically with version
|
||||||
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags='-w -s' -o mdhost .
|
ARG APP_VERSION=dev
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s -X main.version=${APP_VERSION}" -o mdhost .
|
||||||
|
|
||||||
# Final scratch image
|
# Final scratch image
|
||||||
FROM scratch
|
FROM scratch
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
A simple, single-binary Go web application for hosting and sharing markdown files.
|
A simple, single-binary Go web application for hosting and sharing markdown files.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Create, view, edit, and delete** markdown files via web interface
|
- **Create, view, edit, and delete** markdown files via web interface
|
||||||
@@ -119,6 +121,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
|
||||||
@@ -139,7 +143,7 @@ docker run -d \
|
|||||||
-p 8080:8080 \
|
-p 8080:8080 \
|
||||||
-v ~/mdhost-posts:/posts \
|
-v ~/mdhost-posts:/posts \
|
||||||
-v ~/mdhost-data:/data \
|
-v ~/mdhost-data:/data \
|
||||||
mdhost
|
gitea.scu.si/florian.walther/mdhost:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
The application will be available at `http://localhost:8080`.
|
The application will be available at `http://localhost:8080`.
|
||||||
@@ -155,7 +159,8 @@ Create a `docker-compose.yml`:
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
mdhost:
|
mdhost:
|
||||||
build: .
|
image: gitea.scu.si/florian.walther/mdhost:latest
|
||||||
|
# build: .
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -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
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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=
|
||||||
|
|||||||
@@ -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"
|
||||||
)
|
)
|
||||||
@@ -26,6 +27,7 @@ var (
|
|||||||
port = ":8080"
|
port = ":8080"
|
||||||
markdown = newMarkdownRenderer()
|
markdown = newMarkdownRenderer()
|
||||||
dataMu sync.RWMutex
|
dataMu sync.RWMutex
|
||||||
|
version = "dev"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListFormat configures how files are rendered in the index
|
// ListFormat configures how files are rendered in the index
|
||||||
@@ -83,9 +85,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"),
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,9 +471,17 @@ const css = `<style>
|
|||||||
--blockquote-border:#3498db;
|
--blockquote-border:#3498db;
|
||||||
--blockquote-text:#555;
|
--blockquote-text:#555;
|
||||||
--private-color:#95a5a6;
|
--private-color:#95a5a6;
|
||||||
|
--table-border:#ddd;
|
||||||
|
--table-bg:#fafafa;
|
||||||
|
--table-header-bg:#f0f0f0;
|
||||||
|
--table-row-alt:#f5f5f5;
|
||||||
}
|
}
|
||||||
.dark{
|
.dark{
|
||||||
--bg-color:#1e1e1e;
|
--bg-color:#1e1e1e;
|
||||||
|
--table-border:#444;
|
||||||
|
--table-bg:#2a2a2a;
|
||||||
|
--table-header-bg:#333;
|
||||||
|
--table-row-alt:#252525;
|
||||||
--text-color:#e0e0e0;
|
--text-color:#e0e0e0;
|
||||||
--heading-color:#e0e0e0;
|
--heading-color:#e0e0e0;
|
||||||
--nav-bg:#2c3e50;
|
--nav-bg:#2c3e50;
|
||||||
@@ -509,6 +522,11 @@ const css = `<style>
|
|||||||
.markdown-body pre{background:var(--code-bg);padding:1rem;border-radius:4px;overflow-x:auto;color:var(--code-text)}
|
.markdown-body pre{background:var(--code-bg);padding:1rem;border-radius:4px;overflow-x:auto;color:var(--code-text)}
|
||||||
.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 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 var(--blockquote-border);padding-left:1rem;margin-left:0;color:var(--blockquote-text)}
|
.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}
|
||||||
.dark .chroma{color:var(--code-text)!important;background-color:var(--code-bg)!important}
|
.dark .chroma{color:var(--code-text)!important;background-color:var(--code-bg)!important}
|
||||||
.dark .chroma .lnt{color:var(--private-color)!important}
|
.dark .chroma .lnt{color:var(--private-color)!important}
|
||||||
@@ -519,6 +537,9 @@ const css = `<style>
|
|||||||
.edit-link:hover{color:var(--link-color)}
|
.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{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)}
|
#theme-toggle:hover{background:rgba(255,255,255,.1)}
|
||||||
|
footer{position:fixed;bottom:0;left:0;width:100%;background:var(--nav-bg);color:var(--nav-text);padding:.5rem 1rem;display:flex;justify-content:space-between;align-items:center;font-size:.85rem;z-index:100}
|
||||||
|
footer .left{font-weight:600}
|
||||||
|
footer .right{font-family:monospace}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded',function(){
|
document.addEventListener('DOMContentLoaded',function(){
|
||||||
@@ -544,7 +565,8 @@ const chromaCSS = `<style>
|
|||||||
</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, chromaCSS, css, getNavBar(r), body)
|
footer := fmt.Sprintf("<footer><span class='left'>mdhost</span><span class='center'></span><span class='right'>%s</span></footer>", version)
|
||||||
|
fmt.Fprintf(w, "<html><head><title>%s</title>%s%s</head><body>%s<main>%s</main>%s</body></html>", title, chromaCSS, css, getNavBar(r), body, footer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func listHandler(w http.ResponseWriter, r *http.Request) {
|
func listHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -1093,5 +1115,6 @@ func viewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use getNavBar which already includes all links
|
// Use getNavBar which already includes all links
|
||||||
fmt.Fprintf(w, "<html><head><title>%s</title>%s%s</head><body>%s<main><div class='markdown-body'>%s</div></main></body></html>", entry.Name, css, chromaCSS, getNavBar(r), buf.String())
|
footer := fmt.Sprintf("<footer><span class='left'>mdhost</span><span class='center'></span><span class='right'>%s</span></footer>", version)
|
||||||
|
fmt.Fprintf(w, "<html><head><title>%s</title>%s%s</head><body>%s<main><div class='markdown-body'>%s</div></main>%s</body></html>", entry.Name, css, chromaCSS, getNavBar(r), buf.String(), footer)
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
Reference in New Issue
Block a user