cleanup: archive search results — extract 10 inline styles into row classes

renderArchiveSearchResults was building each result row as an HTML
template literal carrying ~10 inline-style props per row (flex
layouts, padding, border-bottom, font-sizes, secondary text colour,
ellipsis truncation, gap...). For a 200-hit search that meant
~2KB of duplicated inline style noise in the DOM and made any
visual tweak require editing the renderer.

Extracted to a .archive-result-* family in styles.css:
- .archive-result-row + hover-tint (table-row scannability — was
  missing before, every row read flat)
- .archive-result-body / -meta / -streamer / -date / -filename /
  -size / -actions for the column layout
- .archive-type-badge with .live + .vod modifiers for the LIVE/VOD
  pill (was two separate inline-styled spans with hard-coded
  rgba colours)
- .archive-no-matches for the empty-state line

Dates + sizes in the row pick up font-variant-numeric: tabular-nums
so columns of numbers align even when filenames are different
widths. Last-child gets its bottom border dropped so the list
doesnt end on a dangling line — same treatment as the storage
stats table.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
xRangerDE 2026-05-11 04:45:38 +02:00
parent 58f8164db4
commit a2b7a02db7
2 changed files with 102 additions and 12 deletions

View File

@ -110,15 +110,13 @@ function renderArchiveSearchResults(result: ArchiveSearchResult): void {
}
if (result.hits.length === 0) {
applyArchiveHtml(resultsEl, `<div style="color: var(--text-secondary); padding: 12px;">${escapeArchiveHtml(UI_TEXT.static.archiveNoMatches || 'Keine Treffer.')}</div>`);
applyArchiveHtml(resultsEl, `<div class="archive-no-matches">${escapeArchiveHtml(UI_TEXT.static.archiveNoMatches || 'Keine Treffer.')}</div>`);
return;
}
const rows = result.hits.map((hit) => {
const date = new Date(hit.mtimeMs).toLocaleString();
const typeBadge = hit.type === 'live'
? `<span style="background: rgba(255,68,68,0.18); color: #ff4444; font-size: 10px; font-weight:700; padding: 2px 6px; border-radius: 3px;">LIVE</span>`
: `<span style="background: rgba(145,70,255,0.18); color: #9146ff; font-size: 10px; font-weight:700; padding: 2px 6px; border-radius: 3px;">VOD</span>`;
const typeBadge = `<span class="archive-type-badge ${hit.type === 'live' ? 'live' : 'vod'}">${hit.type === 'live' ? 'LIVE' : 'VOD'}</span>`;
const safeFullAttr = hit.fullPath.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
const chatBtn = hit.chatPath
? `<button class="queue-detail-btn" onclick="openEventsOrChat('${safeFullAttr.replace(/\.(mp4|mkv|ts|m4v)$/i, '.chat.jsonl')}', '${escapeArchiveHtml(hit.fileName)}', 'chat')">${escapeArchiveHtml(UI_TEXT.static.archiveViewChat || 'Chat')}</button>`
@ -127,17 +125,17 @@ function renderArchiveSearchResults(result: ArchiveSearchResult): void {
? `<button class="queue-detail-btn" onclick="openEventsOrChat('${(hit.eventsPath || '').replace(/\\/g, '\\\\').replace(/'/g, "\\'")}', '${escapeArchiveHtml(hit.fileName)}', 'events')">${escapeArchiveHtml(UI_TEXT.static.archiveViewEvents || 'Events')}</button>`
: '';
return `
<div style="display:flex; padding: 10px 8px; border-bottom: 1px solid var(--border-soft); gap: 10px; align-items: center;">
<div style="flex: 1; min-width: 0;">
<div style="display:flex; gap: 8px; align-items: center; margin-bottom: 4px;">
<div class="archive-result-row">
<div class="archive-result-body">
<div class="archive-result-meta">
${typeBadge}
<strong style="color: var(--text);">${escapeArchiveHtml(hit.streamer)}</strong>
<span style="font-size: 12px; color: var(--text-secondary);">${escapeArchiveHtml(date)}</span>
<strong class="archive-result-streamer">${escapeArchiveHtml(hit.streamer)}</strong>
<span class="archive-result-date">${escapeArchiveHtml(date)}</span>
</div>
<div style="font-size: 13px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="${escapeArchiveHtml(hit.fullPath)}">${escapeArchiveHtml(hit.fileName)}</div>
<div style="font-size: 11px; color: var(--text-secondary); margin-top: 2px;">${escapeArchiveHtml(formatBytesForArchive(hit.size))}</div>
<div class="archive-result-filename" title="${escapeArchiveHtml(hit.fullPath)}">${escapeArchiveHtml(hit.fileName)}</div>
<div class="archive-result-size">${escapeArchiveHtml(formatBytesForArchive(hit.size))}</div>
</div>
<div style="display:flex; flex-direction: column; gap: 4px; flex-shrink: 0;">
<div class="archive-result-actions">
<button class="queue-detail-btn" onclick="openFilePath('${safeFullAttr}')">${escapeArchiveHtml(UI_TEXT.static.archiveOpen || 'Oeffnen')}</button>
<button class="queue-detail-btn" onclick="showFileInFolder('${safeFullAttr}')">${escapeArchiveHtml(UI_TEXT.static.archiveShowInFolder || 'Ordner')}</button>
${chatBtn}

View File

@ -2116,6 +2116,98 @@ select option {
margin-top: 10px;
}
/* ============================================
ARCHIVE SEARCH RESULTS row layout
============================================
Replaces ~10 inline-styled divs in renderer-archive's row template
with reusable classes. Hover background scoped to the row so the
list scans as a real interactive list. */
.archive-no-matches {
color: var(--text-secondary);
padding: 12px;
}
.archive-result-row {
display: flex;
padding: 10px 8px;
border-bottom: 1px solid var(--border-soft);
gap: 10px;
align-items: center;
transition: background 0.12s;
}
.archive-result-row:hover {
background: rgba(255, 255, 255, 0.03);
}
.archive-result-row:last-child {
border-bottom: none;
}
.archive-result-body {
flex: 1;
min-width: 0;
}
.archive-result-meta {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 4px;
flex-wrap: wrap;
}
.archive-result-streamer {
color: var(--text);
}
.archive-result-date {
font-size: 12px;
color: var(--text-secondary);
font-variant-numeric: tabular-nums;
}
.archive-result-filename {
font-size: 13px;
color: var(--text);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.archive-result-size {
font-size: 11px;
color: var(--text-secondary);
margin-top: 2px;
font-variant-numeric: tabular-nums;
}
.archive-result-actions {
display: flex;
flex-direction: column;
gap: 4px;
flex-shrink: 0;
}
/* Type pill — LIVE / VOD chip in the archive row's meta line. */
.archive-type-badge {
font-size: 10px;
font-weight: 700;
padding: 2px 6px;
border-radius: 3px;
letter-spacing: 0.3px;
}
.archive-type-badge.live {
background: rgba(255, 68, 68, 0.18);
color: #ff4444;
}
.archive-type-badge.vod {
background: rgba(145, 70, 255, 0.18);
color: #9146ff;
}
/* Old generic scrollbar rules were dead superseded by the
purple-themed *::-webkit-scrollbar block further down the file.
Removed to avoid confusion when someone greps for scrollbar styles. */