Files
gott/wwwroot/js/ui-helpers.js
T
Meleki 0dcc05ebf9 refactor: ui.js, chat.js, history.js in 13 modulare Dateien aufteilen
Die monolithische ui.js (1534 Zeilen) zusammen mit chat.js (612) und
history.js (626) in fokussierte Module aufgeteilt:

Neue Dateien aus ui.js:
- ui-helpers.js (126) - DOM-Utilities, $, esc, truncate, scrollDown, Toast
- markdown.js (143) - renderMarkdown, wrapKreaGalleries, LaTeX/Code-Schutz
- cards.js (90) - buildSessionCard, buildAgentCard
- msg-actions.js (208) - Delete, Mark, Share, Reply-Button, Timestamp
- tool-ui.js (332) - Tool-Boxes, Diffs, Todo-Liste, Visibility
- modals.js (190) - System-Prompt, Command-Output, Krea-Image Modals
- stream-ui.js (124) - Stream-Bubble, Review-Streaming
- bubbles.js (312) - User/Assistant/Error/Warning/Choice/Review Bubbles

Neue Dateien aus chat.js:
- reply.js (54) - Reply/Quote-Handling mit pendingReply State
- files.js (110) - File-Upload, Workspace-Refs mit pendingFiles/Refs State

Neue Datei aus history.js:
- archive.js (173) - Archiv-Loading mit loadedArchiveCount State

Verbleibend:
- chat.js (448) - Stream-Events, sendMessage, handleChoiceClick, Plan-Mode
- history.js (464) - History laden, Polling, Message-Rendering

Kein Code verändert, nur verschoben. Alle 94 Funktionen verifiziert.
Globale Variablen in die Module verschoben, wo sie primär genutzt werden.
2026-03-07 19:32:33 +01:00

127 lines
3.7 KiB
JavaScript

// ── DOM Helpers ──
const $ = (sel) => document.querySelector(sel);
const chatEl = () => $('#chat');
const metaEl = () => $('#meta');
function esc(s) {
const d = document.createElement('div');
d.textContent = s;
return d.innerHTML;
}
function truncate(s, max) {
return s && s.length > max ? s.substring(0, max) + '...' : (s || '');
}
function scrollDown() {
const chat = chatEl();
if (!chat) return;
chat.scrollTop = chat.scrollHeight;
// Nach Font-Swap kann sich die Höhe ändern → nochmal scrollen
document.fonts.ready.then(() => {
chat.scrollTop = chat.scrollHeight;
});
}
function prettyModelName(model) {
if (!model) return '?';
model = model.split('claude-').join('');
if (model == 'sonnet') return 'Sonnet';
if (model == 'sonnet-4-5') return 'Sonnet 4.5';
if (model == 'sonnet-4-6') return 'Sonnet 4.6';
if (model == 'opus') return 'Opus';
if (model == 'opus-4-5') return 'Opus 4.5';
if (model == 'opus-4-6') return 'Opus 4.6';
if (model == 'haiku') return 'Haiku';
if (model == 'haiku-4-5') return 'Haiku 4.5';
return 'Unbekannt (' + model + ')';
}
// ── Toast Notifications ──
function showToast(message, type) {
type = type || 'info';
var container = document.getElementById('toastContainer');
if (!container) {
container = document.createElement('div');
container.id = 'toastContainer';
document.body.appendChild(container);
}
var toast = document.createElement('div');
toast.className = 'toast toast-' + type;
var icon = type === 'success' ? 'fa-check-circle' : type === 'error' ? 'fa-times-circle' : 'fa-info-circle';
toast.innerHTML = '<i class="fa ' + icon + '"></i> ' + (message || '');
container.appendChild(toast);
// Einblenden
requestAnimationFrame(function() { toast.classList.add('toast-visible'); });
// Automatisch ausblenden
var timeout = setTimeout(function() { removeToast(toast); }, 4000);
toast.addEventListener('click', function() {
clearTimeout(timeout);
removeToast(toast);
});
}
function removeToast(toast) {
toast.classList.remove('toast-visible');
toast.addEventListener('transitionend', function() { toast.remove(); });
}
// ── Meta Bar ──
function setMeta(text) {
metaEl().textContent = text;
}
function setMetaHtml(html) {
metaEl().innerHTML = html;
}
// ── Older Messages Button ──
function showOlderMessagesButton(remainingCount) {
removeOlderMessagesButton();
const btn = document.createElement('button');
btn.className = 'archive-load-btn older-messages-btn';
btn.innerHTML = '<i class="fa fa-arrow-up"></i> ' + remainingCount + ' ältere Nachrichten laden';
btn.addEventListener('click', () => loadOlderMessages());
chatEl().prepend(btn);
}
function removeOlderMessagesButton() {
const btn = chatEl().querySelector('.older-messages-btn');
if (btn) btn.remove();
}
// ── Archive Button ──
function showArchiveLoadButton() {
const existing = chatEl().querySelector('.archive-load-btn:not(.older-messages-btn)');
if (existing) existing.remove();
const btn = document.createElement('button');
btn.className = 'archive-load-btn';
btn.innerHTML = '<i class="fa fa-archive"></i> Archivierte Nachrichten laden';
btn.addEventListener('click', loadLatestArchive);
// Immer ganz oben im Chat (aber nach dem older-messages-btn falls vorhanden)
const olderBtn = chatEl().querySelector('.older-messages-btn');
if (olderBtn) {
olderBtn.after(btn);
} else {
chatEl().prepend(btn);
}
}
function removeArchiveLoadButton() {
const btns = chatEl().querySelectorAll('.archive-load-btn:not(.older-messages-btn)');
btns.forEach(b => b.remove());
}
// ── Streamed Elements ──
function removeStreamedElements() {
chatEl().querySelectorAll('.streamed').forEach(el => el.remove());
}