From ff7d8d08dc23919752521a0e3dd44f6b585d9b2f Mon Sep 17 00:00:00 2001 From: Palash Debnath Date: Wed, 1 Jul 2026 03:23:40 +0530 Subject: [PATCH] feat(ui): migrate Settings models/reco/engines styling to shadcn, trim Settings.css (fast mode) (#830) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate the last reducible CSS chunk in Settings.css — the recommendation banner, the models/engines toolbar chrome, and the role-tab/search controls — to Tailwind utilities (chrome tokens kept) at the JSX, following the established shadcn fast-mode convention. Behavior and palette unchanged. What moved to Tailwind: - RecoBanner (.reco-banner* → utilities on models/RecoBanner.jsx) - Models/Engines toolbar (.models-toolbar* → ModelStoreTab.jsx + EnginesTab.jsx), including the previously-unstyled HF-token inline chrome - Role tabs + search (.models-controls/.models-search/.models-roletabs) What was deleted as dead CSS (zero consumers, grep-verified): - the entire .engines-* block (EnginesTab already on shadcn; no consumer) - the .models-table__body > .models-row override (selector no longer matches the body > virtual > row DOM the table renders) What was KEPT as irreducible styling hooks (cannot be utilities): - .models-table* + .models-row* — the virtualized table geometry. Rows are absolutely positioned with an inline translateY from the virtualizer; the table body/virtual spacer and per-cell hooks must stay class-based. Settings.css: 386 → 225 lines (−161). Not deleted (virtualized hooks remain). Verified: vite build ✓, oxlint 0, oxfmt clean, vitest 641/641, visual 48/48, bun install --frozen-lockfile ✓. Live-eyeballed Settings → Models (store + 17-row virtualized table + reco banner) and Engines (matrix + toolbar) against the live backend; rows render correctly and chrome is coherent. Co-authored-by: mergetest Co-authored-by: Claude Opus 4.8 (1M context) --- .../src/components/settings/EnginesTab.jsx | 6 +- .../src/components/settings/ModelStoreTab.jsx | 40 ++-- .../components/settings/models/RecoBanner.jsx | 30 ++- frontend/src/pages/Settings.css | 171 +----------------- 4 files changed, 50 insertions(+), 197 deletions(-) diff --git a/frontend/src/components/settings/EnginesTab.jsx b/frontend/src/components/settings/EnginesTab.jsx index 17f1975b..d64d0b33 100644 --- a/frontend/src/components/settings/EnginesTab.jsx +++ b/frontend/src/components/settings/EnginesTab.jsx @@ -31,8 +31,8 @@ export default function EnginesTab() { return (
-
-
+
+
- · + · {reviewMode === 'on' ? t('engines.banners_on') : t('engines.banners_off')}
diff --git a/frontend/src/components/settings/ModelStoreTab.jsx b/frontend/src/components/settings/ModelStoreTab.jsx index d9ee34a9..59f25567 100644 --- a/frontend/src/components/settings/ModelStoreTab.jsx +++ b/frontend/src/components/settings/ModelStoreTab.jsx @@ -406,22 +406,26 @@ export default function ModelStoreTab({ info, modelBadge }) { return (
-
-
+
+
- {fmtBytes(data.total_installed_bytes)} + + {fmtBytes(data.total_installed_bytes)} + - · - - {data.hf_cache_dir?.replace(/^\/Users\/[^/]+/, '~')} + · + + + {data.hf_cache_dir?.replace(/^\/Users\/[^/]+/, '~')} + - {info && ·} + {info && ·} {info && {modelBadge}} {info?.fast_download?.xet_enabled && ( <> - · + · )}
-
+
{/* Compact HF token inline */} {!hfTokenSet && !hfExpanded && ( )} {!hfTokenSet && hfExpanded && ( -
+
setHfToken(e.target.value)} @@ -470,7 +474,7 @@ export default function ModelStoreTab({ info, modelBadge }) { { e.preventDefault(); openExternal('https://huggingface.co/settings/tokens'); @@ -482,7 +486,7 @@ export default function ModelStoreTab({ info, modelBadge }) {
)} {hfTokenSet && ( - + )} @@ -507,12 +511,12 @@ export default function ModelStoreTab({ info, modelBadge }) { onInstallRecommended={onInstallRecommended} /> -
+
setQuery(e.target.value)} diff --git a/frontend/src/components/settings/models/RecoBanner.jsx b/frontend/src/components/settings/models/RecoBanner.jsx index f9e76d87..22ef5f9e 100644 --- a/frontend/src/components/settings/models/RecoBanner.jsx +++ b/frontend/src/components/settings/models/RecoBanner.jsx @@ -19,22 +19,24 @@ export default function RecoBanner({ if (!reco) return null; if (reco.all_installed) { return ( -
+
{t('models.reco_installed_for', { device: reco.device.label })} - {reco.total_gb} GB + + {reco.total_gb} GB +
); } return ( -
-
- +
+
+ {t('models.reco_for', { device: reco.device.label })} -
+
{(() => { const requiredMissing = reco.models.filter((m) => m.required && !m.installed); const requiredGb = requiredMissing.reduce((s, m) => s + m.size_gb, 0); @@ -77,15 +79,23 @@ export default function RecoBanner({
-
+
{reco.models.map((m) => ( {m.installed ? '✓' : '○'} {m.label} - {m.size_gb} - {m.required && {t('models.req_tag')}} + + {m.size_gb} + + {m.required && ( + + {t('models.req_tag')} + + )} ))}
diff --git a/frontend/src/pages/Settings.css b/frontend/src/pages/Settings.css index a30e9654..f87e6bcd 100644 --- a/frontend/src/pages/Settings.css +++ b/frontend/src/pages/Settings.css @@ -64,51 +64,6 @@ `@max-[600px]/settings:` row-stacking variant depends on) is Tailwind on Settings.jsx now — see the content `
` there. */ -/* ── Engines tab ─────────────────────────────────────────────── */ -.engines-family { margin-bottom: var(--space-5); } -.engines-family__active { - margin-left: var(--space-4); - font-weight: 400; - color: var(--chrome-fg-dim); - font-size: var(--text-xs); - font-family: var(--chrome-font-mono); -} -.engines-family__active code { color: var(--chrome-fg); } - -.engines-list { - list-style: none; - padding: 0; - margin: 0; - display: flex; - flex-direction: column; - gap: var(--space-2); -} -.engines-list li { - display: flex; - align-items: center; - gap: var(--space-3); - padding: var(--space-2) var(--space-3); - background: transparent; - border: 1px solid var(--chrome-border); - border-left: 2px solid var(--chrome-border-strong); - border-radius: var(--chrome-radius-pill); - font-family: var(--font-sans); - font-size: var(--text-md); - color: var(--chrome-fg-muted); - flex-wrap: wrap; -} -.engines-list li.is-ok { - border-left-color: var(--chrome-severity-ok); - background: color-mix(in srgb, var(--chrome-severity-ok) 5%, transparent); -} -.engines-list li.is-off { - border-left-color: var(--chrome-severity-warn); - opacity: 0.85; -} -.engines-list__name { flex: 1; min-width: 240px; color: var(--chrome-fg); } -.engines-list__name code { color: var(--chrome-fg); font-family: var(--chrome-font-mono); font-size: var(--text-sm); } -.engines-list__reason { flex-basis: 100%; font-size: var(--text-xs); color: var(--chrome-fg-dim); font-family: var(--font-sans); padding-left: var(--space-4); } - /* ── Models tab ──────────────────────────────────────────────── */ .models-row__tag { margin-left: var(--space-2); @@ -123,111 +78,11 @@ background: color-mix(in srgb, #d3869b 8%, transparent); } -/* ── Models tab: toolbar + role tabs + table ─────────────────── */ -.models-toolbar { - display: flex; - align-items: center; - justify-content: space-between; - gap: var(--space-3); - padding: 2px 2px 6px; - font-family: var(--chrome-font-mono); - font-size: var(--text-xs); - color: var(--chrome-fg-muted); - flex-wrap: wrap; -} -.models-toolbar__stats { - display: inline-flex; - align-items: center; - gap: var(--space-2); - flex-wrap: wrap; -} -.models-toolbar__stats strong { color: var(--chrome-fg); font-weight: 600; } -.models-toolbar__sep { color: var(--chrome-fg-dim); } -.models-toolbar__cache code { color: var(--chrome-fg); font-family: var(--chrome-font-mono); font-size: var(--text-xs); } - -.models-roletabs { margin: 4px 0 6px; } - -/* ── Compact recommendation banner ───────────────────────────────── */ -.reco-banner { - display: flex; - align-items: center; - gap: var(--space-3); - margin-bottom: var(--space-2); - padding: var(--space-2) var(--space-4); - border-radius: var(--chrome-radius-pill); - font-size: var(--text-xs); - color: var(--chrome-fg-muted); - border: 1px solid; - border-left-width: 2px; -} -.reco-banner--ok { - border-color: color-mix(in srgb, #8ec07c 30%, transparent); - border-left-color: #8ec07c; - background: color-mix(in srgb, #8ec07c 4%, transparent); -} -.reco-banner--pending { - flex-direction: column; - align-items: stretch; - gap: var(--space-2); - padding: var(--space-3) var(--space-4) var(--space-4); - border-color: color-mix(in srgb, #f3a5b6 25%, transparent); - border-left-color: #f3a5b6; - background: linear-gradient(135deg, color-mix(in srgb, #f3a5b6 4%, transparent), color-mix(in srgb, #d3869b 2%, transparent)); - box-shadow: 0 0 12px color-mix(in srgb, #f3a5b6 6%, transparent); -} -.reco-banner__gb { - font-size: var(--text-2xs); - color: var(--chrome-fg-dim); -} -.reco-banner__top { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; -} -.reco-banner__title { - font-weight: 600; - font-size: var(--text-md); - color: var(--chrome-fg); -} -.reco-banner__btns { - display: flex; - gap: 4px; - flex-shrink: 0; -} -.reco-banner__grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 0 var(--space-5); - font-size: var(--text-sm); - line-height: 1.6; -} -.reco-banner__model { - display: inline-flex; - align-items: center; - gap: 4px; - color: var(--chrome-fg-muted); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.reco-banner__model--ok { color: var(--chrome-fg); } -.reco-banner__model-size { - font-family: var(--chrome-font-mono); - font-size: var(--text-2xs); - color: var(--chrome-fg-dim); -} -.reco-banner__req { - font-size: var(--text-2xs); - text-transform: uppercase; - letter-spacing: 0.04em; - color: #d3869b; - padding: 0 3px; - border: 1px solid color-mix(in srgb, #d3869b 30%, transparent); - border-radius: 999px; - line-height: 1.5; -} - +/* ── Models tab: table (virtualised) ───────────────────────────── + The toolbar / role tabs / search chrome and the recommendation + banner are Tailwind on their components now (ModelStoreTab.jsx, + EnginesTab.jsx, models/RecoBanner.jsx). What remains here is the + virtualised-table geometry the utilities can't carry. */ /* Table — dense rows, fixed-width action column. */ .models-table { border-radius: var(--chrome-radius-pill); } .models-table .ui-table-header { padding: 5px var(--space-3); } @@ -349,13 +204,6 @@ color: var(--chrome-severity-err); font-size: var(--text-xs); margin-top: 4px; } -.models-controls { - display: flex; align-items: center; gap: var(--space-2); - margin: var(--space-2) 0; -} -/* Visuals come from SettingsInput; .models-search only adds the in-toolbar flex - sizing + lifts the primitive's 360px cap so the search fills the toolbar. */ -.models-search { flex: 1; min-width: 120px; max-width: none; font-size: var(--text-xs); } .models-row__size { font-family: var(--chrome-font-mono); font-size: var(--text-xs); color: var(--chrome-fg-muted); font-variant-numeric: tabular-nums; } .models-row__actions { @@ -373,14 +221,5 @@ .models-row__name { flex: 1 1 100%; } .models-row__size { width: auto !important; text-align: left !important; } .models-row__actions { margin-left: auto; } - .models-toolbar { flex-direction: column; align-items: flex-start; } - .models-controls { flex-direction: column; align-items: stretch; } -} - -/* ── Engines tab: rows are NOT virtualised, so override the absolute - positioning that .models-row inherits from the Models tab. ───── */ -[data-slot='settings-section'] > .models-table > .models-table__body > .models-row { - position: relative; - top: auto; }