feat(admin): /admin/media upload page — browser upload to Garage via minio-go, {{media:...}} snippet

This commit is contained in:
sam
2026-09-10 07:23:44 +10:00
parent dd029c8819
commit 423901c80d
2 changed files with 41 additions and 0 deletions

View File

@@ -9,6 +9,8 @@ import (
"mime"
"net/http"
"os"
"github.com/a-h/templ"
)
// bundled static assets + admin UI (served under /web/)
@@ -47,6 +49,9 @@ func main() {
http.HandleFunc("/admin/media/upload", func(w http.ResponseWriter, r *http.Request) {
s.mediaUpload(w, r)
})
http.HandleFunc("/admin/media", func(w http.ResponseWriter, r *http.Request) {
templ.Handler(AdminMediaPage()).ServeHTTP(w, r)
})
http.HandleFunc("/subjects/{slug}", func(w http.ResponseWriter, r *http.Request) {
s.subject(w, r, r.PathValue("slug"))
})

View File

@@ -300,3 +300,39 @@ templ AdminRedirect() {
<!DOCTYPE html>
<html><head><meta http-equiv="refresh" content="0; url=/admin/"/></head><body></body></html>
}
// AdminMediaPage is a browser-based media uploader that posts to
// /admin/media/upload (which stores into Garage S3 via minio-go) and
// returns the {{media:...}} snippet to paste into an article.
templ AdminMediaPage() {
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Kontra — Media Library</title>
<link rel="stylesheet" href="/web/assets/kontra.css"/>
</head>
<body class="admin-body">
<header class="masthead"><div class="container">
<div class="brand-row"><div aria-hidden="true"></div>
<div class="brand"><a href="/" class="display-masthead">Kontra</a></div>
<div class="brand-tools"><a href="/admin" class="nav-link">CMS</a></div>
</div>
</div></header>
<main class="container">
<section style="padding:24px 0;">
<h1 class="headline-lg" style="color:var(--ink);">Media Library</h1>
<div class="body-sm" style="color:var(--ink-muted);margin:8px 0 16px;">
Upload an image — it is stored in Garage S3 and served at <b>/media/&lt;file&gt;</b>.
A &#123;&#123;media:...&#125;&#125; snippet is shown to paste into an article.
</div>
<form method="post" action="/admin/media/upload" enctype="multipart/form-data" class="newsletter-card">
<input class="field" type="file" name="file" required/>
<button class="btn-primary" type="submit">Upload</button>
</form>
</section>
</main>
</body>
</html>
}