diff --git a/internal/web/files.go b/internal/web/files.go
index 91b35b8..c33920b 100644
--- a/internal/web/files.go
+++ b/internal/web/files.go
@@ -211,6 +211,16 @@ func (s *Server) handleFilesGet(w http.ResponseWriter, r *http.Request, username
return
}
+ // Determine sort order (name asc/desc) from query param, default to asc
+ sortBy := r.URL.Query().Get("sort_by")
+ sortDir := r.URL.Query().Get("sort_dir")
+ if sortBy == "" {
+ sortBy = "name"
+ }
+ if sortDir == "" {
+ sortDir = "asc"
+ }
+
// os.ReadDir already returns entries sorted by filename, so filtering
// into two passes keeps each group (directories, then files)
// alphabetically sorted while grouping directories first.
@@ -234,6 +244,40 @@ func (s *Server) handleFilesGet(w http.ResponseWriter, r *http.Request, username
files = append(files, entry)
}
}
+
+ // Sort entries based on sortBy and sortDir
+ less := func(i, j templates.FileEntry) bool {
+ switch sortBy {
+ case "name":
+ if sortDir == "desc" {
+ return i.Name > j.Name
+ }
+ return i.Name < j.Name
+ default:
+ if sortDir == "desc" {
+ return i.ModTime > j.ModTime
+ }
+ return i.ModTime < j.ModTime
+ }
+ }
+
+ // Sort dirs
+ for i := 0; i < len(dirs)-1; i++ {
+ for j := i + 1; j < len(dirs); j++ {
+ if less(dirs[j], dirs[i]) {
+ dirs[i], dirs[j] = dirs[j], dirs[i]
+ }
+ }
+ }
+ // Sort files
+ for i := 0; i < len(files)-1; i++ {
+ for j := i + 1; j < len(files); j++ {
+ if less(files[j], files[i]) {
+ files[i], files[j] = files[j], files[i]
+ }
+ }
+ }
+
entries := append(dirs, files...)
var breadcrumbs []templates.Breadcrumb
@@ -248,7 +292,7 @@ func (s *Server) handleFilesGet(w http.ResponseWriter, r *http.Request, username
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
- _ = templates.FilesPage(username, breadcrumbs, entries, relPath).Render(context.Background(), w)
+ _ = templates.FilesPage(username, breadcrumbs, entries, relPath, sortBy, sortDir).Render(context.Background(), w)
}
func (s *Server) handleFilesUpload(w http.ResponseWriter, r *http.Request, root, fullPath string) {
diff --git a/internal/web/templates/files.templ b/internal/web/templates/files.templ
index ec0c99e..da3d9a8 100644
--- a/internal/web/templates/files.templ
+++ b/internal/web/templates/files.templ
@@ -16,7 +16,7 @@ type FileEntry struct {
RelPath string // relative path (no leading slash) used to build the link
}
-templ FilesPage(username string, breadcrumbs []Breadcrumb, entries []FileEntry, currentPath string) {
+templ FilesPage(username string, breadcrumbs []Breadcrumb, entries []FileEntry, currentPath string, sortBy string, sortDir string) {
@Layout("Files", username) {
Files
@@ -33,6 +33,10 @@ templ FilesPage(username string, breadcrumbs []Breadcrumb, entries []FileEntry,
Upload folder
+
@@ -48,6 +52,8 @@ templ FilesPage(username string, breadcrumbs []Breadcrumb, entries []FileEntry,
id="file-drop-zone"
data-current-path={ currentPath }
data-upload-url={ "/web/files/" + currentPath }
+ data-sort-by={ sortBy }
+ data-sort-dir={ sortDir }
class="bg-white rounded-lg border-2 border-dashed border-gray-200 p-2 transition-colors"
>
@@ -60,9 +66,29 @@ templ FilesPage(username string, breadcrumbs []Breadcrumb, entries []FileEntry,
- | Name |
+
+ if sortBy == "name" {
+ if sortDir == "asc" {
+ Name ↓
+ } else {
+ Name ↑
+ }
+ } else {
+ Name
+ }
+ |
Size |
- Modified |
+
+ if sortBy == "modtime" {
+ if sortDir == "asc" {
+ Modified ↓
+ } else {
+ Modified ↑
+ }
+ } else {
+ Modified
+ }
+ |
|
@@ -163,4 +189,3 @@ templ fileDeleteButton(e FileEntry) {
Delete
}
-
diff --git a/internal/web/templates/files_templ.go b/internal/web/templates/files_templ.go
index bb4eaaf..f036127 100644
--- a/internal/web/templates/files_templ.go
+++ b/internal/web/templates/files_templ.go
@@ -24,7 +24,7 @@ type FileEntry struct {
RelPath string // relative path (no leading slash) used to build the link
}
-func FilesPage(username string, breadcrumbs []Breadcrumb, entries []FileEntry, currentPath string) templ.Component {
+func FilesPage(username string, breadcrumbs []Breadcrumb, entries []FileEntry, currentPath string, sortBy string, sortDir string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -57,176 +57,276 @@ func FilesPage(username string, breadcrumbs []Breadcrumb, entries []FileEntry, c
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "