refactor: Inline-Styles durch CSS-Klassen ersetzt

- 40+ Utility-Klassen in form.css (clickable, text-danger, flex-row, loading-state, etc.)
- share-menu position/z-index in chat.css statt inline
- index.html: 0 Inline-Styles (hidden-Attribut, CSS-Klassen)
- 12 JS-Dateien bereinigt: style.cssText/style.* durch classList ersetzt
- Bugfix: var(--danger) → var(--dangerous) (nicht existierende Variable)
- display:none Toggles → hidden-Attribut wo passend
- Hardcoded font-sizes in chat.css → var(--font-size)

15 Dateien, nur Frontend (CSS/JS/HTML), kein Backend
This commit is contained in:
Meleki committed 2026-03-14 17:14:30 +01:00
1 parent e368abced0
commit ce50633e33
15 files changed
+109 -76

No files matched your search

+5 -3
View File
@@ -241,7 +241,7 @@
border-radius: var(--border-radius); border-radius: var(--border-radius);
color: var(--text) !important; color: var(--text) !important;
text-decoration: none !important; text-decoration: none !important;
font-size: 0.85em; font-size: var(--font-size);
transition: background var(--transition-speed), border-color var(--transition-speed); transition: background var(--transition-speed), border-color var(--transition-speed);
max-width: 20em; max-width: 20em;
overflow: hidden; overflow: hidden;
@@ -254,7 +254,7 @@
} }
.web-search-source .fa { .web-search-source .fa {
font-size: 0.75em; font-size: var(--font-size);
opacity: 0.6; opacity: 0.6;
} }
@@ -324,7 +324,7 @@
padding-top: 0; padding-top: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
font-size: .85rem; font-size: var(--font-size);
gap: var(--badge-spacing); gap: var(--badge-spacing);
} }
@@ -979,6 +979,8 @@
/* Share Menu */ /* Share Menu */
.share-menu { .share-menu {
position: fixed;
z-index: 10000;
background: var(--f2-bg); background: var(--f2-bg);
border: var(--border-width) solid var(--f2-border); border: var(--border-width) solid var(--f2-border);
border-radius: var(--border-radius); border-radius: var(--border-radius);
+39
View File
@@ -855,3 +855,42 @@ a.admin-user-meta {
.db-back-link:hover { .db-back-link:hover {
color: var(--primary); color: var(--primary);
} }
/* ── Utility Classes (Inline-Style Replacements) ── */
.clickable { cursor: pointer }
.semi-dim { opacity: var(--semi-transparent) }
.text-danger { color: var(--dangerous) }
.text-accent { color: var(--accent) }
.text-primary { color: var(--primary) }
.text-error { color: var(--color-error) }
.text-secondary { color: var(--text-secondary) }
.icon-dim { opacity: var(--semi-transparent) }
.icon-dim-sm { opacity: var(--semi-transparent); font-size: var(--font-size) }
.chevron-separator { opacity: var(--semi-transparent); font-size: var(--font-size); margin: 0 .3em }
.pad-v { padding: 1rem 0 }
.loading-state { opacity: var(--semi-transparent); pointer-events: none }
.flex-row { display: flex; align-items: center; gap: .5rem }
.flex-row-tight { display: flex; align-items: center; gap: 8px; margin-top: 2px }
.min-w-0 { min-width: 0 }
.ml-auto { margin-left: auto }
.mr-badge { margin-right: var(--badge-spacing) }
.ml-sm { margin-left: 8px }
.mt-xs { margin-top: 4px }
.font-sm { font-size: var(--font-size) }
.semi-transparent { opacity: var(--semi-transparent) }
.lh-relaxed { line-height: 1.7 }
.scan-status { font-size: .85em; color: var(--text-secondary); padding: 0 0 .5rem 0 }
.check-status-line { padding: 0 var(--box-padding) .5rem; display: none; font-size: .85em }
.empty-hint { padding: 1rem; text-align: center; opacity: .7 }
.scanner-toolbar { display: flex; align-items: center; gap: 8px; padding: 8px var(--box-padding); border-bottom: 1px solid var(--border) }
.event-scanner-status { padding: 1em 2em }
.event-scanner-log { white-space: pre-line }
.remote-hint { font-size: var(--font-size); opacity: var(--semi-transparent); margin-bottom: var(--box-spacing) }
.remote-card-content { font-size: var(--font-size); display: flex; align-items: center; gap: var(--box-spacing) }
.remote-card-info { flex: 1; opacity: var(--semi-transparent) }
.none-card-image { display: flex; align-items: center; justify-content: center }
.none-card-icon { font-size: 2em; opacity: var(--semi-transparent) }
+5 -5
View File
@@ -473,7 +473,7 @@
</div> </div>
</div> </div>
</section> </section>
<section id="settingsBackupSection" class="settings-section" style="display:none"> <section id="settingsBackupSection" class="settings-section" hidden>
<h2>Daten</h2> <h2>Daten</h2>
<div class="setting-row"> <div class="setting-row">
<div class="setting-info"> <div class="setting-info">
@@ -573,7 +573,7 @@
<div class="form"> <div class="form">
<div class="section-header"> <div class="section-header">
<h2>API-Key</h2> <h2>API-Key</h2>
<button id="apiKeysCheckAllBtn" class="section-add-btn" style="margin-right: var(--badge-spacing); margin-left: auto;"><i class="fa fa-refresh"></i> Alle prüfen</button> <button id="apiKeysCheckAllBtn" class="section-add-btn mr-badge ml-auto"><i class="fa fa-refresh"></i> Alle prüfen</button>
<button id="apiKeysNewBtn" class="section-add-btn"><i class="fa fa-plus"></i> Neuer Key</button> <button id="apiKeysNewBtn" class="section-add-btn"><i class="fa fa-plus"></i> Neuer Key</button>
</div> </div>
<div id="apiKeysList" class="admin-user-list"></div> <div id="apiKeysList" class="admin-user-list"></div>
@@ -596,19 +596,19 @@
</div> </div>
</div> </div>
<div id="eventScannerStatus" style="display:none;padding:1em 2em;"></div> <div id="eventScannerStatus" class="event-scanner-status" hidden></div>
<div class="form"> <div class="form">
<div class="section-header"> <div class="section-header">
<h2>Key Scanner</h2> <h2>Key Scanner</h2>
<div style="display:flex;gap:.5rem;align-items:center"> <div class="flex-row">
<button id="recheckAllScannedBtn" class="section-add-btn"><i class="fa fa-refresh"></i> Alle prüfen</button> <button id="recheckAllScannedBtn" class="section-add-btn"><i class="fa fa-refresh"></i> Alle prüfen</button>
<button id="scanQuickBtn" class="section-add-btn"><i class="fa fa-bolt"></i> Quick</button> <button id="scanQuickBtn" class="section-add-btn"><i class="fa fa-bolt"></i> Quick</button>
<button id="scanWebBtn" class="section-add-btn"><i class="fa fa-globe"></i> Web</button> <button id="scanWebBtn" class="section-add-btn"><i class="fa fa-globe"></i> Web</button>
<button id="scanFullBtn" class="section-add-btn"><i class="fa fa-search"></i> Full</button> <button id="scanFullBtn" class="section-add-btn"><i class="fa fa-search"></i> Full</button>
</div> </div>
</div> </div>
<div id="scanStatus" style="font-size:.85em;color:var(--text-secondary);padding:0 0 .5rem 0"></div> <div id="scanStatus" class="scan-status"></div>
<div id="scannedKeysList" class="admin-user-list"></div> <div id="scannedKeysList" class="admin-user-list"></div>
<div class="form-actions"> <div class="form-actions">
<button hidden>&nbsp;</button> <button hidden>&nbsp;</button>
+2 -2
View File
@@ -55,7 +55,7 @@ var AvatarEditor = (function () {
renderPreview(); renderPreview();
// Click → Modal öffnen // Click → Modal öffnen
previewEl.style.cursor = 'pointer'; previewEl.classList.add('clickable');
previewEl.addEventListener('click', openModal); previewEl.addEventListener('click', openModal);
// Paste Handler (global, immer aktiv) // Paste Handler (global, immer aktiv)
@@ -326,7 +326,7 @@ var AvatarEditor = (function () {
pasteHandler = null; pasteHandler = null;
} }
previewEl.removeEventListener('click', openModal); previewEl.removeEventListener('click', openModal);
previewEl.style.cursor = ''; previewEl.classList.remove('clickable');
} }
}; };
} }
+2 -2
View File
@@ -72,7 +72,7 @@ function _renderUserTextContent(container, raw, inlineImages) {
const filePath = ref.replace(/:\d+(-\d+)?$/, ''); const filePath = ref.replace(/:\d+(-\d+)?$/, '');
const fileName = filePath.includes('/') ? filePath.substring(filePath.lastIndexOf('/') + 1) : filePath; const fileName = filePath.includes('/') ? filePath.substring(filePath.lastIndexOf('/') + 1) : filePath;
const lineInfo = ref.replace(filePath, '').trim(); const lineInfo = ref.replace(filePath, '').trim();
return '<span class="file-ref-chip" data-filepath="' + esc(filePath) + '" title="' + esc(ref) + '" style="cursor:pointer">' return '<span class="file-ref-chip clickable" data-filepath="' + esc(filePath) + '" title="' + esc(ref) + '">'
+ '<i class="fa fa-file-text-o"></i> ' + esc(fileName + lineInfo) + '</span>'; + '<i class="fa fa-file-text-o"></i> ' + esc(fileName + lineInfo) + '</span>';
}); });
@@ -141,7 +141,7 @@ function createAttachmentIndicator(messageId, count, namesJson) {
const ind = document.createElement('div'); const ind = document.createElement('div');
ind.className = 'attachment-indicator'; ind.className = 'attachment-indicator';
ind.innerHTML = `<i class="fa fa-paperclip"></i> ${count} Datei${count > 1 ? 'en' : ''}` + (nameList ? `: ${esc(nameList)}` : ''); ind.innerHTML = `<i class="fa fa-paperclip"></i> ${count} Datei${count > 1 ? 'en' : ''}` + (nameList ? `: ${esc(nameList)}` : '');
ind.style.cursor = 'pointer'; ind.classList.add('clickable');
ind.title = 'Klicken zum Anzeigen'; ind.title = 'Klicken zum Anzeigen';
ind.addEventListener('click', () => loadAndShowAttachments(messageId, ind)); ind.addEventListener('click', () => loadAndShowAttachments(messageId, ind));
return ind; return ind;
+1 -1
View File
@@ -303,7 +303,7 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
case 'error': { case 'error': {
var errDiv = document.createElement('div'); var errDiv = document.createElement('div');
errDiv.className = 'msg system-info' + (archived ? ' archived' : ''); errDiv.className = 'msg system-info' + (archived ? ' archived' : '');
errDiv.style.color = 'var(--dangerous)'; errDiv.classList.add('text-danger');
errDiv.textContent = (msg.content || '').trim(); errDiv.textContent = (msg.content || '').trim();
fragment.appendChild(errDiv); fragment.appendChild(errDiv);
break; break;
+17 -19
View File
@@ -72,7 +72,7 @@ async function showSystemPromptModal(sessionId) {
body.innerHTML = ''; body.innerHTML = '';
_renderSystemPromptBlocks(body, blocks); _renderSystemPromptBlocks(body, blocks);
} catch (e) { } catch (e) {
body.innerHTML = '<div class="sp-loading" style="color:var(--dangerous)">Fehler beim Laden des System-Prompts</div>'; body.innerHTML = '<div class="sp-loading text-danger">Fehler beim Laden des System-Prompts</div>';
} }
} }
@@ -106,7 +106,7 @@ function showKreaImageModal(titleText, fullUrl) {
img.className = 'krea-modal-image'; img.className = 'krea-modal-image';
img.alt = titleText; img.alt = titleText;
img.addEventListener('error', function() { img.addEventListener('error', function() {
body.innerHTML = '<div class="sp-loading" style="color:var(--dangerous)">Bild konnte nicht geladen werden</div>'; body.innerHTML = '<div class="sp-loading text-danger">Bild konnte nicht geladen werden</div>';
}); });
body.appendChild(img); body.appendChild(img);
@@ -137,7 +137,7 @@ function _openPickerModal(title, items, currentId, onSelect, options) {
const noneCard = document.createElement('div'); const noneCard = document.createElement('div');
noneCard.className = 'card agent-picker-item' + (!currentId ? ' selected' : ''); noneCard.className = 'card agent-picker-item' + (!currentId ? ' selected' : '');
noneCard.innerHTML = ` noneCard.innerHTML = `
<div class="card-image" style="display:flex;align-items:center;justify-content:center"><i class="fa ${esc(noneIcon)}" style="font-size:2em;opacity:var(--semi-transparent)"></i></div> <div class="card-image none-card-image"><i class="fa ${esc(noneIcon)} none-card-icon"></i></div>
<div class="card-body"> <div class="card-body">
<div class="card-title-row"> <div class="card-title-row">
<span class="card-title">${esc(noneLabel)}</span> <span class="card-title">${esc(noneLabel)}</span>
@@ -268,16 +268,14 @@ async function showOpenClawImportModal(sessionId) {
var confirmed = confirm('OpenClaw-Session importieren?\n\nSession: ' + openclawSession.sessionId.substring(0, 8) + '…\n' + openclawSession.totalMessages + ' Nachrichten\n\nVorhandene Imports werden ersetzt.'); var confirmed = confirm('OpenClaw-Session importieren?\n\nSession: ' + openclawSession.sessionId.substring(0, 8) + '…\n' + openclawSession.totalMessages + ' Nachrichten\n\nVorhandene Imports werden ersetzt.');
if (!confirmed) return; if (!confirmed) return;
card.style.opacity = '0.5'; card.classList.add('loading-state');
card.style.pointerEvents = 'none';
try { try {
var result = await apiImportOpenclawSession(openclawSession.sessionId, sessionId); var result = await apiImportOpenclawSession(openclawSession.sessionId, sessionId);
close(); close();
showToast(result.messageCount + ' Nachrichten in ' + result.chainCount + ' Chains importiert', 'success'); showToast(result.messageCount + ' Nachrichten in ' + result.chainCount + ' Chains importiert', 'success');
} catch (e) { } catch (e) {
card.style.opacity = '1'; card.classList.remove('loading-state');
card.style.pointerEvents = '';
showToast('Import fehlgeschlagen: ' + e.message, 'error'); showToast('Import fehlgeschlagen: ' + e.message, 'error');
} }
}); });
@@ -288,7 +286,7 @@ async function showOpenClawImportModal(sessionId) {
body.appendChild(list); body.appendChild(list);
} catch (e) { } catch (e) {
body.innerHTML = '<div class="sp-loading" style="color:var(--dangerous)">Fehler: ' + esc(e.message) + '</div>'; body.innerHTML = '<div class="sp-loading text-danger">Fehler: ' + esc(e.message) + '</div>';
} }
} }
@@ -308,14 +306,14 @@ async function showRemoteModal(sessionId) {
var empty = document.createElement('div'); var empty = document.createElement('div');
empty.className = 'sp-loading'; empty.className = 'sp-loading';
empty.innerHTML = 'Keine Remote-Verbindungen aktiv.<br><br>' + empty.innerHTML = 'Keine Remote-Verbindungen aktiv.<br><br>' +
'<span style="font-size:var(--font-size);opacity:var(--semi-transparent)">Auf dem Windows-PC ausführen:<br>' + '<span class="font-sm semi-transparent">Auf dem Windows-PC ausführen:<br>' +
'<code>irm ' + esc(location.origin) + '/remote | iex</code></span>'; '<code>irm ' + esc(location.origin) + '/remote | iex</code></span>';
body.appendChild(empty); body.appendChild(empty);
return; return;
} }
var hint = document.createElement('div'); var hint = document.createElement('div');
hint.style.cssText = 'font-size:var(--font-size);opacity:var(--semi-transparent);margin-bottom:var(--box-spacing)'; hint.className = 'remote-hint';
hint.textContent = 'Verbindung auswählen um Remote-Befehle in dieser Session zu ermöglichen:'; hint.textContent = 'Verbindung auswählen um Remote-Befehle in dieser Session zu ermöglichen:';
body.appendChild(hint); body.appendChild(hint);
@@ -323,7 +321,7 @@ async function showRemoteModal(sessionId) {
var conn = connections[i]; var conn = connections[i];
var card = document.createElement('div'); var card = document.createElement('div');
card.className = 'sp-block'; card.className = 'sp-block';
card.style.cursor = 'pointer'; card.classList.add('clickable');
var isAssigned = conn.assignedSessionId === sessionId; var isAssigned = conn.assignedSessionId === sessionId;
var isAssignedOther = conn.assignedSessionId && conn.assignedSessionId !== sessionId; var isAssignedOther = conn.assignedSessionId && conn.assignedSessionId !== sessionId;
@@ -331,17 +329,17 @@ async function showRemoteModal(sessionId) {
var label = document.createElement('div'); var label = document.createElement('div');
label.className = 'sp-block-label'; label.className = 'sp-block-label';
var statusIcon = isAssigned ? 'fa-check-circle' : (isAssignedOther ? 'fa-link' : 'fa-desktop'); var statusIcon = isAssigned ? 'fa-check-circle' : (isAssignedOther ? 'fa-link' : 'fa-desktop');
var statusColor = isAssigned ? 'color:var(--primary)' : ''; var statusClass = isAssigned ? ' text-primary' : '';
label.innerHTML = '<i class="fa ' + statusIcon + '" style="' + statusColor + '"></i> ' + label.innerHTML = '<i class="fa ' + statusIcon + statusClass + '"></i> ' +
esc(conn.username || '?') + '@' + esc(conn.hostname || '?'); esc(conn.username || '?') + '@' + esc(conn.hostname || '?');
card.appendChild(label); card.appendChild(label);
var content = document.createElement('div'); var content = document.createElement('div');
content.className = 'sp-block-content'; content.className = 'sp-block-content';
content.style.cssText = 'font-size:var(--font-size);display:flex;align-items:center;gap:var(--box-spacing)'; content.className = 'remote-card-content';
var info = document.createElement('span'); var info = document.createElement('span');
info.style.cssText = 'flex:1;opacity:var(--semi-transparent)'; info.className = 'remote-card-info';
var connDate = new Date(conn.connectedAt); var connDate = new Date(conn.connectedAt);
info.textContent = conn.os + ' • Verbunden seit ' + connDate.toLocaleTimeString('de'); info.textContent = conn.os + ' • Verbunden seit ' + connDate.toLocaleTimeString('de');
content.appendChild(info); content.appendChild(info);
@@ -349,14 +347,14 @@ async function showRemoteModal(sessionId) {
var btn = document.createElement('button'); var btn = document.createElement('button');
if (isAssigned) { if (isAssigned) {
btn.textContent = 'Trennen'; btn.textContent = 'Trennen';
btn.style.cssText = 'color:var(--dangerous)'; btn.classList.add('text-danger');
} else if (isAssignedOther) { } else if (isAssignedOther) {
btn.textContent = 'Andere Session'; btn.textContent = 'Andere Session';
btn.disabled = true; btn.disabled = true;
btn.style.cssText = 'opacity:var(--semi-transparent)'; btn.classList.add('semi-transparent');
} else { } else {
btn.textContent = 'Verbinden'; btn.textContent = 'Verbinden';
btn.style.cssText = 'color:var(--primary)'; btn.classList.add('text-primary');
} }
content.appendChild(btn); content.appendChild(btn);
@@ -383,7 +381,7 @@ async function showRemoteModal(sessionId) {
})(conn, isAssigned); })(conn, isAssigned);
} }
} catch (e) { } catch (e) {
body.innerHTML = '<div class="sp-loading" style="color:var(--dangerous)">Fehler beim Laden: ' + esc(e.message) + '</div>'; body.innerHTML = '<div class="sp-loading text-danger">Fehler beim Laden: ' + esc(e.message) + '</div>';
} }
} }
-2
View File
@@ -140,10 +140,8 @@ function _showShareMenu(anchorBtn) {
// Positionierung // Positionierung
const rect = anchorBtn.getBoundingClientRect(); const rect = anchorBtn.getBoundingClientRect();
menu.style.position = 'fixed';
menu.style.top = (rect.bottom + 4) + 'px'; menu.style.top = (rect.bottom + 4) + 'px';
menu.style.left = rect.left + 'px'; menu.style.left = rect.left + 'px';
menu.style.zIndex = '10000';
document.body.appendChild(menu); document.body.appendChild(menu);
+25 -27
View File
@@ -76,8 +76,7 @@ registerPage('api-keys', {
if (keys.length === 0) { if (keys.length === 0) {
var empty = document.createElement('div'); var empty = document.createElement('div');
empty.className = 'admin-user-meta'; empty.className = 'admin-user-meta pad-v';
empty.style.padding = '1rem 0';
empty.textContent = 'Keine API-Keys konfiguriert.'; empty.textContent = 'Keine API-Keys konfiguriert.';
list.appendChild(empty); list.appendChild(empty);
return; return;
@@ -118,13 +117,13 @@ registerPage('api-keys', {
// Toggle + Usage-Badge nebeneinander // Toggle + Usage-Badge nebeneinander
var badgeRow = document.createElement('div'); var badgeRow = document.createElement('div');
badgeRow.style.cssText = 'display:flex;align-items:center;gap:8px;margin-top:2px'; badgeRow.className = 'flex-row-tight';
var publicBtn = document.createElement('button'); var publicBtn = document.createElement('button');
publicBtn.className = 'icon-btn'; publicBtn.className = 'icon-btn';
publicBtn.title = key.isPublic ? 'Öffentlich (klicken zum Privatschalten)' : 'Privat (klicken zum Veröffentlichen)'; publicBtn.title = key.isPublic ? 'Öffentlich (klicken zum Privatschalten)' : 'Privat (klicken zum Veröffentlichen)';
publicBtn.innerHTML = key.isPublic publicBtn.innerHTML = key.isPublic
? '<i class="fa fa-globe" style="color:var(--accent)"></i>' ? '<i class="fa fa-globe text-accent"></i>'
: '<i class="fa fa-lock"></i>'; : '<i class="fa fa-lock"></i>';
publicBtn.addEventListener('click', function() { togglePublic(key); }); publicBtn.addEventListener('click', function() { togglePublic(key); });
badgeRow.appendChild(publicBtn); badgeRow.appendChild(publicBtn);
@@ -135,7 +134,7 @@ registerPage('api-keys', {
// Status-Zeile (für Check-Ergebnis) // Status-Zeile (für Check-Ergebnis)
var statusLine = document.createElement('div'); var statusLine = document.createElement('div');
statusLine.className = 'admin-user-meta'; statusLine.className = 'admin-user-meta';
statusLine.style.cssText = 'padding:0 var(--box-padding) .5rem;display:none;font-size:.85em'; statusLine.className = 'admin-user-meta check-status-line';
// Check – rechts neben Usage-Badge // Check – rechts neben Usage-Badge
if (key.provider === 'anthropic' || key.provider === 'openai' || key.provider === 'google') { if (key.provider === 'anthropic' || key.provider === 'openai' || key.provider === 'google') {
@@ -202,7 +201,7 @@ registerPage('api-keys', {
text.textContent = parts.join(' · '); text.textContent = parts.join(' · ');
statusLine.appendChild(text); statusLine.appendChild(text);
var badge = createUsageBadge(result.usage5h, result.usage7d); var badge = createUsageBadge(result.usage5h, result.usage7d);
if (badge) { badge.style.marginTop = '4px'; statusLine.appendChild(badge); } if (badge) { badge.classList.add('mt-xs'); statusLine.appendChild(badge); }
} else { } else {
statusLine.textContent = '❌ ' + (result.message || 'Unbekannter Fehler'); statusLine.textContent = '❌ ' + (result.message || 'Unbekannter Fehler');
} }
@@ -350,7 +349,7 @@ registerPage('api-keys', {
if (!summary || summary.length === 0) { if (!summary || summary.length === 0) {
var empty = document.createElement('div'); var empty = document.createElement('div');
empty.className = 'admin-user-meta'; empty.className = 'admin-user-meta';
empty.style.padding = '1rem 0'; empty.className = 'admin-user-meta pad-v';
empty.textContent = 'Keine gescannten Keys vorhanden.'; empty.textContent = 'Keine gescannten Keys vorhanden.';
scannedList.appendChild(empty); scannedList.appendChild(empty);
return; return;
@@ -358,8 +357,7 @@ registerPage('api-keys', {
summary.forEach(function(s) { summary.forEach(function(s) {
var row = document.createElement('div'); var row = document.createElement('div');
row.className = 'admin-user-row'; row.className = 'admin-user-row clickable';
row.style.cursor = 'pointer';
var info = document.createElement('div'); var info = document.createElement('div');
info.className = 'admin-user-info'; info.className = 'admin-user-info';
@@ -382,7 +380,7 @@ registerPage('api-keys', {
var badge = document.createElement('div'); var badge = document.createElement('div');
badge.className = 'admin-user-actions'; badge.className = 'admin-user-actions';
badge.innerHTML = '<i class="fa fa-chevron-right" style="opacity:.5"></i>'; badge.innerHTML = '<i class="fa fa-chevron-right icon-dim"></i>';
row.appendChild(info); row.appendChild(info);
row.appendChild(badge); row.appendChild(badge);
@@ -397,8 +395,7 @@ registerPage('api-keys', {
// Zurück-Button // Zurück-Button
var backRow = document.createElement('div'); var backRow = document.createElement('div');
backRow.className = 'admin-user-row'; backRow.className = 'admin-user-row';
backRow.style.cursor = 'pointer'; backRow.classList.add('clickable', 'semi-dim');
backRow.style.opacity = '.7';
var backInfo = document.createElement('div'); var backInfo = document.createElement('div');
backInfo.className = 'admin-user-info'; backInfo.className = 'admin-user-info';
var backName = document.createElement('span'); var backName = document.createElement('span');
@@ -414,7 +411,7 @@ registerPage('api-keys', {
var uncheckedKeys = visibleKeys.filter(function(sk) { return sk.status === 'unchecked'; }); var uncheckedKeys = visibleKeys.filter(function(sk) { return sk.status === 'unchecked'; });
if (uncheckedKeys.length > 0) { if (uncheckedKeys.length > 0) {
var toolbar = document.createElement('div'); var toolbar = document.createElement('div');
toolbar.style.cssText = 'display:flex;align-items:center;gap:8px;padding:8px var(--box-padding);border-bottom:1px solid var(--border)'; toolbar.className = 'scanner-toolbar';
var checkUncheckedBtn = document.createElement('button'); var checkUncheckedBtn = document.createElement('button');
checkUncheckedBtn.className = 'section-add-btn'; checkUncheckedBtn.className = 'section-add-btn';
@@ -422,7 +419,7 @@ registerPage('api-keys', {
var progressSpan = document.createElement('span'); var progressSpan = document.createElement('span');
progressSpan.className = 'admin-user-meta'; progressSpan.className = 'admin-user-meta';
progressSpan.style.marginLeft = '8px'; progressSpan.classList.add('ml-sm');
toolbar.appendChild(checkUncheckedBtn); toolbar.appendChild(checkUncheckedBtn);
toolbar.appendChild(progressSpan); toolbar.appendChild(progressSpan);
@@ -435,7 +432,7 @@ registerPage('api-keys', {
var stopBtn = document.createElement('button'); var stopBtn = document.createElement('button');
stopBtn.className = 'icon-btn'; stopBtn.className = 'icon-btn';
stopBtn.title = 'Abbrechen'; stopBtn.title = 'Abbrechen';
stopBtn.innerHTML = '<i class="fa fa-stop" style="color:var(--danger)"></i>'; stopBtn.innerHTML = '<i class="fa fa-stop text-danger"></i>';
stopBtn.addEventListener('click', function() { checkUncheckedAbort = true; }); stopBtn.addEventListener('click', function() { checkUncheckedAbort = true; });
toolbar.appendChild(stopBtn); toolbar.appendChild(stopBtn);
@@ -474,7 +471,7 @@ registerPage('api-keys', {
if (visibleKeys.length === 0) { if (visibleKeys.length === 0) {
var empty = document.createElement('div'); var empty = document.createElement('div');
empty.className = 'admin-user-meta'; empty.className = 'admin-user-meta';
empty.style.padding = '1rem 0'; empty.className = 'admin-user-meta pad-v';
empty.textContent = 'Keine nicht-übernommenen Keys in dieser Kategorie.'; empty.textContent = 'Keine nicht-übernommenen Keys in dieser Kategorie.';
scannedList.appendChild(empty); scannedList.appendChild(empty);
return; return;
@@ -487,7 +484,7 @@ registerPage('api-keys', {
var info = document.createElement('div'); var info = document.createElement('div');
info.className = 'admin-user-info'; info.className = 'admin-user-info';
info.style.minWidth = '0'; info.classList.add('min-w-0');
if (sk.sourceUrl) { if (sk.sourceUrl) {
var nameSpan = document.createElement('a'); var nameSpan = document.createElement('a');
@@ -540,7 +537,7 @@ registerPage('api-keys', {
var adoptBtn = document.createElement('button'); var adoptBtn = document.createElement('button');
adoptBtn.className = 'icon-btn'; adoptBtn.className = 'icon-btn';
adoptBtn.title = 'Als API-Key übernehmen'; adoptBtn.title = 'Als API-Key übernehmen';
adoptBtn.innerHTML = '<i class="fa fa-plus-circle" style="color:var(--accent)"></i>'; adoptBtn.innerHTML = '<i class="fa fa-plus-circle text-accent"></i>';
adoptBtn.addEventListener('click', async function(e) { adoptBtn.addEventListener('click', async function(e) {
e.stopPropagation(); e.stopPropagation();
try { try {
@@ -582,7 +579,7 @@ registerPage('api-keys', {
async function loadScannedKeysByType(type) { async function loadScannedKeysByType(type) {
selectedType = type; selectedType = type;
scannedList.innerHTML = '<div class="admin-user-meta" style="padding:1rem 0"><i class="fa fa-spinner fa-spin"></i> Lade Keys…</div>'; scannedList.innerHTML = '<div class="admin-user-meta pad-v"><i class="fa fa-spinner fa-spin"></i> Lade Keys…</div>';
try { try {
scannedKeys = await apiGetScannedKeys(type); scannedKeys = await apiGetScannedKeys(type);
renderScannedKeys(); renderScannedKeys();
@@ -619,8 +616,8 @@ registerPage('api-keys', {
if (!el) return; if (!el) return;
try { try {
var s = await apiEventScannerStatus(); var s = await apiEventScannerStatus();
if (!s.enabled) { el.style.display = 'none'; return; } if (!s.enabled) { el.hidden = true; return; }
el.style.display = 'block'; el.hidden = false;
// Status-Zeile // Status-Zeile
var parts = ['🔴 Event Scanner']; var parts = ['🔴 Event Scanner'];
@@ -651,26 +648,27 @@ registerPage('api-keys', {
// Immer klickbare Status-Zeile rendern // Immer klickbare Status-Zeile rendern
var wasOpen = false; var wasOpen = false;
var oldLog = document.getElementById('eventScannerLog'); var oldLog = document.getElementById('eventScannerLog');
if (oldLog) wasOpen = oldLog.style.display !== 'none'; if (oldLog) wasOpen = !oldLog.hidden;
el.innerHTML = ''; el.innerHTML = '';
var statusEl = document.createElement('div'); var statusEl = document.createElement('div');
statusEl.style.cssText = 'cursor:pointer'; statusEl.className = 'clickable';
statusEl.title = logLines.length > 0 ? 'Klicken für Log' : ''; statusEl.title = logLines.length > 0 ? 'Klicken für Log' : '';
statusEl.textContent = statusLine; statusEl.textContent = statusLine;
el.appendChild(statusEl); el.appendChild(statusEl);
var logEl = document.createElement('div'); var logEl = document.createElement('div');
logEl.id = 'eventScannerLog'; logEl.id = 'eventScannerLog';
logEl.style.cssText = 'white-space:pre-line;display:none'; logEl.className = 'event-scanner-log';
logEl.hidden = true;
logEl.textContent = logLines.length > 0 ? logLines.join('\n') : 'Noch keine Log-Einträge…'; logEl.textContent = logLines.length > 0 ? logLines.join('\n') : 'Noch keine Log-Einträge…';
if (wasOpen) logEl.style.display = 'block'; if (wasOpen) logEl.hidden = false;
el.appendChild(logEl); el.appendChild(logEl);
statusEl.addEventListener('click', function() { statusEl.addEventListener('click', function() {
logEl.style.display = logEl.style.display === 'none' ? 'block' : 'none'; logEl.hidden = !logEl.hidden;
}); });
} catch(e) { el.style.display = 'none'; } } catch(e) { el.hidden = true; }
} }
function formatScanProgress(s) { function formatScanProgress(s) {
+5 -7
View File
@@ -104,7 +104,7 @@ function _renderChatUsageBadge(container, key) {
_showKeySwitchModal(); _showKeySwitchModal();
}); });
badge.title = (key.name || 'API Key') + ' · ' + (key.plan || '?'); badge.title = (key.name || 'API Key') + ' · ' + (key.plan || '?');
badge.style.cursor = 'pointer'; badge.classList.add('clickable');
container.appendChild(badge); container.appendChild(badge);
// Check-Button nur für Admins // Check-Button nur für Admins
@@ -143,7 +143,7 @@ async function _showKeySwitchModal() {
if (keys.length === 0) { if (keys.length === 0) {
var empty = document.createElement('div'); var empty = document.createElement('div');
empty.style.cssText = 'padding:1rem;text-align:center;opacity:0.7'; empty.className = 'empty-hint';
empty.textContent = 'Keine Keys verfügbar. Ein Admin muss Keys als öffentlich markieren.'; empty.textContent = 'Keine Keys verfügbar. Ein Admin muss Keys als öffentlich markieren.';
body.appendChild(empty); body.appendChild(empty);
return; return;
@@ -183,18 +183,16 @@ async function _showKeySwitchModal() {
} }
if (key.keyId !== selectedKeyId) { if (key.keyId !== selectedKeyId) {
row.style.cursor = 'pointer'; row.classList.add('clickable');
row.addEventListener('click', async function() { row.addEventListener('click', async function() {
row.style.opacity = '0.5'; row.classList.add('loading-state');
row.style.pointerEvents = 'none';
try { try {
await apiSelectApiKey(key.keyId); await apiSelectApiKey(key.keyId);
close(); close();
await _initChatUsageBadge(); await _initChatUsageBadge();
} catch(e) { } catch(e) {
console.error('Key switch failed:', e); console.error('Key switch failed:', e);
row.style.opacity = ''; row.classList.remove('loading-state');
row.style.pointerEvents = '';
} }
}); });
} }
+2 -2
View File
@@ -160,10 +160,10 @@ function updateCronPreview(input, preview) {
const desc = describeCron(expr); const desc = describeCron(expr);
if (desc) { if (desc) {
preview.textContent = desc; preview.textContent = desc;
preview.style.color = ''; preview.classList.remove('text-error');
} else { } else {
preview.textContent = 'Ungültige Cron-Expression'; preview.textContent = 'Ungültige Cron-Expression';
preview.style.color = 'var(--color-error)'; preview.classList.add('text-error');
} }
} }
+3 -3
View File
@@ -66,10 +66,10 @@ registerPage('db-explorer', {
async function loadTableData(name, page) { async function loadTableData(name, page) {
currentTable = name; currentTable = name;
titleEl.innerHTML = '<span class="db-back-link">Datenbank-Explorer</span> <i class="fa fa-chevron-right" style="opacity:.4;font-size:.7em;margin:0 .3em"></i> ' + esc(name); titleEl.innerHTML = '<span class="db-back-link">Datenbank-Explorer</span> <i class="fa fa-chevron-right chevron-separator"></i> ' + esc(name);
// Back-Link klickbar // Back-Link klickbar
titleEl.querySelector('.db-back-link').style.cursor = 'pointer'; titleEl.querySelector('.db-back-link').classList.add('clickable');
titleEl.querySelector('.db-back-link').addEventListener('click', function() { titleEl.querySelector('.db-back-link').addEventListener('click', function() {
loadTables(); loadTables();
}); });
@@ -129,7 +129,7 @@ registerPage('db-explorer', {
data.columns.forEach(function(col) { data.columns.forEach(function(col) {
var th = document.createElement('th'); var th = document.createElement('th');
th.textContent = col.name; th.textContent = col.name;
if (col.pk) th.innerHTML += ' <i class="fa fa-key" style="opacity:.4;font-size:.75em"></i>'; if (col.pk) th.innerHTML += ' <i class="fa fa-key icon-dim-sm"></i>';
th.title = col.type + (col.notnull ? ' NOT NULL' : '') + (col.pk ? ' PRIMARY KEY' : ''); th.title = col.type + (col.notnull ? ' NOT NULL' : '') + (col.pk ? ' PRIMARY KEY' : '');
headerRow.appendChild(th); headerRow.appendChild(th);
}); });
+1 -1
View File
@@ -12,7 +12,7 @@ registerPage('settings', {
// Backup nur für Admins // Backup nur für Admins
if (currentUser && currentUser.isAdmin) { if (currentUser && currentUser.isAdmin) {
backupSection.style.display = ''; backupSection.hidden = false;
} }
const s = loadSettings(); const s = loadSettings();
+1 -1
View File
@@ -11,7 +11,7 @@ fetch('/api/info').then(r => r.json()).then(data => {
function _showEmbeddingWarning() { function _showEmbeddingWarning() {
const { body } = _createModal('⚠️ Embedding-Modell nicht gefunden'); const { body } = _createModal('⚠️ Embedding-Modell nicht gefunden');
body.style.lineHeight = '1.7'; body.classList.add('lh-relaxed');
body.innerHTML = body.innerHTML =
'<p>Das Embedding-Modell <strong>all-MiniLM-L6-v2</strong> wurde nicht gefunden. ' + '<p>Das Embedding-Modell <strong>all-MiniLM-L6-v2</strong> wurde nicht gefunden. ' +
'Ohne dieses Modell ist die semantische Suche (<code>memory_search</code>) deaktiviert.</p>' + 'Ohne dieses Modell ist die semantische Suche (<code>memory_search</code>) deaktiviert.</p>' +
+1 -1
View File
@@ -156,7 +156,7 @@ function renderToolBoxContent(div, name, inputJson, result, isError, sources) {
} }
if (foldTarget && name !== 'todo_write') { if (foldTarget && name !== 'todo_write') {
header.style.cursor = 'pointer'; header.classList.add('clickable');
header.addEventListener('click', () => { header.addEventListener('click', () => {
foldTarget.hidden = !foldTarget.hidden; foldTarget.hidden = !foldTarget.hidden;
}); });