diff options
21 files changed, 109 insertions, 16 deletions
diff --git a/internal/locale/translations/de_DE.json b/internal/locale/translations/de_DE.json index fa3d3a68..ff297ba6 100644 --- a/internal/locale/translations/de_DE.json +++ b/internal/locale/translations/de_DE.json @@ -55,7 +55,9 @@ "search.label": "Suche", "search.placeholder": "Suche...", "search.submit": "Search", + "pagination.last": "Last", "pagination.next": "Nächste", + "pagination.first": "First", "pagination.previous": "Vorherige", "entry.status.unread": "Ungelesen", "entry.status.read": "Gelesen", diff --git a/internal/locale/translations/el_EL.json b/internal/locale/translations/el_EL.json index 28169261..932c7c47 100644 --- a/internal/locale/translations/el_EL.json +++ b/internal/locale/translations/el_EL.json @@ -55,7 +55,9 @@ "search.label": "Αναζήτηση", "search.placeholder": "Αναζήτηση...", "search.submit": "Search", + "pagination.last": "Last", "pagination.next": "Επόμενη", + "pagination.first": "First", "pagination.previous": "Προηγούμενη", "entry.status.unread": "Μη αναγνωσμένο", "entry.status.read": "Αναγνωσμένο", diff --git a/internal/locale/translations/en_US.json b/internal/locale/translations/en_US.json index 71867ffe..872f63f5 100644 --- a/internal/locale/translations/en_US.json +++ b/internal/locale/translations/en_US.json @@ -55,7 +55,9 @@ "search.label": "Search", "search.placeholder": "Search…", "search.submit": "Search", + "pagination.last": "Last", "pagination.next": "Next", + "pagination.first": "First", "pagination.previous": "Previous", "entry.status.unread": "Unread", "entry.status.read": "Read", diff --git a/internal/locale/translations/es_ES.json b/internal/locale/translations/es_ES.json index 0c7766e8..b52d47d1 100644 --- a/internal/locale/translations/es_ES.json +++ b/internal/locale/translations/es_ES.json @@ -55,7 +55,9 @@ "search.label": "Buscar", "search.placeholder": "Búsqueda...", "search.submit": "Search", + "pagination.last": "Ultimo", "pagination.next": "Siguiente", + "pagination.first": "Primero", "pagination.previous": "Anterior", "entry.status.unread": "No leído", "entry.status.read": "Leído", diff --git a/internal/locale/translations/fi_FI.json b/internal/locale/translations/fi_FI.json index 7b6565fc..00e4c8f4 100644 --- a/internal/locale/translations/fi_FI.json +++ b/internal/locale/translations/fi_FI.json @@ -55,7 +55,9 @@ "search.label": "Haku", "search.placeholder": "Hae...", "search.submit": "Search", + "pagination.last": "Last", "pagination.next": "Seuraava", + "pagination.first": "First", "pagination.previous": "Edellinen", "entry.status.unread": "Lukematon", "entry.status.read": "Luettu", diff --git a/internal/locale/translations/fr_FR.json b/internal/locale/translations/fr_FR.json index b25033b4..63d7d790 100644 --- a/internal/locale/translations/fr_FR.json +++ b/internal/locale/translations/fr_FR.json @@ -55,7 +55,9 @@ "search.label": "Recherche", "search.placeholder": "Recherche...", "search.submit": "Rechercher", + "pagination.last": "Last", "pagination.next": "Suivant", + "pagination.first": "First", "pagination.previous": "Précédent", "entry.status.unread": "Non lu", "entry.status.read": "Lu", diff --git a/internal/locale/translations/hi_IN.json b/internal/locale/translations/hi_IN.json index 2ebe379a..6d956521 100644 --- a/internal/locale/translations/hi_IN.json +++ b/internal/locale/translations/hi_IN.json @@ -55,7 +55,9 @@ "search.label": "खोजे", "search.placeholder": "खोजे...", "search.submit": "Search", + "pagination.last": "Last", "pagination.next": "अगला", + "pagination.first": "First", "pagination.previous": "पिछला", "entry.status.unread": "अपठित", "entry.status.read": "पढ़े", diff --git a/internal/locale/translations/id_ID.json b/internal/locale/translations/id_ID.json index 06ecd7db..001687b3 100644 --- a/internal/locale/translations/id_ID.json +++ b/internal/locale/translations/id_ID.json @@ -56,6 +56,8 @@ "search.placeholder": "Cari...", "search.submit": "Search", "pagination.next": "Berikutnya", + "pagination.last": "Last", + "pagination.first": "First", "pagination.previous": "Sebelumnya", "entry.status.unread": "Belum dibaca", "entry.status.read": "Telah dibaca", diff --git a/internal/locale/translations/it_IT.json b/internal/locale/translations/it_IT.json index fcb5daae..f62526f0 100644 --- a/internal/locale/translations/it_IT.json +++ b/internal/locale/translations/it_IT.json @@ -56,6 +56,8 @@ "search.placeholder": "Cerca...", "search.submit": "Search", "pagination.next": "Successivo", + "pagination.last": "Last", + "pagination.first": "First", "pagination.previous": "Precedente", "entry.status.unread": "Da leggere", "entry.status.read": "Letto", diff --git a/internal/locale/translations/ja_JP.json b/internal/locale/translations/ja_JP.json index f6f3d72c..c0c68923 100644 --- a/internal/locale/translations/ja_JP.json +++ b/internal/locale/translations/ja_JP.json @@ -55,7 +55,9 @@ "search.label": "検索", "search.placeholder": "…を検索", "search.submit": "Search", + "pagination.last": "Last", "pagination.next": "次", + "pagination.first": "First", "pagination.previous": "前", "entry.status.unread": "未読にする", "entry.status.read": "既読にする", diff --git a/internal/locale/translations/nl_NL.json b/internal/locale/translations/nl_NL.json index 6b73abbc..134ddcb9 100644 --- a/internal/locale/translations/nl_NL.json +++ b/internal/locale/translations/nl_NL.json @@ -55,7 +55,9 @@ "search.label": "Zoeken", "search.placeholder": "Zoeken...", "search.submit": "Search", + "pagination.last": "Last", "pagination.next": "Volgende", + "pagination.first": "First", "pagination.previous": "Vorige", "entry.status.unread": "Ongelezen", "entry.status.read": "Gelezen", diff --git a/internal/locale/translations/pl_PL.json b/internal/locale/translations/pl_PL.json index 0044d021..b8bf855d 100644 --- a/internal/locale/translations/pl_PL.json +++ b/internal/locale/translations/pl_PL.json @@ -55,7 +55,9 @@ "search.label": "Szukaj", "search.placeholder": "Szukaj...", "search.submit": "Search", + "pagination.last": "Ostatni", "pagination.next": "Następny", + "pagination.first": "Pierwszy", "pagination.previous": "Poprzedni", "entry.status.unread": "Nieprzeczytane", "entry.status.read": "Przeczytane", diff --git a/internal/locale/translations/pt_BR.json b/internal/locale/translations/pt_BR.json index 1dd3f195..d014c603 100644 --- a/internal/locale/translations/pt_BR.json +++ b/internal/locale/translations/pt_BR.json @@ -55,7 +55,9 @@ "search.label": "Buscar", "search.placeholder": "Buscar por...", "search.submit": "Search", + "pagination.last": "Last", "pagination.next": "Próximo", + "pagination.first": "First", "pagination.previous": "Anterior", "entry.status.unread": "Não lido", "entry.status.read": "Lido", diff --git a/internal/locale/translations/ru_RU.json b/internal/locale/translations/ru_RU.json index d759621b..47df1f61 100644 --- a/internal/locale/translations/ru_RU.json +++ b/internal/locale/translations/ru_RU.json @@ -55,7 +55,9 @@ "search.label": "Поиск", "search.placeholder": "Поиск…", "search.submit": "Search", + "pagination.last": "Last", "pagination.next": "Следующая", + "pagination.first": "First", "pagination.previous": "Предыдущая", "entry.status.unread": "Не прочитано", "entry.status.read": "Прочитано", diff --git a/internal/locale/translations/tr_TR.json b/internal/locale/translations/tr_TR.json index fbaa3efb..965f68de 100644 --- a/internal/locale/translations/tr_TR.json +++ b/internal/locale/translations/tr_TR.json @@ -485,7 +485,9 @@ "page.users.title": "Kullanıcılar", "page.users.username": "Kullanıcı adı", "page.webauthn_rename.title": "Passkey'i Yeniden Adlandır", + "pagination.last": "Last", "pagination.next": "Sonraki", + "pagination.first": "First", "pagination.previous": "Önceki", "search.label": "Ara", "search.placeholder": "Ara...", diff --git a/internal/locale/translations/uk_UA.json b/internal/locale/translations/uk_UA.json index 84ed3278..f8496ad6 100644 --- a/internal/locale/translations/uk_UA.json +++ b/internal/locale/translations/uk_UA.json @@ -55,7 +55,9 @@ "search.label": "Пошук", "search.placeholder": "Шукати...", "search.submit": "Search", + "pagination.last": "Last", "pagination.next": "Вперед", + "pagination.first": "First", "pagination.previous": "Назад", "entry.status.unread": "Непрочитане", "entry.status.read": "Прочитане", diff --git a/internal/locale/translations/zh_CN.json b/internal/locale/translations/zh_CN.json index 7ab55344..5b9387fa 100644 --- a/internal/locale/translations/zh_CN.json +++ b/internal/locale/translations/zh_CN.json @@ -55,7 +55,9 @@ "search.label": "搜索", "search.placeholder": "搜索…", "search.submit": "Search", + "pagination.last": "Last", "pagination.next": "下一页", + "pagination.first": "First", "pagination.previous": "上一页", "entry.status.unread": "标为未读", "entry.status.read": "标为已读", diff --git a/internal/locale/translations/zh_TW.json b/internal/locale/translations/zh_TW.json index 12ea4c7a..79020d9f 100644 --- a/internal/locale/translations/zh_TW.json +++ b/internal/locale/translations/zh_TW.json @@ -55,7 +55,9 @@ "search.label": "搜尋", "search.placeholder": "搜尋…", "search.submit": "送出", + "pagination.last": "Last", "pagination.next": "下一頁", + "pagination.first": "First", "pagination.previous": "上一頁", "entry.status.unread": "標為未讀", "entry.status.read": "標為已讀", diff --git a/internal/template/templates/common/pagination.html b/internal/template/templates/common/pagination.html index 964a7a0f..7bcf870e 100644 --- a/internal/template/templates/common/pagination.html +++ b/internal/template/templates/common/pagination.html @@ -1,19 +1,39 @@ {{ define "pagination" }} <div class="pagination"> - <div class="pagination-prev {{ if not .ShowPrev }}disabled{{end}}"> - {{ if .ShowPrev }} - <a href="{{ .Route }}{{ if gt .PrevOffset 0 }}?offset={{ .PrevOffset }}{{ if .SearchQuery }}&q={{ .SearchQuery }}{{ end }}{{ else }}{{ if .SearchQuery }}?q={{ .SearchQuery }}{{ end }}{{ end }}" data-page="previous" rel="prev">{{ t "pagination.previous" }}</a> - {{ else }} - {{ t "pagination.previous" }} - {{ end }} + <div class="pagination-backward"> + <div class="pagination-first {{ if not .ShowFirst }}disabled{{end}}"> + {{ if .ShowFirst }} + <a href="{{ .Route }}{{ if gt .FirstOffset 0 }}?offset={{ .FirstOffset }}{{ if .SearchQuery }}&q={{ .SearchQuery }}{{ end }}{{ else }}{{ if .SearchQuery }}?q={{ .SearchQuery }}{{ end }}{{ end }}" data-page="first">{{ t "pagination.first" }}</a> + {{ else }} + {{ t "pagination.first" }} + {{ end }} + </div> + + <div class="pagination-prev {{ if not .ShowPrev }}disabled{{end}}"> + {{ if .ShowPrev }} + <a href="{{ .Route }}{{ if gt .PrevOffset 0 }}?offset={{ .PrevOffset }}{{ if .SearchQuery }}&q={{ .SearchQuery }}{{ end }}{{ else }}{{ if .SearchQuery }}?q={{ .SearchQuery }}{{ end }}{{ end }}" data-page="previous" rel="prev">{{ t "pagination.previous" }}</a> + {{ else }} + {{ t "pagination.previous" }} + {{ end }} + </div> </div> - <div class="pagination-next {{ if not .ShowNext }}disabled{{end}}"> - {{ if .ShowNext }} - <a href="{{ .Route }}?offset={{ .NextOffset }}{{ if .SearchQuery }}&q={{ .SearchQuery }}{{ end }}" data-page="next" rel="next">{{ t "pagination.next" }}</a> - {{ else }} - {{ t "pagination.next" }} - {{ end }} + <div class="pagination-forward"> + <div class="pagination-next {{ if not .ShowNext }}disabled{{end}}"> + {{ if .ShowNext }} + <a href="{{ .Route }}?offset={{ .NextOffset }}{{ if .SearchQuery }}&q={{ .SearchQuery }}{{ end }}" data-page="next" rel="next">{{ t "pagination.next" }}</a> + {{ else }} + {{ t "pagination.next" }} + {{ end }} + </div> + + <div class="pagination-last {{ if not .ShowLast }}disabled{{end}}"> + {{ if .ShowLast }} + <a href="{{ .Route }}?offset={{ .LastOffset }}{{ if .SearchQuery }}&q={{ .SearchQuery }}{{ end }}" data-page="last" >{{ t "pagination.last" }}</a> + {{ else }} + {{ t "pagination.last" }} + {{ end }} + </div> </div> </div> {{ end }} diff --git a/internal/ui/pagination.go b/internal/ui/pagination.go index 5a31192a..e7c63a16 100644 --- a/internal/ui/pagination.go +++ b/internal/ui/pagination.go @@ -9,17 +9,30 @@ type pagination struct { Offset int ItemsPerPage int ShowNext bool + ShowLast bool + ShowFirst bool ShowPrev bool NextOffset int + LastOffset int PrevOffset int + FirstOffset int SearchQuery string } func getPagination(route string, total, offset, nbItemsPerPage int) pagination { nextOffset := 0 prevOffset := 0 + + firstOffset := 0 + lastOffset := (total / nbItemsPerPage) * nbItemsPerPage + if lastOffset == total { + lastOffset -= nbItemsPerPage + } + showNext := (total - offset) > nbItemsPerPage showPrev := offset > 0 + showLast := showNext + showFirst := showPrev if showNext { nextOffset = offset + nbItemsPerPage @@ -35,8 +48,12 @@ func getPagination(route string, total, offset, nbItemsPerPage int) pagination { Offset: offset, ItemsPerPage: nbItemsPerPage, ShowNext: showNext, + ShowLast: showLast, NextOffset: nextOffset, + LastOffset: lastOffset, ShowPrev: showPrev, + ShowFirst: showFirst, PrevOffset: prevOffset, + FirstOffset: firstOffset, } } diff --git a/internal/ui/static/css/common.css b/internal/ui/static/css/common.css index a27aadae..66a6b0f1 100644 --- a/internal/ui/static/css/common.css +++ b/internal/ui/static/css/common.css @@ -710,6 +710,7 @@ template { font-size: 1.1em; display: flex; align-items: center; + justify-content: space-between; } .pagination-top { @@ -732,21 +733,40 @@ template { } .pagination > div { - flex: 1; + display: flex; +} + +.pagination > div.pagination-backward > div { + padding-right: 15px; +} + +.pagination > div.pagination-forward > div { + padding-left: 15px; } .pagination-next { text-align: right; } -.pagination-prev:before { - content: "« "; +.pagination-next:after { + content: " ›"; } -.pagination-next:after { +.pagination-last { + text-align: right; +} + +.pagination-last:after { content: " »"; } +.pagination-prev:before { + content: "‹ "; +} +.pagination-first:before { + content: "« "; +} + .pagination a { color: var(--pagination-link-color); } |