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

+2 -2
View File
@@ -55,7 +55,7 @@ var AvatarEditor = (function () {
renderPreview();
// Click → Modal öffnen
previewEl.style.cursor = 'pointer';
previewEl.classList.add('clickable');
previewEl.addEventListener('click', openModal);
// Paste Handler (global, immer aktiv)
@@ -326,7 +326,7 @@ var AvatarEditor = (function () {
pasteHandler = null;
}
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 fileName = filePath.includes('/') ? filePath.substring(filePath.lastIndexOf('/') + 1) : filePath;
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>';
});
@@ -141,7 +141,7 @@ function createAttachmentIndicator(messageId, count, namesJson) {
const ind = document.createElement('div');
ind.className = 'attachment-indicator';
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.addEventListener('click', () => loadAndShowAttachments(messageId, ind));
return ind;
+1 -1
View File
@@ -303,7 +303,7 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
case 'error': {
var errDiv = document.createElement('div');
errDiv.className = 'msg system-info' + (archived ? ' archived' : '');
errDiv.style.color = 'var(--dangerous)';
errDiv.classList.add('text-danger');
errDiv.textContent = (msg.content || '').trim();
fragment.appendChild(errDiv);
break;
+17 -19
View File
@@ -72,7 +72,7 @@ async function showSystemPromptModal(sessionId) {
body.innerHTML = '';
_renderSystemPromptBlocks(body, blocks);
} 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.alt = titleText;
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);
@@ -137,7 +137,7 @@ function _openPickerModal(title, items, currentId, onSelect, options) {
const noneCard = document.createElement('div');
noneCard.className = 'card agent-picker-item' + (!currentId ? ' selected' : '');
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-title-row">
<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.');
if (!confirmed) return;
card.style.opacity = '0.5';
card.style.pointerEvents = 'none';
card.classList.add('loading-state');
try {
var result = await apiImportOpenclawSession(openclawSession.sessionId, sessionId);
close();
showToast(result.messageCount + ' Nachrichten in ' + result.chainCount + ' Chains importiert', 'success');
} catch (e) {
card.style.opacity = '1';
card.style.pointerEvents = '';
card.classList.remove('loading-state');
showToast('Import fehlgeschlagen: ' + e.message, 'error');
}
});
@@ -288,7 +286,7 @@ async function showOpenClawImportModal(sessionId) {
body.appendChild(list);
} 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');
empty.className = 'sp-loading';
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>';
body.appendChild(empty);
return;
}
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:';
body.appendChild(hint);
@@ -323,7 +321,7 @@ async function showRemoteModal(sessionId) {
var conn = connections[i];
var card = document.createElement('div');
card.className = 'sp-block';
card.style.cursor = 'pointer';
card.classList.add('clickable');
var isAssigned = conn.assignedSessionId === sessionId;
var isAssignedOther = conn.assignedSessionId && conn.assignedSessionId !== sessionId;
@@ -331,17 +329,17 @@ async function showRemoteModal(sessionId) {
var label = document.createElement('div');
label.className = 'sp-block-label';
var statusIcon = isAssigned ? 'fa-check-circle' : (isAssignedOther ? 'fa-link' : 'fa-desktop');
var statusColor = isAssigned ? 'color:var(--primary)' : '';
label.innerHTML = '<i class="fa ' + statusIcon + '" style="' + statusColor + '"></i> ' +
var statusClass = isAssigned ? ' text-primary' : '';
label.innerHTML = '<i class="fa ' + statusIcon + statusClass + '"></i> ' +
esc(conn.username || '?') + '@' + esc(conn.hostname || '?');
card.appendChild(label);
var content = document.createElement('div');
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');
info.style.cssText = 'flex:1;opacity:var(--semi-transparent)';
info.className = 'remote-card-info';
var connDate = new Date(conn.connectedAt);
info.textContent = conn.os + ' • Verbunden seit ' + connDate.toLocaleTimeString('de');
content.appendChild(info);
@@ -349,14 +347,14 @@ async function showRemoteModal(sessionId) {
var btn = document.createElement('button');
if (isAssigned) {
btn.textContent = 'Trennen';
btn.style.cssText = 'color:var(--dangerous)';
btn.classList.add('text-danger');
} else if (isAssignedOther) {
btn.textContent = 'Andere Session';
btn.disabled = true;
btn.style.cssText = 'opacity:var(--semi-transparent)';
btn.classList.add('semi-transparent');
} else {
btn.textContent = 'Verbinden';
btn.style.cssText = 'color:var(--primary)';
btn.classList.add('text-primary');
}
content.appendChild(btn);
@@ -383,7 +381,7 @@ async function showRemoteModal(sessionId) {
})(conn, isAssigned);
}
} 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
const rect = anchorBtn.getBoundingClientRect();
menu.style.position = 'fixed';
menu.style.top = (rect.bottom + 4) + 'px';
menu.style.left = rect.left + 'px';
menu.style.zIndex = '10000';
document.body.appendChild(menu);
+25 -27
View File
@@ -76,8 +76,7 @@ registerPage('api-keys', {
if (keys.length === 0) {
var empty = document.createElement('div');
empty.className = 'admin-user-meta';
empty.style.padding = '1rem 0';
empty.className = 'admin-user-meta pad-v';
empty.textContent = 'Keine API-Keys konfiguriert.';
list.appendChild(empty);
return;
@@ -118,13 +117,13 @@ registerPage('api-keys', {
// Toggle + Usage-Badge nebeneinander
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');
publicBtn.className = 'icon-btn';
publicBtn.title = key.isPublic ? 'Öffentlich (klicken zum Privatschalten)' : 'Privat (klicken zum Veröffentlichen)';
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>';
publicBtn.addEventListener('click', function() { togglePublic(key); });
badgeRow.appendChild(publicBtn);
@@ -135,7 +134,7 @@ registerPage('api-keys', {
// Status-Zeile (für Check-Ergebnis)
var statusLine = document.createElement('div');
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
if (key.provider === 'anthropic' || key.provider === 'openai' || key.provider === 'google') {
@@ -202,7 +201,7 @@ registerPage('api-keys', {
text.textContent = parts.join(' · ');
statusLine.appendChild(text);
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 {
statusLine.textContent = '❌ ' + (result.message || 'Unbekannter Fehler');
}
@@ -350,7 +349,7 @@ registerPage('api-keys', {
if (!summary || summary.length === 0) {
var empty = document.createElement('div');
empty.className = 'admin-user-meta';
empty.style.padding = '1rem 0';
empty.className = 'admin-user-meta pad-v';
empty.textContent = 'Keine gescannten Keys vorhanden.';
scannedList.appendChild(empty);
return;
@@ -358,8 +357,7 @@ registerPage('api-keys', {
summary.forEach(function(s) {
var row = document.createElement('div');
row.className = 'admin-user-row';
row.style.cursor = 'pointer';
row.className = 'admin-user-row clickable';
var info = document.createElement('div');
info.className = 'admin-user-info';
@@ -382,7 +380,7 @@ registerPage('api-keys', {
var badge = document.createElement('div');
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(badge);
@@ -397,8 +395,7 @@ registerPage('api-keys', {
// Zurück-Button
var backRow = document.createElement('div');
backRow.className = 'admin-user-row';
backRow.style.cursor = 'pointer';
backRow.style.opacity = '.7';
backRow.classList.add('clickable', 'semi-dim');
var backInfo = document.createElement('div');
backInfo.className = 'admin-user-info';
var backName = document.createElement('span');
@@ -414,7 +411,7 @@ registerPage('api-keys', {
var uncheckedKeys = visibleKeys.filter(function(sk) { return sk.status === 'unchecked'; });
if (uncheckedKeys.length > 0) {
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');
checkUncheckedBtn.className = 'section-add-btn';
@@ -422,7 +419,7 @@ registerPage('api-keys', {
var progressSpan = document.createElement('span');
progressSpan.className = 'admin-user-meta';
progressSpan.style.marginLeft = '8px';
progressSpan.classList.add('ml-sm');
toolbar.appendChild(checkUncheckedBtn);
toolbar.appendChild(progressSpan);
@@ -435,7 +432,7 @@ registerPage('api-keys', {
var stopBtn = document.createElement('button');
stopBtn.className = 'icon-btn';
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; });
toolbar.appendChild(stopBtn);
@@ -474,7 +471,7 @@ registerPage('api-keys', {
if (visibleKeys.length === 0) {
var empty = document.createElement('div');
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.';
scannedList.appendChild(empty);
return;
@@ -487,7 +484,7 @@ registerPage('api-keys', {
var info = document.createElement('div');
info.className = 'admin-user-info';
info.style.minWidth = '0';
info.classList.add('min-w-0');
if (sk.sourceUrl) {
var nameSpan = document.createElement('a');
@@ -540,7 +537,7 @@ registerPage('api-keys', {
var adoptBtn = document.createElement('button');
adoptBtn.className = 'icon-btn';
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) {
e.stopPropagation();
try {
@@ -582,7 +579,7 @@ registerPage('api-keys', {
async function loadScannedKeysByType(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 {
scannedKeys = await apiGetScannedKeys(type);
renderScannedKeys();
@@ -619,8 +616,8 @@ registerPage('api-keys', {
if (!el) return;
try {
var s = await apiEventScannerStatus();
if (!s.enabled) { el.style.display = 'none'; return; }
el.style.display = 'block';
if (!s.enabled) { el.hidden = true; return; }
el.hidden = false;
// Status-Zeile
var parts = ['🔴 Event Scanner'];
@@ -651,26 +648,27 @@ registerPage('api-keys', {
// Immer klickbare Status-Zeile rendern
var wasOpen = false;
var oldLog = document.getElementById('eventScannerLog');
if (oldLog) wasOpen = oldLog.style.display !== 'none';
if (oldLog) wasOpen = !oldLog.hidden;
el.innerHTML = '';
var statusEl = document.createElement('div');
statusEl.style.cssText = 'cursor:pointer';
statusEl.className = 'clickable';
statusEl.title = logLines.length > 0 ? 'Klicken für Log' : '';
statusEl.textContent = statusLine;
el.appendChild(statusEl);
var logEl = document.createElement('div');
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…';
if (wasOpen) logEl.style.display = 'block';
if (wasOpen) logEl.hidden = false;
el.appendChild(logEl);
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) {
+5 -7
View File
@@ -104,7 +104,7 @@ function _renderChatUsageBadge(container, key) {
_showKeySwitchModal();
});
badge.title = (key.name || 'API Key') + ' · ' + (key.plan || '?');
badge.style.cursor = 'pointer';
badge.classList.add('clickable');
container.appendChild(badge);
// Check-Button nur für Admins
@@ -143,7 +143,7 @@ async function _showKeySwitchModal() {
if (keys.length === 0) {
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.';
body.appendChild(empty);
return;
@@ -183,18 +183,16 @@ async function _showKeySwitchModal() {
}
if (key.keyId !== selectedKeyId) {
row.style.cursor = 'pointer';
row.classList.add('clickable');
row.addEventListener('click', async function() {
row.style.opacity = '0.5';
row.style.pointerEvents = 'none';
row.classList.add('loading-state');
try {
await apiSelectApiKey(key.keyId);
close();
await _initChatUsageBadge();
} catch(e) {
console.error('Key switch failed:', e);
row.style.opacity = '';
row.style.pointerEvents = '';
row.classList.remove('loading-state');
}
});
}
+2 -2
View File
@@ -160,10 +160,10 @@ function updateCronPreview(input, preview) {
const desc = describeCron(expr);
if (desc) {
preview.textContent = desc;
preview.style.color = '';
preview.classList.remove('text-error');
} else {
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) {
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
titleEl.querySelector('.db-back-link').style.cursor = 'pointer';
titleEl.querySelector('.db-back-link').classList.add('clickable');
titleEl.querySelector('.db-back-link').addEventListener('click', function() {
loadTables();
});
@@ -129,7 +129,7 @@ registerPage('db-explorer', {
data.columns.forEach(function(col) {
var th = document.createElement('th');
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' : '');
headerRow.appendChild(th);
});
+1 -1
View File
@@ -12,7 +12,7 @@ registerPage('settings', {
// Backup nur für Admins
if (currentUser && currentUser.isAdmin) {
backupSection.style.display = '';
backupSection.hidden = false;
}
const s = loadSettings();
+1 -1
View File
@@ -11,7 +11,7 @@ fetch('/api/info').then(r => r.json()).then(data => {
function _showEmbeddingWarning() {
const { body } = _createModal('⚠️ Embedding-Modell nicht gefunden');
body.style.lineHeight = '1.7';
body.classList.add('lh-relaxed');
body.innerHTML =
'<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>' +
+1 -1
View File
@@ -156,7 +156,7 @@ function renderToolBoxContent(div, name, inputJson, result, isError, sources) {
}
if (foldTarget && name !== 'todo_write') {
header.style.cursor = 'pointer';
header.classList.add('clickable');
header.addEventListener('click', () => {
foldTarget.hidden = !foldTarget.hidden;
});