commit 0361107ddaba8f72092f706558f6b94f2ef80f18
parent f32568d1a2384824c64910a7bc3565c9be9a0432
Author: breadcat <breadcat@users.noreply.github.com>
Date: Tue, 7 Oct 2025 18:13:51 +0100
Pagination improvements
Add pagination to tag filter pages
Add first/last buttons
Add manual navigation jump input
Diffstat:
4 files changed, 104 insertions(+), 41 deletions(-)
diff --git a/main.go b/main.go
@@ -869,6 +869,23 @@ func tagsHandler(w http.ResponseWriter, r *http.Request) {
}
func tagFilterHandler(w http.ResponseWriter, r *http.Request) {
+ // Get page number from query params
+ pageStr := r.URL.Query().Get("page")
+ page := 1
+ if pageStr != "" {
+ if p, err := strconv.Atoi(pageStr); err == nil && p > 0 {
+ page = p
+ }
+ }
+
+ // Get per page from config
+ perPage := 50
+ if config.ItemsPerPage != "" {
+ if pp, err := strconv.Atoi(config.ItemsPerPage); err == nil && pp > 0 {
+ perPage = pp
+ }
+ }
+
// Split by /and/tag/ to get individual tag pairs
fullPath := strings.TrimPrefix(r.URL.Path, "/tag/")
tagPairs := strings.Split(fullPath, "/and/tag/")
@@ -888,6 +905,42 @@ func tagFilterHandler(w http.ResponseWriter, r *http.Request) {
filters = append(filters, filter{parts[0], parts[1]})
}
+ // Build count query first
+ countQuery := `SELECT COUNT(DISTINCT f.id) FROM files f WHERE 1=1`
+ countArgs := []interface{}{}
+ for _, f := range filters {
+ if f.Value == "unassigned" {
+ countQuery += `
+ AND NOT EXISTS (
+ SELECT 1
+ FROM file_tags ft
+ JOIN tags t ON ft.tag_id = t.id
+ JOIN categories c ON c.id = t.category_id
+ WHERE ft.file_id = f.id AND c.name = ?
+ )`
+ countArgs = append(countArgs, f.Category)
+ } else {
+ countQuery += `
+ AND EXISTS (
+ SELECT 1
+ FROM file_tags ft
+ JOIN tags t ON ft.tag_id = t.id
+ JOIN categories c ON c.id = t.category_id
+ WHERE ft.file_id = f.id AND c.name = ? AND t.value = ?
+ )`
+ countArgs = append(countArgs, f.Category, f.Value)
+ }
+ }
+
+ // Get total count
+ var total int
+ err := db.QueryRow(countQuery, countArgs...).Scan(&total)
+ if err != nil {
+ renderError(w, "Failed to count files", http.StatusInternalServerError)
+ return
+ }
+
+ // Build main query with pagination
query := `SELECT f.id, f.filename, f.path, COALESCE(f.description, '') as description FROM files f WHERE 1=1`
args := []interface{}{}
for _, f := range filters {
@@ -914,7 +967,16 @@ func tagFilterHandler(w http.ResponseWriter, r *http.Request) {
}
}
- files, _ := queryFilesWithTags(query, args...)
+ // Add pagination
+ offset := (page - 1) * perPage
+ query += ` ORDER BY f.id DESC LIMIT ? OFFSET ?`
+ args = append(args, perPage, offset)
+
+ files, err := queryFilesWithTags(query, args...)
+ if err != nil {
+ renderError(w, "Failed to fetch files", http.StatusInternalServerError)
+ return
+ }
var titleParts []string
for _, f := range filters {
@@ -922,10 +984,10 @@ func tagFilterHandler(w http.ResponseWriter, r *http.Request) {
}
title := "Tagged: " + strings.Join(titleParts, ", ")
- pageData := buildPageData(title, struct {
+ pageData := buildPageDataWithPagination(title, struct {
Tagged []File
Untagged []File
- }{files, nil})
+ }{files, nil}, page, total, perPage)
renderTemplate(w, "list.html", pageData)
}
diff --git a/templates/_pagination.html b/templates/_pagination.html
@@ -0,0 +1,36 @@
+{{define "_pagination"}}
+
+{{if .Pagination}}
+{{if gt .Pagination.TotalPages 1}}
+<div class="pagination">
+ {{if .Pagination.HasPrev}}
+ <a href="?page=1">«« First</a>
+ <a href="?page={{.Pagination.PrevPage}}">« Previous</a>
+ {{else}}
+ <span class="disabled">«« First</span>
+ <span class="disabled">« Previous</span>
+ {{end}}
+
+ <span class="page-info">
+ Page
+ <input type="number"
+ id="pageInput"
+ value="{{.Pagination.CurrentPage}}"
+ min="1"
+ max="{{.Pagination.TotalPages}}"
+ style="width: 60px; text-align: center;"
+ onkeypress="if(event.key === 'Enter') { var page = parseInt(this.value); if(page >= 1 && page <= {{.Pagination.TotalPages}}) { window.location.href = '?page=' + page; } }">
+ of {{.Pagination.TotalPages}}
+ </span>
+
+ {{if .Pagination.HasNext}}
+ <a href="?page={{.Pagination.NextPage}}">Next »</a>
+ <a href="?page={{.Pagination.TotalPages}}">Last »»</a>
+ {{else}}
+ <span class="disabled">Next »</span>
+ <span class="disabled">Last »»</span>
+ {{end}}
+</div>
+{{end}}
+{{end}}
+{{end}}
+\ No newline at end of file
diff --git a/templates/list.html b/templates/list.html
@@ -23,24 +23,6 @@
</div>
{{end}}
-{{if .Pagination}}
-{{if gt .Pagination.TotalPages 1}}
-<div class="pagination">
- {{if .Pagination.HasPrev}}
- <a href="?page={{.Pagination.PrevPage}}">« Previous</a>
- {{else}}
- <span class="disabled">« Previous</span>
- {{end}}
-
- <span class="page-info">Page {{.Pagination.CurrentPage}} of {{.Pagination.TotalPages}}</span>
-
- {{if .Pagination.HasNext}}
- <a href="?page={{.Pagination.NextPage}}">Next »</a>
- {{else}}
- <span class="disabled">Next »</span>
- {{end}}
-</div>
-{{end}}
-{{end}}
+{{template "_pagination" .}}
{{template "_footer"}}
diff --git a/templates/untagged.html b/templates/untagged.html
@@ -9,24 +9,6 @@
{{end}}
</div>
-{{if .Pagination}}
-{{if gt .Pagination.TotalPages 1}}
-<div class="pagination">
- {{if .Pagination.HasPrev}}
- <a href="?page={{.Pagination.PrevPage}}">« Previous</a>
- {{else}}
- <span class="disabled">« Previous</span>
- {{end}}
-
- <span class="page-info">Page {{.Pagination.CurrentPage}} of {{.Pagination.TotalPages}}</span>
-
- {{if .Pagination.HasNext}}
- <a href="?page={{.Pagination.NextPage}}">Next »</a>
- {{else}}
- <span class="disabled">Next »</span>
- {{end}}
-</div>
-{{end}}
-{{end}}
+{{template "_pagination" .}}
{{template "_footer"}}