Harden account import/continuous behavior and finish multi-account UI polish

This commit is contained in:
forust committed 2026-06-27 21:26:18 +02:00
1 parent 59cdad220a
commit 881e7ddfca
8 files changed
+572 -35

No files matched your search

+74 -4
View File
@@ -8,7 +8,9 @@ const viewerState = {
oldestMessageId: null,
newestMessageId: null,
userId: null,
search: "",
loading: false,
autoRefreshTimer: null,
sentinelObserver: null,
};
@@ -21,6 +23,24 @@ async function api(path) {
return data;
}
function showToast(message, type = "info") {
let root = document.getElementById("toast-root");
if (!root) {
root = document.createElement("div");
root.id = "toast-root";
root.className = "toast-root";
document.body.appendChild(root);
}
const toast = document.createElement("div");
toast.className = `toast toast-${type}`;
toast.textContent = message;
root.appendChild(toast);
window.setTimeout(() => {
toast.classList.add("toast-hide");
window.setTimeout(() => toast.remove(), 250);
}, 3600);
}
function formatDateHeader(dateStr) {
if (!dateStr) return "";
const d = new Date(dateStr.replace(" ", "T"));
@@ -136,10 +156,13 @@ function renderChannelList() {
}
function messageEndpoint(channelId, before = "") {
const search = viewerState.search
? `&search=${encodeURIComponent(viewerState.search)}`
: "";
if (viewerState.accountId) {
return `/api/accounts/${encodeURIComponent(viewerState.accountId)}/channels/${encodeURIComponent(channelId)}/messages?limit=80${before}`;
return `/api/accounts/${encodeURIComponent(viewerState.accountId)}/channels/${encodeURIComponent(channelId)}/messages?limit=80${before}${search}`;
}
return `/api/channels/${encodeURIComponent(channelId)}/messages?limit=80${before}`;
return `/api/channels/${encodeURIComponent(channelId)}/messages?limit=80${before}${search}`;
}
function channelsEndpoint() {
@@ -172,6 +195,9 @@ function renderAccountSelector() {
async function switchViewerAccount(accountId) {
viewerState.accountId = accountId || null;
viewerState.search = "";
const searchInput = document.getElementById("viewer-search");
if (searchInput) searchInput.value = "";
viewerState.accounts.forEach((acc) => {
if (acc.id === accountId) {
const opts = document.getElementById("viewer-account-select")?.options;
@@ -323,7 +349,7 @@ function renderMessages(payload, append = false) {
document.getElementById("viewer-title").textContent =
channel?.name || payload.channel_id;
document.getElementById("viewer-subtitle").textContent = channel
? `${channel.message_count} messages, latest: ${channel.last_date || "-"}`
? `${payload.messages.length} shown${viewerState.search ? ` for "${viewerState.search}"` : ""}, ${channel.message_count} total, latest: ${channel.last_date || "-"}`
: "No local database found for this channel yet.";
if (!append) {
@@ -371,6 +397,15 @@ function renderMessages(payload, append = false) {
viewerState.oldestMessageId = payload.messages[0].message_id;
viewerState.newestMessageId =
payload.messages[payload.messages.length - 1].message_id;
} else if (!append) {
viewerState.oldestMessageId = null;
viewerState.newestMessageId = null;
const empty = document.createElement("div");
empty.className = "viewer-empty-state";
empty.textContent = viewerState.search
? `No messages found for "${viewerState.search}".`
: "No saved messages in this channel yet.";
root.appendChild(empty);
}
if (!append) {
@@ -407,6 +442,40 @@ async function loadChannel(channelId, append = false) {
}
}
async function refreshCurrentChannel() {
if (!viewerState.channelId || viewerState.loading) return;
viewerState.oldestMessageId = null;
viewerState.newestMessageId = null;
await loadChannel(viewerState.channelId);
}
function setupViewerTools() {
const searchInput = document.getElementById("viewer-search");
const refreshBtn = document.getElementById("viewer-refresh-btn");
const autoRefresh = document.getElementById("viewer-auto-refresh");
let searchTimer = null;
if (searchInput) {
searchInput.addEventListener("input", () => {
clearTimeout(searchTimer);
searchTimer = setTimeout(() => {
viewerState.search = searchInput.value.trim();
refreshCurrentChannel();
}, 250);
});
}
if (refreshBtn) {
refreshBtn.addEventListener("click", () => refreshCurrentChannel());
}
viewerState.autoRefreshTimer = window.setInterval(() => {
if (!autoRefresh || autoRefresh.checked) {
refreshCurrentChannel();
}
}, 30000);
}
function setupInfiniteScroll() {
const sentinel = document.getElementById("scroll-sentinel");
if (!sentinel) return;
@@ -456,6 +525,7 @@ async function main() {
}
setupInfiniteScroll();
setupViewerTools();
const toggle = document.getElementById("sidebar-toggle");
const sidebar = document.querySelector(".viewer-sidebar");
@@ -473,5 +543,5 @@ async function main() {
main().catch((error) => {
console.error(error);
alert(error.message);
showToast(error.message, "error");
});