cmd/pkgserver: basic web ui

This commit is contained in:
mae
2026-03-04 22:50:58 -06:00
parent 7e2f13fa1b
commit f93158cb3c
15 changed files with 231 additions and 0 deletions

55
cmd/pkgserver/main.go Normal file
View File

@@ -0,0 +1,55 @@
package main
import (
"embed"
"fmt"
"net/http"
)
//go:generate sh -c "sass ui/static/dark.scss ui/static/dark.css && sass ui/static/light.scss ui/static/light.css && tsc ui/static/index.ts"
//go:embed ui/*
var content embed.FS
func serveWebUI(w http.ResponseWriter, r *http.Request) {
fmt.Printf("serveWebUI: %s\n", r.URL.Path)
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Pragma", "no-cache")
w.Header().Set("Expires", "0")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-XSS-Protection", "1")
w.Header().Set("X-Frame-Options", "DENY")
http.ServeFileFS(w, r, content, "ui/index.html")
}
func serveStaticContent(w http.ResponseWriter, r *http.Request) {
fmt.Printf("serveStaticContent: %s\n", r.URL.Path)
switch r.URL.Path {
case "/static/style.css":
darkTheme := r.CookiesNamed("dark_theme")
if len(darkTheme) > 0 && darkTheme[0].Value == "true" {
http.ServeFileFS(w, r, content, "ui/static/dark.css")
} else {
http.ServeFileFS(w, r, content, "ui/static/light.css")
}
break
case "/favicon.ico":
http.ServeFileFS(w, r, content, "ui/static/favicon.ico")
break
case "/static/index.js":
http.ServeFileFS(w, r, content, "ui/static/index.js")
break
default:
http.NotFound(w, r)
}
}
func serveAPI(w http.ResponseWriter, r *http.Request) {
}
func main() {
http.HandleFunc("GET /{$}", serveWebUI)
http.HandleFunc("GET /favicon.ico", serveStaticContent)
http.HandleFunc("GET /static/", serveStaticContent)
http.HandleFunc("GET /api/", serveAPI)
http.ListenAndServe(":8067", nil)
}

View File

@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="static/style.css">
<title>Hakurei PkgServer</title>
<script src="static/index.js"></script>
</head>
<body>
<h1>Hakurei PkgServer</h1>
<span><label for="count">Entries per page:</label><select name="count" id="count">
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select></span>
<table id="pkg-list">
<tr><th>Status</th><th>Name</th><th>Version</th></tr>
</table>
<p>Showing entries <span id="entry-counter"></span>.</p>
<span class="bottom-nav"><a href="javascript:prevPage()">&laquo; Previous</a><span id="page-number"></span><a href="javascript:nextPage">Next &raquo;</a></span>
</body>
</html>

View File

View File

@@ -0,0 +1,6 @@
@use 'common';
html {
background-color: #2c2c2c;
color: ghostwhite; }
/*# sourceMappingURL=dark.css.map */

View File

@@ -0,0 +1,7 @@
{
"version": 3,
"mappings": "AAAA,aAAa;AAEb,IAAK;EACH,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,UAAU",
"sources": ["dark.scss"],
"names": [],
"file": "dark.css"
}

View File

@@ -0,0 +1,6 @@
@use 'common';
html {
background-color: #2c2c2c;
color: ghostwhite;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,4 @@
function prevPage() {
}
function nextPage() {
}

View File

@@ -0,0 +1,6 @@
function prevPage() {
}
function nextPage() {
}

View File

@@ -0,0 +1,6 @@
@use 'common';
html {
background-color: #d3d3d3;
color: black; }
/*# sourceMappingURL=light.css.map */

View File

@@ -0,0 +1,7 @@
{
"version": 3,
"mappings": "AAAA,aAAa;AAEb,IAAK;EACH,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,KAAK",
"sources": ["light.scss"],
"names": [],
"file": "light.css"
}

View File

@@ -0,0 +1,6 @@
@use 'common';
html {
background-color: #d3d3d3;
color: black;
}