UI: индикатор загрузки истории чата

This commit is contained in:
AidarKC
2026-07-22 19:07:15 +04:00
parent af62b51ef5
commit a183a586cb
3 changed files with 82 additions and 3 deletions
+2 -2
View File
@@ -1,2 +1,2 @@
client.version=1.2.343 client.version=1.2.344
server.version=1.2.315 server.version=1.2.316
+18 -1
View File
@@ -837,6 +837,16 @@ export function render({ navigate, route }) {
const wrap = document.createElement('div'); const wrap = document.createElement('div');
wrap.className = 'chat-wrap dm-chat-wrap'; wrap.className = 'chat-wrap dm-chat-wrap';
const historyLoader = document.createElement('div');
historyLoader.className = 'dm-history-loader';
historyLoader.hidden = true;
historyLoader.innerHTML = `
<div class="dm-history-loader__pill" aria-live="polite" aria-busy="true">
<span class="dm-history-loader__spinner" aria-hidden="true"></span>
<span class="dm-history-loader__label">Загрузка истории…</span>
</div>
`;
const log = document.createElement('div'); const log = document.createElement('div');
log.className = 'messages-log dm-messages-log'; log.className = 'messages-log dm-messages-log';
@@ -987,6 +997,11 @@ export function render({ navigate, route }) {
} }
}; };
const setHistoryLoadingState = (isLoading) => {
historyLoader.hidden = !isLoading;
historyLoader.classList.toggle('is-visible', !!isLoading);
};
const syncComposerLayout = () => { const syncComposerLayout = () => {
const height = Number.parseFloat(input?.style.height || '0'); const height = Number.parseFloat(input?.style.height || '0');
form.classList.toggle('dm-chat-input--multiline', height > 52); form.classList.toggle('dm-chat-input--multiline', height > 52);
@@ -1325,6 +1340,7 @@ export function render({ navigate, route }) {
if (historyLoading) return; if (historyLoading) return;
if (historyBootstrapped && !historyHasMore) return; if (historyBootstrapped && !historyHasMore) return;
historyLoading = true; historyLoading = true;
setHistoryLoadingState(true);
const scrollContainer = boundScrollContainer || log.closest('.screen-content') || wrap.parentElement || wrap; const scrollContainer = boundScrollContainer || log.closest('.screen-content') || wrap.parentElement || wrap;
const prevScrollTop = Number(scrollContainer?.scrollTop || 0); const prevScrollTop = Number(scrollContainer?.scrollTop || 0);
const prevScrollHeight = Number(scrollContainer?.scrollHeight || 0); const prevScrollHeight = Number(scrollContainer?.scrollHeight || 0);
@@ -1359,6 +1375,7 @@ export function render({ navigate, route }) {
}); });
} finally { } finally {
historyLoading = false; historyLoading = false;
setHistoryLoadingState(false);
} }
}; };
@@ -1467,7 +1484,7 @@ export function render({ navigate, route }) {
window.visualViewport?.addEventListener('resize', syncKeyboardUi); window.visualViewport?.addEventListener('resize', syncKeyboardUi);
window.addEventListener('resize', syncKeyboardUi); window.addEventListener('resize', syncKeyboardUi);
wrap.append(log, form); wrap.append(historyLoader, log, form);
screen.append(wrap); screen.append(wrap);
renderLog(log, chatId, { renderLog(log, chatId, {
onOpenActions: handleOpenActions, onOpenActions: handleOpenActions,
+62
View File
@@ -4669,6 +4669,68 @@ html, body { overflow-x: hidden; }
gap: 10px; gap: 10px;
} }
.dm-history-loader {
position: sticky;
top: 0;
z-index: 3;
display: flex;
justify-content: center;
pointer-events: none;
margin-bottom: -4px;
opacity: 0;
transform: translateY(-8px);
transition: opacity 160ms ease, transform 160ms ease;
}
.dm-history-loader[hidden] {
display: none;
}
.dm-history-loader.is-visible {
opacity: 1;
transform: translateY(0);
}
.dm-history-loader__pill {
display: inline-flex;
align-items: center;
gap: 10px;
min-height: 34px;
padding: 7px 14px;
border-radius: 999px;
border: 1px solid rgba(212, 175, 55, 0.24);
background: rgba(9, 15, 26, 0.92);
color: rgba(245, 226, 179, 0.96);
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.28);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
}
.dm-history-loader__label {
font-size: 12px;
font-weight: 600;
letter-spacing: 0.02em;
}
.dm-history-loader__spinner {
width: 16px;
height: 16px;
border-radius: 50%;
border: 2px solid rgba(255, 234, 186, 0.22);
border-top-color: rgba(242, 201, 92, 0.96);
box-shadow: 0 0 10px rgba(212, 175, 55, 0.18);
animation: dm-history-loader-spin 0.85s linear infinite;
}
@keyframes dm-history-loader-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.dm-screen .bubble { .dm-screen .bubble {
max-width: 78%; max-width: 78%;
padding: 11px 14px; padding: 11px 14px;