commit 64817f9e40e7496fde07edd24d911b15ad41b685
parent 47ba205af44ff590f48935478dea74c436e1f040
Author: breadcat <breadcat@users.noreply.github.com>
Date: Tue, 7 Apr 2026 10:41:25 +0100
Preserve view mode while navigating
Diffstat:
| M | main.go | | | 53 | ++++++++++++++++++++++++++++++++++++----------------- |
1 file changed, 36 insertions(+), 17 deletions(-)
diff --git a/main.go b/main.go
@@ -47,6 +47,7 @@ type PageData struct {
Breadcrumbs []Breadcrumb
Files []FileEntry
TreeJSON template.JS
+ View string
}
const tmpl = `<!DOCTYPE html>
@@ -123,13 +124,13 @@ header{border-bottom:1px solid #333;padding:10px 16px;display:flex;align-items:c
{{ if eq $i (sub1 (len $.Breadcrumbs)) }}
<span class="current">{{ $crumb.Name }}</span>
{{ else }}
- <a href="{{ $crumb.Path }}">{{ $crumb.Name }}</a>
+ <a href="{{ viewSuffix $.View $crumb.Path }}">{{ $crumb.Name }}</a>
{{ end }}
{{ end }}
</div>
<div class="view-toggle">
- <button id="btn-list" class="active" onclick="setView('list')">☰ List</button>
- <button id="btn-thumb" onclick="setView('thumb')">▦ Thumbs</button>
+ <button id="btn-list" class="{{ if eq .View "list" }}active{{ end }}" onclick="setView('list')">☰ List</button>
+ <button id="btn-thumb" class="{{ if eq .View "thumb" }}active{{ end }}" onclick="setView('thumb')">▦ Thumbs</button>
</div>
</header>
@@ -140,7 +141,7 @@ header{border-bottom:1px solid #333;padding:10px 16px;display:flex;align-items:c
</nav>
<main class="main">
- <div id="view-list">
+ <div id="view-list"{{ if eq .View "thumb" }} style="display:none"{{ end }}>
{{ if .Files }}
<table class="file-table" id="file-table">
<thead>
@@ -153,7 +154,7 @@ header{border-bottom:1px solid #333;padding:10px 16px;display:flex;align-items:c
<tbody>
{{ if ne .CurrentPath "/" }}
<tr>
- <td class="name"><span class="file-icon dir">📁</span><a href="../">../</a></td>
+ <td class="name"><span class="file-icon dir">📁</span><a href="{{ viewSuffix $.View "../" }}">../</a></td>
<td class="size">—</td>
<td class="date">—</td>
</tr>
@@ -162,7 +163,7 @@ header{border-bottom:1px solid #333;padding:10px 16px;display:flex;align-items:c
<tr data-name="{{ .Name }}" data-size="{{ .Size }}" data-date="{{ .ModTime.Unix }}">
<td class="name">
{{ if .IsDir }}
- <span class="file-icon dir">📁</span><a href="{{ .Path }}">{{ .Name }}/</a>
+ <span class="file-icon dir">📁</span><a href="{{ viewSuffix $.View .Path }}">{{ .Name }}/</a>
{{ else if isImage .Ext }}
<span class="file-icon img">📷</span><a href="{{ .Path }}">{{ .Name }}</a>
{{ else }}
@@ -180,12 +181,12 @@ header{border-bottom:1px solid #333;padding:10px 16px;display:flex;align-items:c
{{ end }}
</div>
- <div id="view-thumb" style="display:none">
+ <div id="view-thumb"{{ if eq .View "list" }} style="display:none"{{ end }}>
{{ if .Files }}
<div class="thumb-grid">
{{ if ne .CurrentPath "/" }}
<div class="thumb-item">
- <a href="../" style="display:block">
+ <a href="{{ viewSuffix $.View "../" }}" style="display:block">
<div class="thumb-preview"><span class="big-icon dir-icon">↑</span></div>
<div class="thumb-label">../</div>
</a>
@@ -193,7 +194,7 @@ header{border-bottom:1px solid #333;padding:10px 16px;display:flex;align-items:c
{{ end }}
{{ range .Files }}
<div class="thumb-item">
- <a href="{{ .Path }}" style="display:block">
+ <a href="{{ if .IsDir }}{{ viewSuffix $.View .Path }}{{ else }}{{ .Path }}{{ end }}" style="display:block">
<div class="thumb-preview">
{{ if .IsDir }}
<span class="big-icon dir-icon">📁</span>
@@ -220,14 +221,16 @@ header{border-bottom:1px solid #333;padding:10px 16px;display:flex;align-items:c
<script>
const TREE_DATA = {{ .TreeJSON }};
-const CURRENT_PATH = {{ printf "%q" .CurrentPath }};
+const CURRENT_PATH = '{{ .CurrentPath }}';
+const VIEW = '{{ .View }}';
function setView(v) {
- const isList = v === 'list';
- document.getElementById('view-list').style.display = isList ? '' : 'none';
- document.getElementById('view-thumb').style.display = isList ? 'none' : '';
- document.getElementById('btn-list').className = isList ? 'active' : '';
- document.getElementById('btn-thumb').className = isList ? '' : 'active';
+ if (v === VIEW) return;
+ window.location.href = v === 'thumb' ? window.location.pathname + '?v=thumb' : window.location.pathname;
+}
+
+function viewHref(path) {
+ return VIEW === 'thumb' ? path + '?v=thumb' : path;
}
let sortCol = -1, sortDir = 1;
@@ -293,7 +296,7 @@ function buildTree(nodes, container, depth) {
});
}
- item.addEventListener('click', () => { window.location.href = node.path; });
+ item.addEventListener('click', () => { window.location.href = viewHref(node.path); });
if (CURRENT_PATH.startsWith(node.path) && childUl) {
childUl.classList.add('open');
@@ -364,7 +367,11 @@ func listingHandler(w http.ResponseWriter, r *http.Request) {
}
if !strings.HasSuffix(r.URL.Path, "/") {
- http.Redirect(w, r, r.URL.Path+"/", http.StatusMovedPermanently)
+ redir := r.URL.Path + "/"
+ if v := r.URL.Query().Get("v"); v == "thumb" {
+ redir += "?v=thumb"
+ }
+ http.Redirect(w, r, redir, http.StatusMovedPermanently)
return
}
@@ -412,11 +419,17 @@ func listingHandler(w http.ResponseWriter, r *http.Request) {
tree := buildTree(rootDir, "/")
treeBytes, _ := json.Marshal(tree)
+ view := r.URL.Query().Get("v")
+ if view != "thumb" {
+ view = "list"
+ }
+
data := PageData{
CurrentPath: urlPath,
Breadcrumbs: buildBreadcrumbs(urlPath),
Files: files,
TreeJSON: template.JS(treeBytes),
+ View: view,
}
funcMap := template.FuncMap{
@@ -424,6 +437,12 @@ func listingHandler(w http.ResponseWriter, r *http.Request) {
"formatTime": func(t time.Time) string { return t.Format("2006-01-02 15:04") },
"isImage": isImageExt,
"sub1": func(n int) int { return n - 1 },
+ "viewSuffix": func(view, path string) string {
+ if view == "thumb" {
+ return path + "?v=thumb"
+ }
+ return path
+ },
}
t, err := template.New("page").Funcs(funcMap).Parse(tmpl)