Procházet zdrojové kódy

fix: switch feeds table from flex divs to proper <table> element

The flexbox div approach had rendering issues (header misaligned, columns
not lining up). Replaced with a real <table class='feeds-table'> with
<thead>/<tbody>, native <th>/<td> cells, and border-collapse for clean
row borders. Column widths are now enforced by the table layout engine:
38px checkbox cols (centered), flexible URL col, right-aligned hint col.
Lukas Goldschmidt před 5 dny
rodič
revize
b96f508418
2 změnil soubory, kde provedl 45 přidání a 57 odebrání
  1. 15 21
      dashboard/dashboard.js
  2. 30 36
      dashboard/style.css

+ 15 - 21
dashboard/dashboard.js

@@ -146,15 +146,13 @@ function renderFeedsList() {
   var html = '<div style="margin-bottom:.75rem;display:flex;justify-content:space-between;align-items:center">' +
     '<span style="font-size:.82rem;color:var(--text-dim)">' + enabledCount + ' / ' + _feedsData.length + ' feeds enabled</span>' +
     '<button onclick="loadFeeds()" style="font-size:.75rem;padding:.25rem .6rem;background:var(--surface2);border:1px solid var(--border);border-radius:6px;color:var(--text);cursor:pointer">↻ Refresh</button>' +
-  '</div>';
-  html += '<div class="feed-toggle-list">';
-  // Table header
-  html += '<div class="feed-toggle-header">' +
-    '<div class="feed-col-check">Enable</div>' +
-    '<div class="feed-col-check">Re-enrich</div>' +
-    '<div class="feed-col-url">Feed URL</div>' +
-    '<div class="feed-col-hint">Last seen</div>' +
     '</div>';
+  html += '<table class="feeds-table"><thead><tr>' +
+    '<th class="col-check">Enable</th>' +
+    '<th class="col-check">Re-enrich</th>' +
+    '<th class="col-url">Feed URL</th>' +
+    '<th class="col-hint">Last seen</th>' +
+    '</tr></thead><tbody>';
   for (var i = 0; i < _feedsData.length; i++) {
     var f = _feedsData[i];
     var domain = f.feed_key.replace(/^https?:\/\//, '').replace(/\/$/, '');
@@ -162,20 +160,16 @@ function renderFeedsList() {
     var lastSeen = f.updated_at ? ' · ' + new Date(f.updated_at).toLocaleString() : '';
     var isEnabled = f.enabled !== false;
     var isReEnrich = f.re_enrich === true;
-    html += '<div class="feed-toggle-row">' +
-      '<div class="feed-col-check">' +
-      '<input type="checkbox" id="feed-' + esc(String(i)) + '"' + (isEnabled ? ' checked' : '') +
-      ' onchange="toggleFeed(\'' + esc(f.feed_key) + '\', this.checked)" />' +
-      '</div>' +
-      '<div class="feed-col-check">' +
-      '<input type="checkbox" id="re-enrich-' + esc(String(i)) + '"' + (isReEnrich ? ' checked' : '') +
-      ' onchange="toggleReEnrich(\'' + esc(f.feed_key) + '\', this.checked)" title="Re-enrich on content change" />' +
-      '</div>' +
-      '<div class="feed-col-url">' + esc(domain) + '</div>' +
-      '<div class="feed-col-hint">' + lastItems + lastSeen + '</div>' +
-      '</div>';
+    html += '<tr>' +
+      '<td class="col-check"><input type="checkbox" id="feed-' + esc(String(i)) + '"' + (isEnabled ? ' checked' : '') +
+      ' onchange="toggleFeed(\'' + esc(f.feed_key) + '\', this.checked)" /></td>' +
+      '<td class="col-check"><input type="checkbox" id="re-enrich-' + esc(String(i)) + '"' + (isReEnrich ? ' checked' : '') +
+      ' onchange="toggleReEnrich(\'' + esc(f.feed_key) + '\', this.checked)" title="Re-enrich on content change" /></td>' +
+      '<td class="col-url">' + esc(domain) + '</td>' +
+      '<td class="col-hint">' + lastItems + lastSeen + '</td>' +
+      '</tr>';
   }
-  html += '</div>';
+  html += '</tbody></table>';
   el.innerHTML = html;
 }
 

+ 30 - 36
dashboard/style.css

@@ -205,65 +205,59 @@ tr:hover td { background: rgba(91,138,245,.05); }
 .feed-item .feed-count { color: var(--text-dim); font-size: .78rem; min-width: 50px; text-align: right; }
 
 /* ── Feeds management view ───────────────────────── */
-.feed-toggle-list {
-  display: flex;
-  flex-direction: column;
-  gap: .15rem;
+.feeds-table {
+  width: 100%;
+  border-collapse: collapse;
   border: 1px solid rgba(42,46,58,.4);
   border-radius: var(--radius);
   overflow: hidden;
 }
-.feed-toggle-header,
-.feed-toggle-row {
-  display: flex;
-  align-items: center;
-  padding: .5rem .6rem;
-}
-.feed-toggle-header {
+.feeds-table thead tr {
   background: var(--surface2);
+}
+.feeds-table th {
+  font-size: .65rem;
+  text-transform: uppercase;
+  letter-spacing: .06em;
+  color: var(--text-dim);
+  font-weight: 600;
+  padding: .4rem .6rem;
+  text-align: left;
   border-bottom: 1px solid rgba(42,46,58,.5);
-  padding: .35rem .6rem;
 }
-.feed-toggle-row {
+.feeds-table th.col-check {
+  text-align: center;
+}
+.feeds-table td {
+  padding: .5rem .6rem;
   border-bottom: 1px solid rgba(42,46,58,.3);
+  vertical-align: middle;
 }
-.feed-toggle-row:last-child { border: none; }
-
-.feed-col-check {
-  width: 36px;
-  flex-shrink: 0;
-  display: flex;
-  align-items: center;
-  justify-content: center;
+.feeds-table tbody tr:last-child td {
+  border-bottom: none;
+}
+.feeds-table .col-check {
+  width: 38px;
+  text-align: center;
 }
-.feed-col-check input[type=checkbox] {
+.feeds-table .col-check input[type=checkbox] {
   accent-color: var(--accent);
   width: 15px;
   height: 15px;
   cursor: pointer;
+  margin: 0;
 }
-.feed-col-url {
-  flex: 1;
-  min-width: 0;
+.feeds-table .col-url {
   font-size: .82rem;
   font-weight: 500;
   word-break: break-all;
-  padding: 0 .6rem;
 }
-.feed-col-hint {
+.feeds-table .col-hint {
   font-size: .72rem;
   color: var(--text-dim);
   white-space: nowrap;
-  flex-shrink: 0;
   text-align: right;
-}
-.feed-toggle-header .feed-col-url,
-.feed-toggle-header .feed-col-hint,
-.feed-toggle-header .feed-col-check {
-  font-size: .65rem;
-  text-transform: uppercase;
-  letter-spacing: .06em;
-  color: var(--text-dim);
+  min-width: 1%;
 }
 .toast {
   position: fixed; bottom: 1.5rem; left: 50%; transform: translateX(-50%);