From f9cfd3fc3bf078ae0018fc9405b801cb2b090a1d Mon Sep 17 00:00:00 2001 From: visionmercer <62051836+visionmercer@users.noreply.github.com> Date: Wed, 15 Apr 2026 09:08:14 +0200 Subject: [PATCH] moved html and css out to seperate files. --- internal/handlers/handlers.go | 188 +++++++++++----------------------- main.go | 1 + static/css/style.css | 24 +++++ templates/browse.html | 27 +++++ templates/index.html | 38 +++++++ 5 files changed, 152 insertions(+), 126 deletions(-) create mode 100644 static/css/style.css create mode 100644 templates/browse.html create mode 100644 templates/index.html diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index 301802a..6cd7ff8 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -17,8 +17,9 @@ import ( ) type Handler struct { - dir string - tmpl *template.Template + dir string + tmpl *template.Template + staticFS http.FileSystem } // breadcrumb represents a link in the navigation chain @@ -29,6 +30,7 @@ type breadcrumb struct { func New(dir string) *Handler { h := &Handler{dir: dir} + h.staticFS = http.FS(os.DirFS("static")) h.tmpl = template.Must( template.New("").Funcs(template.FuncMap{ "humanSize": humanSize, @@ -37,7 +39,7 @@ func New(dir string) *Handler { "base": filepath.Base, "add1": func(i int) int { return i + 1 }, "trimExt": func(s string) string { return strings.TrimSuffix(s, filepath.Ext(s)) }, - }).Parse(allTemplates), + }).ParseGlob("templates/*.html"), ) return h } @@ -74,9 +76,9 @@ func (h *Handler) ListISOs(w http.ResponseWriter, r *http.Request) { name := e.Name() relPath := filepath.ToSlash(filepath.Join(relDir, name)) info, _ := e.Info() - + isISO := !e.IsDir() && strings.EqualFold(filepath.Ext(name), ".iso") - + item := libraryEntry{ Name: name, RelativePath: relPath, @@ -106,11 +108,13 @@ func (h *Handler) ListISOs(w http.ResponseWriter, r *http.Request) { } sort.Slice(items, func(i, j int) bool { - if items[i].IsDir != items[j].IsDir { return items[i].IsDir } + if items[i].IsDir != items[j].IsDir { + return items[i].IsDir + } return strings.ToLower(items[i].Name) < strings.ToLower(items[j].Name) }) - h.tmpl.ExecuteTemplate(w, "index", map[string]any{ + h.tmpl.ExecuteTemplate(w, "index.html", map[string]any{ "Title": "ISO Library", "Items": items, "CurrentPath": relDir, @@ -139,11 +143,13 @@ func (h *Handler) BrowseISO(w http.ResponseWriter, r *http.Request) { } sort.Slice(entries, func(i, j int) bool { - if entries[i].IsDir != entries[j].IsDir { return entries[i].IsDir } + if entries[i].IsDir != entries[j].IsDir { + return entries[i].IsDir + } return strings.ToLower(entries[i].Name) < strings.ToLower(entries[j].Name) }) - h.tmpl.ExecuteTemplate(w, "browse", map[string]any{ + h.tmpl.ExecuteTemplate(w, "browse.html", map[string]any{ "Title": filepath.Base(isoPath), "ISOName": isoPath, "InternalPath": internalPath, @@ -176,7 +182,9 @@ func (h *Handler) DownloadFile(w http.ResponseWriter, r *http.Request) { filename := filepath.Base(internalPath) ext := strings.ToLower(filepath.Ext(filename)) ct := mime.TypeByExtension(ext) - if ct == "" { ct = "application/octet-stream" } + if ct == "" { + ct = "application/octet-stream" + } viewable := false switch ext { @@ -200,6 +208,10 @@ func (h *Handler) RawFile(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, filepath.Join(h.dir, fileName)) } +func (h *Handler) ServeStatic(w http.ResponseWriter, r *http.Request) { + http.StripPrefix("/static/", http.FileServer(h.staticFS)).ServeHTTP(w, r) +} + func (h *Handler) openISO(relPath string) (*iso.Reader, error) { return iso.Open(filepath.Join(h.dir, relPath)) } @@ -209,17 +221,27 @@ func parsePath(urlPath, prefix string) (isoPath, internalPath string, ok bool) { decoded, _ := url.PathUnescape(rest) lower := strings.ToLower(decoded) idx := strings.Index(lower, ".iso") - if idx == -1 { return decoded, "", true } + if idx == -1 { + return decoded, "", true + } return decoded[:idx+4], strings.TrimPrefix(decoded[idx+4:], "/"), true } func buildLibraryBreadcrumbs(relDir string) []breadcrumb { crumbs := []breadcrumb{{Name: "Library", URL: "/"}} - if relDir == "" { return crumbs } + if relDir == "" { + return crumbs + } acc := "" for _, p := range strings.Split(relDir, "/") { - if p == "" { continue } - if acc == "" { acc = p } else { acc = filepath.Join(acc, p) } + if p == "" { + continue + } + if acc == "" { + acc = p + } else { + acc = filepath.Join(acc, p) + } crumbs = append(crumbs, breadcrumb{Name: p, URL: "/" + filepath.ToSlash(acc)}) } return crumbs @@ -233,13 +255,19 @@ func buildISOBreadcrumbs(isoPath, internalPath string) []breadcrumb { } else { crumbs = buildLibraryBreadcrumbs(parentDir) } - + crumbs = append(crumbs, breadcrumb{Name: filepath.Base(isoPath), URL: "/browse/" + url.PathEscape(isoPath)}) if internalPath != "" { acc := "" for _, p := range strings.Split(internalPath, "/") { - if p == "" { continue } - if acc == "" { acc = p } else { acc += "/" + p } + if p == "" { + continue + } + if acc == "" { + acc = p + } else { + acc += "/" + p + } crumbs = append(crumbs, breadcrumb{Name: p, URL: "/browse/" + url.PathEscape(isoPath) + "/" + acc}) } } @@ -247,121 +275,29 @@ func buildISOBreadcrumbs(isoPath, internalPath string) []breadcrumb { } func humanSize(n int64) string { - if n < 1024 { return fmt.Sprintf("%d B", n) } + if n < 1024 { + return fmt.Sprintf("%d B", n) + } div, exp := int64(1024), 0 - for v := n / 1024; v >= 1024; v /= 1024 { div *= 1024; exp++ } + for v := n / 1024; v >= 1024; v /= 1024 { + div *= 1024 + exp++ + } return fmt.Sprintf("%.1f %cB", float64(n)/float64(div), "KMGTPE"[exp]) } func fileIcon(name string) string { ext := strings.ToLower(filepath.Ext(name)) switch ext { - case ".iso": return "💿" - case ".pdf": return "📄" - case ".jpg", ".png", ".jpeg": return "🖼️" - case ".txt", ".md": return "📝" - default: return "📄" + case ".iso": + return "💿" + case ".pdf": + return "📄" + case ".jpg", ".png", ".jpeg": + return "🖼️" + case ".txt", ".md": + return "📝" + default: + return "📄" } } - -const allTemplates = ` -{{define "css"}} - -{{end}} - -{{define "index"}} - - -{{.Title}}{{template "css" .}} - -
-
- - -
- {{range .Items}} - {{if .IsDir}} - -
📁
-
{{.Name}}
-
- {{else}} -
- - {{if .HasImage}} - {{else}}
💿
{{end}} -
-
- {{.Name}} -

{{if .Description}}{{.Description}}{{else}}ISO Disk Image{{end}}

-
- Browse - ISO -
-
-
- {{end}} - {{end}} -
-
- - -{{end}} - -{{define "browse"}} - - -{{.Title}}{{template "css" .}} - -
-
- - - - - {{range .Entries}} - - - - - - {{end}} - -
NameSizeAction
- {{if .IsDir}}📁 {{.Name}} - {{else}}{{fileIcon .Name}} {{.Name}}{{end}} - {{if .IsDir}}—{{else}}{{humanSize .Size}}{{end}}{{if not .IsDir}}Download{{end}}
-
- - -{{end}} -` diff --git a/main.go b/main.go index 0f37527..b5ed82f 100644 --- a/main.go +++ b/main.go @@ -25,6 +25,7 @@ func main() { mux.HandleFunc("/browse/", h.BrowseISO) mux.HandleFunc("/file/", h.DownloadFile) mux.HandleFunc("/raw/", h.RawFile) + mux.HandleFunc("/static/", h.ServeStatic) mux.HandleFunc("/", h.ListISOs) fmt.Printf("ISOSilo running at %s\n", *addr) diff --git a/static/css/style.css b/static/css/style.css new file mode 100644 index 0000000..9027afd --- /dev/null +++ b/static/css/style.css @@ -0,0 +1,24 @@ +:root { + --bg: #0f1117; --surface: #1a1d27; --border: #252836; + --accent: #4f8ef7; --text: #e2e4ef; --muted: #6b7090; --radius: 8px; +} +body { background: var(--bg); color: var(--text); font-family: system-ui; margin: 0; } +header { background: #12151f; border-bottom: 1px solid var(--border); padding: 0 2rem; height: 56px; display: flex; align-items: center; } +.logo { color: var(--accent); font-weight: bold; text-decoration: none; font-family: monospace; } +main { max-width: 1100px; margin: 0 auto; padding: 2rem; } +.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1.5rem; } +.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; display: flex; flex-direction: column; text-decoration: none; color: inherit; transition: transform 0.1s; position: relative;} +.card:hover { transform: translateY(-3px); border-color: var(--accent); } +.card-img { width: 100%; height: 150px; object-fit: cover; background: #000; } +.folder-icon { height: 150px; display: flex; align-items: center; justify-content: center; font-size: 4rem; background: #1c202d; color: #f7c948; } +.iso-icon { height: 150px; display: flex; align-items: center; justify-content: center; font-size: 4rem; background: #12151f; } +.card-body { padding: 1rem; } +.card-name { font-weight: bold; color: var(--accent); margin-bottom: 0.5rem; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.card-desc { font-size: 0.8rem; color: var(--muted); height: 3em; overflow: hidden; } +.bc { background: var(--surface); padding: 0.6rem 1rem; border-radius: 4px; margin-bottom: 1.5rem; font-size: 0.85rem; } +.bc a { color: var(--accent); text-decoration: none; } +.tbl { width: 100%; border-collapse: collapse; background: var(--surface); border-radius: var(--radius); overflow: hidden; } +.tbl th { text-align: left; padding: 1rem; background: #1e2132; color: var(--muted); font-size: 0.75rem; } +.tbl td { padding: 1rem; border-bottom: 1px solid var(--border); } +.dl-btn { border: 1px solid var(--accent); color: var(--accent); padding: 0.2rem 0.5rem; border-radius: 4px; font-size: 0.7rem; text-decoration: none; } +.dl-btn:hover { background: var(--accent); color: #fff; } diff --git a/templates/browse.html b/templates/browse.html new file mode 100644 index 0000000..297df03 --- /dev/null +++ b/templates/browse.html @@ -0,0 +1,27 @@ + + +{{.Title}} + +
+
+ + + + + {{range .Entries}} + + + + + + {{end}} + +
NameSizeAction
+ {{if .IsDir}}📁 {{.Name}} + {{else}}{{fileIcon .Name}} {{.Name}}{{end}} + {{if .IsDir}}—{{else}}{{humanSize .Size}}{{end}}{{if not .IsDir}}Download{{end}}
+
+ + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..391d1a8 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,38 @@ + + +{{.Title}} + +
+
+ + +
+ {{range .Items}} + {{if .IsDir}} + +
📁
+
{{.Name}}
+
+ {{else}} +
+ + {{if .HasImage}} + {{else}}
💿
{{end}} +
+
+ {{.Name}} +

{{if .Description}}{{.Description}}{{else}}ISO Disk Image{{end}}

+
+ Browse + ISO +
+
+
+ {{end}} + {{end}} +
+
+ +