From cf166ba9450ff233aa586acd85fa81983765b4a1 Mon Sep 17 00:00:00 2001 From: you Date: Thu, 19 Mar 2026 03:00:22 +0000 Subject: [PATCH] =?UTF-8?q?Improve=20Route=20Patterns=20layout=20=E2=80=94?= =?UTF-8?q?=20less=20squished?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Detail sidebar starts collapsed, expands on click (420px, max 50vw) - Route column allows word wrap instead of forced nowrap - Tables use auto layout for breathing room - List panel has min-width:0 to prevent flex overflow - Smoother transitions on sidebar open --- public/analytics.js | 5 +++-- public/style.css | 14 ++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/public/analytics.js b/public/analytics.js index cdec50b7..c420dc6e 100644 --- a/public/analytics.js +++ b/public/analytics.js @@ -790,7 +790,7 @@ const prefixDisplay = rawHops.join(' โ†’ '); return ` ${i + 1} - ${routeDisplay}${hasSelfLoop ? ' ๐Ÿ”„' : ''}
${esc(prefixDisplay)} + ${routeDisplay}${hasSelfLoop ? ' ๐Ÿ”„' : ''}
${esc(prefixDisplay)} ${s.count.toLocaleString()} ${s.pct}%
@@ -819,7 +819,7 @@
${renderTable(d4, 'Quads (4-hop chains)')}
${renderTable(d5, 'Long chains (5+ hops)')}
-
+
`; @@ -858,6 +858,7 @@ async function loadSubpathDetail(hopsStr) { const panel = document.getElementById('subpathDetail'); + panel.classList.remove('collapsed'); panel.innerHTML = '
Loadingโ€ฆ
'; try { const data = await api('/analytics/subpath-detail?hops=' + encodeURIComponent(hopsStr)); diff --git a/public/style.css b/public/style.css index a5575519..7fa5565b 100644 --- a/public/style.css +++ b/public/style.css @@ -1155,10 +1155,11 @@ button.ch-item.ch-item-encrypted .ch-badge { filter: grayscale(0.6); } .hop-prefix { color: #9ca3af; font-size: 0.8em; } /* Subpath split layout */ -.subpath-layout { display: flex; gap: 0; height: calc(100vh - 160px); } -.subpath-list { flex: 1; overflow-y: auto; padding: 16px; } -.subpath-detail { width: 380px; min-width: 320px; border-left: 1px solid var(--border, #e5e7eb); overflow-y: auto; padding: 16px; } -.subpath-detail-inner h4 { margin: 0 0 4px; } +.subpath-layout { display: flex; gap: 0; height: calc(100vh - 160px); position: relative; } +.subpath-list { flex: 1; overflow-y: auto; padding: 16px; min-width: 0; } +.subpath-detail { width: 420px; min-width: 360px; max-width: 50vw; border-left: 1px solid var(--border, #e5e7eb); overflow-y: auto; padding: 16px; transition: width 0.2s; } +.subpath-detail.collapsed { width: 0; min-width: 0; padding: 0; overflow: hidden; border: none; } +.subpath-detail-inner h4 { margin: 0 0 4px; word-break: break-word; } .subpath-meta { display: flex; flex-direction: column; gap: 2px; margin-bottom: 12px; color: #9ca3af; font-size: 0.9em; } .subpath-section { margin: 16px 0; } .subpath-section h5 { margin: 0 0 6px; font-size: 0.9em; } @@ -1184,3 +1185,8 @@ tr[data-hops]:hover { background: rgba(59,130,246,0.1); } .subpath-jump-nav span { color: #9ca3af; } .subpath-jump-nav a { padding: 4px 12px; border-radius: 4px; background: var(--accent, #3b82f6); color: #fff; text-decoration: none; font-size: 0.85em; } .subpath-jump-nav a:hover { opacity: 0.8; } + +/* Route patterns table breathing room */ +.subpath-list .analytics-table td:nth-child(2) { white-space: normal; word-break: break-word; max-width: 50vw; } +.subpath-list .analytics-table { table-layout: auto; } +.subpath-list h4 { margin-top: 24px; }