diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
index 4cfdc36..30fc3b9 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
@@ -393,6 +393,14 @@
No bookmarks yet. Click + Add Bookmark to save a frequency.
+
+
Showing 0-0 of 0
+
+
+ Page 1 of 1
+
+
+
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js
index cfb4148..7d94602 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/bookmarks.js
@@ -1,7 +1,10 @@
// --- Bookmarks Tab ---
var bmList = [];
+let bmFilteredList = [];
let bmEditId = null;
+let bmCurrentPage = 1;
+const BM_PAGE_SIZE = 25;
function bmFmtFreq(hz) {
if (!Number.isFinite(hz) || hz <= 0) return "--";
@@ -66,6 +69,8 @@ function bmApplyFilters() {
(bm.comment || "").toLowerCase().includes(text)
)
: filtered;
+ bmFilteredList = filtered;
+ bmCurrentPage = 1;
bmRender(filtered);
}
@@ -106,18 +111,30 @@ async function bmRefreshCategoryFilter(keepValue) {
function bmRender(list) {
const tbody = document.getElementById("bm-tbody");
const emptyEl = document.getElementById("bm-empty");
+ const paginatorEl = document.getElementById("bm-paginator");
+ const pageSummaryEl = document.getElementById("bm-page-summary");
+ const pageIndicatorEl = document.getElementById("bm-page-indicator");
+ const prevBtn = document.getElementById("bm-page-prev");
+ const nextBtn = document.getElementById("bm-page-next");
if (!tbody) return;
tbody.innerHTML = "";
if (list.length === 0) {
if (emptyEl) emptyEl.style.display = "";
+ if (paginatorEl) paginatorEl.style.display = "none";
return;
}
if (emptyEl) emptyEl.style.display = "none";
const canControl = bmCanControl();
+ const totalPages = Math.max(1, Math.ceil(list.length / BM_PAGE_SIZE));
+ const page = Math.min(Math.max(bmCurrentPage, 1), totalPages);
+ bmCurrentPage = page;
+ const startIndex = (page - 1) * BM_PAGE_SIZE;
+ const endIndex = Math.min(startIndex + BM_PAGE_SIZE, list.length);
+ const pageItems = list.slice(startIndex, endIndex);
- list.forEach((bm) => {
+ pageItems.forEach((bm) => {
const tr = document.createElement("tr");
tr.dataset.bmId = bm.id;
const bwCell = bm.bandwidth_hz ? bmFmtFreq(bm.bandwidth_hz) : "--";
@@ -143,6 +160,20 @@ function bmRender(list) {
``;
tbody.appendChild(tr);
});
+
+ if (paginatorEl) paginatorEl.style.display = totalPages > 1 ? "flex" : "";
+ if (pageSummaryEl) pageSummaryEl.textContent = `Showing ${startIndex + 1}-${endIndex} of ${list.length}`;
+ if (pageIndicatorEl) pageIndicatorEl.textContent = `Page ${page} of ${totalPages}`;
+ if (prevBtn) prevBtn.disabled = page <= 1;
+ if (nextBtn) nextBtn.disabled = page >= totalPages;
+}
+
+function bmChangePage(delta) {
+ const totalPages = Math.max(1, Math.ceil(bmFilteredList.length / BM_PAGE_SIZE));
+ const nextPage = Math.min(Math.max(bmCurrentPage + delta, 1), totalPages);
+ if (nextPage === bmCurrentPage) return;
+ bmCurrentPage = nextPage;
+ bmRender(bmFilteredList);
}
// Read decoder checkboxes and return an array of selected decoder names.
@@ -370,6 +401,14 @@ async function bmApply(bm) {
bmApplyFilters();
});
+ document.getElementById("bm-page-prev").addEventListener("click", () => {
+ bmChangePage(-1);
+ });
+
+ document.getElementById("bm-page-next").addEventListener("click", () => {
+ bmChangePage(1);
+ });
+
// Form submit
document.getElementById("bm-form").addEventListener("submit", bmSave);
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
index 02d6c4c..84daa81 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
@@ -3135,6 +3135,30 @@ button:focus-visible, input:focus-visible, select:focus-visible {
color: var(--text-muted);
font-size: 0.9rem;
}
+.bm-paginator {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 0.8rem;
+ padding: 0.9rem 0.2rem 0;
+}
+.bm-page-summary,
+.bm-page-indicator {
+ color: var(--text-muted);
+ font-size: 0.88rem;
+}
+.bm-page-controls {
+ display: flex;
+ align-items: center;
+ gap: 0.55rem;
+}
+.bm-page-controls button {
+ min-width: 6.4rem;
+}
+.bm-page-controls button:disabled {
+ opacity: 0.45;
+ cursor: default;
+}
/* ── Donald style ─────────────────────────────────────────────────────── */
[data-style="golden-rain"] {
@@ -3574,6 +3598,21 @@ button:focus-visible, input:focus-visible, select:focus-visible {
.sch-label {
min-width: 100%;
}
+ .bm-paginator {
+ flex-direction: column;
+ align-items: stretch;
+ }
+ .bm-page-controls {
+ justify-content: space-between;
+ }
+ .bm-page-controls button {
+ flex: 1 1 0;
+ min-width: 0;
+ }
+ .bm-page-indicator,
+ .bm-page-summary {
+ text-align: center;
+ }
.bgd-add-row,
.bgd-status-row {
flex-direction: column;