refactor(ui): all-sans editorial headings + tint-only active nav

Per design review, pivot the heading strategy from hybrid-serif to a
refined grotesk: drop the Fraunces dependency, token, and import; page
titles, the Home greeting, and section/empty-state titles now use Geist
at semibold with the editorial fluid sizing and tight tracking. No serif
anywhere.

Active sidebar item is now a tint-only treatment (accent text + tinted
background); the left accent rail is removed and the shared base
.nav-item.active inset bar is suppressed in the sidebar (as the console
rail already does). Update the design-system e2e specs to assert the
sans display font and the tinted-background active state.

Assisted-by: Claude:claude-opus-4-8 [Claude Code]
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
Ettore Di Giacinto
2026-06-18 12:53:34 +00:00
parent f9a130e446
commit e8cac3506b
7 changed files with 20 additions and 31 deletions

View File

@@ -1,21 +1,25 @@
import { test, expect } from './coverage-fixtures.js'
test.describe('Editorial design system', () => {
test('page titles render in the Fraunces serif', async ({ page }) => {
test('page titles render in the sans display font (no serif)', async ({ page }) => {
await page.goto('/app/settings')
const title = page.locator('.page-title').first()
await expect(title).toBeVisible({ timeout: 15_000 })
const family = await title.evaluate(el => getComputedStyle(el).fontFamily)
expect(family.toLowerCase()).toContain('fraunces')
// Editorial-grotesk direction: headings use the Geist sans family, no serif.
expect(family.toLowerCase()).toContain('geist')
expect(family.toLowerCase()).not.toContain('fraunces')
})
test('active nav item shows a left accent rail (box-shadow), not just a tint', async ({ page }) => {
test('active nav item is highlighted with a tinted background (no rail)', async ({ page }) => {
await page.goto('/app/settings')
await expect(page.locator('.page-title').first()).toBeVisible({ timeout: 15_000 })
const active = page.locator('.sidebar-nav .nav-item.active').first()
await expect(active).toBeVisible()
const shadow = await active.evaluate(el => getComputedStyle(el).boxShadow)
expect(shadow).not.toBe('none')
const bg = await active.evaluate(el => getComputedStyle(el).backgroundColor)
// Tint-only active treatment: a non-transparent tinted background.
expect(bg).not.toBe('rgba(0, 0, 0, 0)')
expect(bg).not.toBe('transparent')
})
test('page reveal animation is defined on .page-transition', async ({ page }) => {

View File

@@ -16,7 +16,6 @@
"@codemirror/search": "^6.5.10",
"@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.36.8",
"@fontsource-variable/fraunces": "^5.2.9",
"@fontsource-variable/geist": "^5.2.8",
"@fontsource-variable/geist-mono": "^5.2.7",
"@fortawesome/fontawesome-free": "^6.7.2",
@@ -1065,15 +1064,6 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@fontsource-variable/fraunces": {
"version": "5.2.9",
"resolved": "https://registry.npmjs.org/@fontsource-variable/fraunces/-/fraunces-5.2.9.tgz",
"integrity": "sha512-Y6IjunlN9Ni723np+GIgAaKzCDBrPRrqNi01TZxHs5wtHYROWFM9W6yiT+/gGwSjWIRD18oX17kD/BRWekc/Lw==",
"license": "OFL-1.1",
"funding": {
"url": "https://github.com/sponsors/ayuhito"
}
},
"node_modules/@fontsource-variable/geist": {
"version": "5.2.8",
"resolved": "https://registry.npmjs.org/@fontsource-variable/geist/-/geist-5.2.8.tgz",

View File

@@ -24,7 +24,6 @@
"@codemirror/search": "^6.5.10",
"@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.36.8",
"@fontsource-variable/fraunces": "^5.2.9",
"@fontsource-variable/geist": "^5.2.8",
"@fontsource-variable/geist-mono": "^5.2.7",
"@fortawesome/fontawesome-free": "^6.7.2",

View File

@@ -352,10 +352,10 @@
border-radius: var(--radius-lg);
}
.sidebar-nav .nav-item.active {
background: var(--color-surface-hover);
color: var(--color-text-primary);
background: var(--color-primary-light);
color: var(--color-primary);
font-weight: var(--font-weight-medium);
box-shadow: inset 3px 0 0 var(--color-nav-rail);
box-shadow: none;
}
.sidebar-nav .nav-item.active .nav-icon { color: var(--color-primary); }
/* Align tier labels with the inset item text (item margin + icon padding). */
@@ -1139,9 +1139,9 @@
}
.page-title {
font-family: var(--font-serif);
font-family: var(--font-sans);
font-size: clamp(1.5rem, 1.15rem + 1.4vw, var(--text-3xl));
font-weight: 480;
font-weight: var(--font-weight-semibold);
letter-spacing: -0.018em;
line-height: var(--leading-tight);
margin-bottom: var(--spacing-xs);
@@ -2808,9 +2808,9 @@ select.input {
}
.empty-state-title {
font-family: var(--font-serif);
font-family: var(--font-sans);
font-size: clamp(1.5rem, 3vw, var(--text-3xl));
font-weight: 480;
font-weight: var(--font-weight-semibold);
letter-spacing: -0.02em;
color: var(--color-text-primary);
margin: 0;
@@ -5639,9 +5639,9 @@ select.input {
color: var(--color-eyebrow);
}
.home-greeting {
font-family: var(--font-serif);
font-family: var(--font-sans);
font-size: clamp(2rem, 1.4rem + 3vw, var(--text-4xl));
font-weight: 440;
font-weight: var(--font-weight-semibold);
letter-spacing: -0.02em;
line-height: 1.05;
margin: var(--spacing-xs) 0 0;

View File

@@ -53,8 +53,8 @@ h1, h2, h3, h4, h5, h6 {
color: var(--color-text-primary);
line-height: var(--leading-tight);
}
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 1.2rem + 2.4vw, var(--text-4xl)); font-weight: 480; letter-spacing: -0.02em; }
h2 { font-family: var(--font-serif); font-size: clamp(1.4rem, 1.05rem + 1.6vw, var(--text-3xl)); font-weight: 480; letter-spacing: -0.015em; }
h1 { font-family: var(--font-sans); font-size: clamp(1.75rem, 1.2rem + 2.4vw, var(--text-4xl)); font-weight: 600; letter-spacing: -0.02em; }
h2 { font-family: var(--font-sans); font-size: clamp(1.4rem, 1.05rem + 1.6vw, var(--text-3xl)); font-weight: 600; letter-spacing: -0.015em; }
h3 { font-size: var(--text-xl); font-weight: var(--font-weight-medium); letter-spacing: -0.01em; }
h4 { font-size: var(--text-lg); font-weight: var(--font-weight-medium); letter-spacing: -0.005em; }
h5 { font-size: var(--text-base);font-weight: var(--font-weight-semibold); }

View File

@@ -10,7 +10,6 @@ import './i18n'
import '@fortawesome/fontawesome-free/css/all.min.css'
import '@fontsource-variable/geist'
import '@fontsource-variable/geist-mono'
import '@fontsource-variable/fraunces'
import './index.css'
import './theme.css'
import './App.css'

View File

@@ -65,7 +65,6 @@
--color-modal-backdrop: rgba(8, 11, 17, 0.68);
--color-focus-ring: rgba(136, 192, 208, 0.7); /* was 0.34 - AA-visible */
--color-nav-rail: var(--color-primary);
--color-eyebrow: #d8b48c; /* muted Nord-aurora brass for editorial eyebrows */
/* Data viz — full aurora + frost palette */
@@ -124,7 +123,6 @@
/* Typography — Geist Variable + Geist Mono Variable */
--font-sans: "Geist", "Geist Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", ui-sans-serif, system-ui, sans-serif;
--font-mono: "Geist Mono", "Geist Mono Variable", ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
--font-serif: "Fraunces Variable", "Fraunces", Georgia, "Times New Roman", serif;
--text-xs: 0.6875rem;
--text-sm: 0.8125rem;
@@ -225,7 +223,6 @@
--color-modal-backdrop: rgba(46, 52, 64, 0.38);
--color-focus-ring: rgba(94, 129, 172, 0.6); /* was 0.34 */
--color-nav-rail: var(--color-primary);
--color-eyebrow: #9a6b3f; /* darker brass for contrast on snow storm */
/* Data viz — muted aurora for light mode */