Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9110002
feat(ui): add Fraunces variable serif + --font-serif token
mudler Jun 18, 2026
b5d8992
feat(ui): serif display tier + section-heading typography scale
mudler Jun 18, 2026
53af180
feat(ui): un-overload accent — nav rail, stronger focus ring, neutral…
mudler Jun 18, 2026
7d501f1
feat(ui): orchestrated page reveal + stagger motion primitives
mudler Jun 18, 2026
6ef88c7
refactor(ui): fix dead token refs + dedupe toggle to one primitive
mudler Jun 18, 2026
24623d5
refactor(ui): route boot fallback through the LoadingSpinner primitive
mudler Jun 18, 2026
f31f311
feat(ui): EmptyState primitive with serif title
mudler Jun 18, 2026
b73b938
feat(ui): Skeleton shimmer primitive
mudler Jun 18, 2026
abd8162
feat(ui): PageHeader + SectionHeading editorial primitives
mudler Jun 18, 2026
0838d7d
feat(ui): StatusPill primitive + time-of-day greeting helper
mudler Jun 18, 2026
c7d9dbd
feat(ui): Home editorial header + status line (north-star redesign)
mudler Jun 18, 2026
76f3e03
feat(ui): Home loaded-models skeleton list, button hierarchy, EmptySt…
mudler Jun 18, 2026
f9a130e
fix(ui): single focus ring (no double-ring) + neutralize stagger dela…
mudler Jun 18, 2026
e8cac35
refactor(ui): all-sans editorial headings + tint-only active nav
mudler Jun 18, 2026
8caf93f
test(e2e): add --host flag to ui-test-server
mudler Jun 18, 2026
7cca835
refactor(ui): declutter Home - discoverable + dismissable API, vertic…
mudler Jun 18, 2026
a24cc84
feat(ui): editorial PageHeader with section eyebrow + scroll-to-top o…
mudler Jun 18, 2026
f1132f9
refactor(ui): adopt PageHeader on agent/media/import/backend pages (b…
mudler Jun 18, 2026
30245d7
refactor(ui): adopt PageHeader on ops/admin/media pages (batch B)
mudler Jun 18, 2026
67e2f2c
test(ui): home greeting asserts sans font, not the dropped serif
mudler Jun 18, 2026
a753f82
feat(ui): ThemeToggle i18n + animated icon, drop transition:all
mudler Jun 18, 2026
a5a4701
feat(ui): canvas drag-to-resize + slide-in, fix hooks order, typed do…
mudler Jun 18, 2026
eb8b9b1
feat(ui): per-message code blocks get a language header + copy button
mudler Jun 18, 2026
5510262
feat(ui): image attachments show a thumbnail in the composer
mudler Jun 18, 2026
8991b94
feat(ui): jump-to-latest pill when scrolled up in chat
mudler Jun 18, 2026
3bafc2e
feat(ui): canvas fullscreen toggle + keyboard tab navigation
mudler Jun 18, 2026
dc209f1
feat(ui): image result lightbox (zoom, prev/next, download, keyboard)
mudler Jun 18, 2026
1949d2c
feat(ui): generation progress with placeholder tiles + elapsed timer
mudler Jun 18, 2026
c6e3625
feat(ui): generation progress on Video, TTS, and Sound pages
mudler Jun 18, 2026
397e3c1
feat(ui): agent chat gets per-message code-copy + reliable highlighting
mudler Jun 18, 2026
2047bec
feat(ui): Talk voice visualizer
mudler Jun 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions core/http/react-ui/e2e/design-system.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { test, expect } from './coverage-fixtures.js'

test.describe('Editorial design system', () => {
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)
// 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 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 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 }) => {
await page.goto('/app/settings')
const pt = page.locator('.page-transition').first()
await expect(pt).toBeVisible({ timeout: 15_000 })
const name = await pt.evaluate(el => getComputedStyle(el).animationName)
expect(name).toBe('pageReveal')
})
})

test.describe('reduced motion', () => {
test('stagger animation-delay is neutralized under reduced motion', async ({ page }) => {
// Emulate prefers-reduced-motion explicitly. (The fixture-option form
// test.use({ reducedMotion }) does not propagate through our extended
// coverage `page` fixture, so set it on the page directly.)
await page.emulateMedia({ reducedMotion: 'reduce' })
await page.goto('/app') // Home renders .reveal-stagger children
// .home-status-line is staggerStyle(1) -> 60ms delay without the fix.
const child = page.locator('.home-status-line').first()
await expect(child).toBeVisible({ timeout: 15_000 })
const delay = await child.evaluate(el => getComputedStyle(el).animationDelay)
// Under reduced motion the per-child delay must be ~0 (not 60ms+).
expect(parseFloat(delay)).toBeLessThan(0.05)
})
})
31 changes: 31 additions & 0 deletions core/http/react-ui/e2e/home-redesign.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { test, expect } from './coverage-fixtures.js'

test.describe('Home editorial redesign', () => {
test('renders the editorial greeting header in the sans display font', async ({ page }) => {
await page.goto('/app')
const greeting = page.locator('.home-greeting')
await expect(greeting).toBeVisible({ timeout: 15_000 })
const family = await greeting.evaluate(el => getComputedStyle(el).fontFamily)
// Refined-grotesk direction: the greeting uses Geist (no serif).
expect(family.toLowerCase()).toContain('geist')
expect(family.toLowerCase()).not.toContain('fraunces')
})

test('quick links expose a single primary action', async ({ page }) => {
await page.goto('/app')
await expect(page.locator('.home-greeting, .empty-state-title').first()).toBeVisible({ timeout: 15_000 })
const primaries = page.locator('.home-quick-links .btn-primary')
// At most one primary CTA in the quick-links row.
expect(await primaries.count()).toBeLessThanOrEqual(1)
})

test('loaded-models block uses an editorial section heading', async ({ page }) => {
await page.goto('/app')
await expect(page.locator('.home-greeting').first()).toBeVisible({ timeout: 15_000 })
// The refined loaded-models block introduces a SectionHeading; the legacy
// inline ".home-loaded-text" label is gone.
const heading = page.locator('.home-loaded .section-heading')
await expect(heading).toBeVisible({ timeout: 15_000 })
await expect(heading).toHaveText(/active models/i)
})
})
Loading
Loading