From 74214cad2956e83d5432828c0bd860eacb75ee4d Mon Sep 17 00:00:00 2001 From: Chad Shaw <10213220+chadleeshaw@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:03:23 -0600 Subject: [PATCH 01/16] UI polish: add formatBytes template func and TFTP breadcrumb data --- handlers/common.go | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/handlers/common.go b/handlers/common.go index 6695b72..6a70fd5 100644 --- a/handlers/common.go +++ b/handlers/common.go @@ -8,6 +8,7 @@ import ( "net" "net/http" "os" + "path/filepath" "strings" "sync" @@ -46,6 +47,49 @@ func LoadTemplates() map[string]*template.Template { return templates } +// templateFuncs exposes formatting helpers to every parsed template. +var templateFuncs = template.FuncMap{ + "formatBytes": formatBytes, +} + +// formatBytes renders a byte count as a human-readable string (e.g. "117.7 MB"). +// Non-numeric or negative inputs render as an empty string. +func formatBytes(v any) string { + var b int64 + switch n := v.(type) { + case int: + b = int64(n) + case int8: + b = int64(n) + case int16: + b = int64(n) + case int32: + b = int64(n) + case int64: + b = n + case uint: + b = int64(n) + case uint8: + b = int64(n) + case uint16: + b = int64(n) + case uint32: + b = int64(n) + case uint64: + b = int64(n) + case float32: + b = int64(n) + case float64: + b = int64(n) + default: + return "" + } + if b < 0 { + return "" + } + return humanReadableSize(b) +} + // parseTemplates parses every page/modal template exactly once. // A template that fails to parse is logged and left out of the map — // callers treat a missing entry as "template not available" instead of @@ -75,7 +119,7 @@ func parseTemplates() map[string]*template.Template { parsed := make(map[string]*template.Template, len(files)) for name, paths := range files { - tmpl, err := template.ParseFiles(paths...) + tmpl, err := template.New(filepath.Base(paths[0])).Funcs(templateFuncs).ParseFiles(paths...) if err != nil { log.Printf("Error parsing template %s: %v", name, err) continue From 64defaa8cc421fb3849911000abe11d2905a54af Mon Sep 17 00:00:00 2001 From: Chad Shaw <10213220+chadleeshaw@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:03:34 -0600 Subject: [PATCH 02/16] UI polish: add formatBytes template func and TFTP breadcrumb data --- handlers/tftp.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/handlers/tftp.go b/handlers/tftp.go index 37fb7fe..389bb6b 100644 --- a/handlers/tftp.go +++ b/handlers/tftp.go @@ -294,12 +294,19 @@ type FileInfo struct { IsDir bool } +// Breadcrumb is one segment of the TFTP directory trail shown in the UI. +type Breadcrumb struct { + Name string + Dir string +} + // TFTPData holds information for rendering the TFTP management page type TFTPData struct { Title string ServerRunning bool ServerDirectory string PrevDirectory string + Breadcrumbs []Breadcrumb Files []FileInfo } @@ -360,10 +367,30 @@ func (h *TFTPHandlers) getFileInfo(dir string) (*TFTPData, error) { ServerRunning: isTFTPRunning(), ServerDirectory: relDir, PrevDirectory: removeLastDir(relDir), + Breadcrumbs: buildBreadcrumbs(relDir), Files: fileInfos, }, nil } +// buildBreadcrumbs turns a TFTP-relative directory ("", "a", "a/b") into a +// trail of clickable segments for the file browser UI. +func buildBreadcrumbs(relDir string) []Breadcrumb { + if relDir == "" { + return nil + } + parts := strings.Split(relDir, string(filepath.Separator)) + crumbs := make([]Breadcrumb, 0, len(parts)) + accum := "" + for _, part := range parts { + if accum != "" { + accum += string(filepath.Separator) + } + accum += part + crumbs = append(crumbs, Breadcrumb{Name: part, Dir: accum}) + } + return crumbs +} + // mustAbs returns the absolute form of p, falling back to p itself on error. func mustAbs(p string) string { abs, err := filepath.Abs(p) From 62bef428c192ccf5b9664ac3143ff79ddf176ad1 Mon Sep 17 00:00:00 2001 From: Chad Shaw <10213220+chadleeshaw@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:03:44 -0600 Subject: [PATCH 03/16] UI polish: nav active state, mobile menu behavior, footer, home cards, login password toggle --- templates/base.templ | 72 ++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/templates/base.templ b/templates/base.templ index 7d5e9e6..3959a05 100755 --- a/templates/base.templ +++ b/templates/base.templ @@ -19,18 +19,18 @@