From 1e115b8b0ce605172248ce9fe66eb7a19c05e10a Mon Sep 17 00:00:00 2001 From: Seungpyo1007 Date: Wed, 24 Jun 2026 11:15:39 +0900 Subject: [PATCH] fix(site): redesign the History growth chart and snapshot panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The growth timeline rendered 27 fixed-width bars in a half-width panel, so it overflowed into a horizontal scroll and got clipped. Replace it with an SVG area chart that scales the whole timeline to the panel width — every sync visible at once, nothing cut off — with start/current captions. Also rebalance the section: top-align the panels (the snapshot no longer stretches into empty space) and give the snapshot's category counts more room so it doesn't read as cramped. Refs #1 --- site/src/scripts/techapi.js | 28 ++++++++---- site/src/styles/techapi.css | 91 +++++++++++++------------------------ 2 files changed, 49 insertions(+), 70 deletions(-) diff --git a/site/src/scripts/techapi.js b/site/src/scripts/techapi.js index 694b711c81b..f080ad5cdb1 100644 --- a/site/src/scripts/techapi.js +++ b/site/src/scripts/techapi.js @@ -282,16 +282,24 @@ function countUp(node, target, opts = {}) { const maxTotal = Math.max(...points.map((point) => point.total)); const minTotal = Math.min(...points.map((point) => point.total)); const range = Math.max(1, maxTotal - minTotal); - chartEl.innerHTML = points.map((point) => { - const pct = 18 + ((point.total - minTotal) / range) * 82; - const deltaText = formatDelta(point.delta, point.baseline); - const deltaClass = point.delta < 0 ? " is-negative" : ""; - return ` - - ${point.total.toLocaleString()} - ${esc(deltaText)} - `; - }).join(""); + // Growth curve: every sync as a point on an area chart scaled to the panel + // width, so the whole timeline fits with nothing clipped or scrolled. + const VW = 1000, VH = 150, PAD = 6; + const xs = (i) => PAD + (points.length < 2 ? 0 : (i / (points.length - 1)) * (VW - 2 * PAD)); + const ys = (t) => VH - PAD - ((t - minTotal) / range) * (VH - 2 * PAD); + const line = points.map((p, i) => `${i ? "L" : "M"}${xs(i).toFixed(1)} ${ys(p.total).toFixed(1)}`).join(" "); + const area = `${line} L${xs(points.length - 1).toFixed(1)} ${VH} L${xs(0).toFixed(1)} ${VH} Z`; + const last = points[points.length - 1]; + chartEl.innerHTML = ` + + + + + + + + ${esc(points[0].when)} · ${minTotal.toLocaleString()} + ${esc(last.when)} · ${last.total.toLocaleString()}`; // Show every sync (newest first), growth-first. The list scrolls (CSS // max-height) so the full history stays reachable without a giant section. diff --git a/site/src/styles/techapi.css b/site/src/styles/techapi.css index 051979c36fd..22f68ba1436 100644 --- a/site/src/styles/techapi.css +++ b/site/src/styles/techapi.css @@ -252,14 +252,17 @@ code, .mono { font-family: var(--mono); } ============================================================ */ .history { display: grid; - grid-template-columns: .9fr 1.1fr; + grid-template-columns: 1fr 1.15fr; gap: 16px; + align-items: start; } .history-panel { border: 1px solid var(--border); border-radius: 8px; background: var(--surface); - padding: 22px; + padding: 24px; + display: flex; + flex-direction: column; } .history-label { font-family: var(--mono); @@ -279,7 +282,7 @@ code, .mono { font-family: var(--mono); } .history-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 8px; + gap: 9px; margin-top: 22px; } .history-count { @@ -287,14 +290,14 @@ code, .mono { font-family: var(--mono); } align-items: center; justify-content: space-between; gap: 12px; - padding: 10px 12px; + padding: 13px 14px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2); font-family: var(--mono); } -.history-count span { color: var(--muted); font-size: 12px; } -.history-count b { color: var(--fg); font-size: 13px; } +.history-count span { color: var(--muted); font-size: 12.5px; } +.history-count b { color: var(--fg); font-size: 15px; } .history-list { list-style: none; margin: 20px 0 0; @@ -312,71 +315,39 @@ code, .mono { font-family: var(--mono); } .history-list::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; } .history-list::-webkit-scrollbar-track { background: transparent; } .history-chart { - min-height: 210px; + position: relative; + height: 168px; margin-top: 18px; - padding: 16px 12px 12px; - display: grid; - grid-auto-flow: column; - grid-auto-columns: minmax(62px, 1fr); - align-items: end; - gap: 10px; - overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); + overflow: hidden; background: - linear-gradient(to top, var(--border) 1px, transparent 1px) 0 25% / 100% 25%, + linear-gradient(to top, var(--grid-line) 1px, transparent 1px) 0 0 / 100% 25%, var(--surface-2); } -.history-empty { - align-self: center; - justify-self: center; - grid-column: 1 / -1; +.history-svg { display: block; width: 100%; height: 100%; } +.history-cap { + position: absolute; + bottom: 8px; font-family: var(--mono); + font-size: 10.5px; color: var(--muted); - font-size: 12px; + background: color-mix(in srgb, var(--surface-2) 72%, transparent); + padding: 1px 6px; + border-radius: 3px; } -.history-bar { - min-width: 0; - height: 178px; +.history-cap-lo { left: 9px; } +.history-cap-hi { right: 9px; color: var(--accent-text); } +.history-empty { + position: absolute; + inset: 0; display: grid; - grid-template-rows: 1fr auto auto; - gap: 6px; - color: var(--fg); -} -.history-bar-fill { - align-self: end; - min-height: 10px; - height: var(--h); - border: 1px solid color-mix(in srgb, var(--accent) 60%, var(--border)); - border-radius: 4px 4px 2px 2px; - background: - linear-gradient(180deg, color-mix(in srgb, var(--accent) 92%, white 8%), var(--accent-deep)); - box-shadow: 0 0 26px -12px var(--accent); - transition: filter .16s, transform .16s; -} -.history-bar:hover .history-bar-fill { - filter: brightness(1.08); - transform: translateY(-2px); -} -.history-bar-total, -.history-bar-delta { - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-family: var(--mono); + place-items: center; text-align: center; -} -.history-bar-total { - font-size: 11px; - font-weight: 700; -} -.history-bar-delta { - font-size: 10px; - color: var(--accent-text); -} -.history-bar-delta.is-negative { - color: var(--err); + padding: 0 16px; + font-family: var(--mono); + color: var(--muted); + font-size: 12px; } .history-list li { display: grid;