Persist root UI/tailwind/responsive guard refinements from stash backlog

This commit is contained in:
zenchantlive 2026-02-11 21:25:46 -08:00
parent b4cb09a6cc
commit e599640d3b
7 changed files with 39 additions and 23 deletions

3
.gitignore vendored
View file

@ -3,3 +3,6 @@ node_modules/
*.tsbuildinfo *.tsbuildinfo
.worktrees/ .worktrees/
worktrees/ worktrees/
# bv (beads viewer) local config and caches
.bv/

View file

@ -3,15 +3,15 @@
@tailwind utilities; @tailwind utilities;
:root { :root {
--color-bg: #090c14; --color-bg: #090909;
--color-surface: #101827; --color-surface: #161616;
--color-surface-muted: #192336; --color-surface-muted: #212121;
--color-surface-raised: #22314a; --color-surface-raised: #2a2a2a;
--color-text-strong: #f6f8ff; --color-text-strong: #f5f5f5;
--color-text-body: #d8e0f1; --color-text-body: #d0d0d0;
--color-text-muted: #9caccc; --color-text-muted: #9a9a9a;
--color-border-soft: rgba(145, 166, 204, 0.3); --color-border-soft: rgba(255, 255, 255, 0.15);
--color-border-strong: rgba(187, 209, 246, 0.62); --color-border-strong: rgba(255, 255, 255, 0.3);
--status-open: #60a5fa; --status-open: #60a5fa;
--status-progress: #fbbf24; --status-progress: #fbbf24;
@ -38,10 +38,9 @@ body {
body { body {
background: background:
radial-gradient(circle at 10% 12%, rgba(12, 138, 215, 0.34), transparent 36%), radial-gradient(circle at 14% 12%, rgba(255, 255, 255, 0.05), transparent 36%),
radial-gradient(circle at 84% 20%, rgba(250, 122, 91, 0.18), transparent 30%), radial-gradient(circle at 84% 18%, rgba(255, 180, 80, 0.06), transparent 32%),
radial-gradient(circle at 68% 88%, rgba(57, 189, 154, 0.14), transparent 36%), linear-gradient(160deg, #070707 0%, #101010 48%, #161616 100%);
linear-gradient(155deg, #05070d 0%, #0b1322 42%, #121e34 100%);
color: var(--color-text-body); color: var(--color-text-body);
font-family: 'Segoe UI', 'Aptos', Inter, system-ui, sans-serif; font-family: 'DM Sans', 'Segoe UI', Inter, system-ui, sans-serif;
} }

View file

@ -1,7 +1,18 @@
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import { DM_Sans, JetBrains_Mono } from 'next/font/google';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import './globals.css'; import './globals.css';
const dmSans = DM_Sans({
subsets: ['latin'],
variable: '--font-ui',
});
const jetbrainsMono = JetBrains_Mono({
subsets: ['latin'],
variable: '--font-mono',
});
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'BeadBoard', title: 'BeadBoard',
description: 'Windows-native Beads dashboard', description: 'Windows-native Beads dashboard',
@ -10,7 +21,7 @@ export const metadata: Metadata = {
export default function RootLayout({ children }: { children: ReactNode }) { export default function RootLayout({ children }: { children: ReactNode }) {
return ( return (
<html lang="en"> <html lang="en">
<body>{children}</body> <body className={`${dmSans.variable} ${jetbrainsMono.variable}`}>{children}</body>
</html> </html>
); );
} }

View file

@ -14,7 +14,7 @@ interface KanbanControlsProps {
export function KanbanControls({ filters, stats, onFiltersChange }: KanbanControlsProps) { export function KanbanControls({ filters, stats, onFiltersChange }: KanbanControlsProps) {
const inputClass = const inputClass =
'rounded-xl border border-border-soft bg-surface-muted/78 px-3 py-2.5 text-sm text-text-strong outline-none transition placeholder:text-text-muted focus:border-cyan-300/70 focus:ring-2 focus:ring-cyan-300/20'; 'rounded-xl border border-border-soft bg-surface-muted/78 px-3 py-2.5 text-sm text-text-strong outline-none transition placeholder:text-text-muted focus:border-border-strong focus:ring-2 focus:ring-white/10';
return ( return (
<section className="grid gap-3"> <section className="grid gap-3">
@ -57,7 +57,7 @@ export function KanbanControls({ filters, stats, onFiltersChange }: KanbanContro
type="checkbox" type="checkbox"
checked={filters.showClosed ?? false} checked={filters.showClosed ?? false}
onChange={(event) => onFiltersChange({ ...filters, showClosed: event.target.checked })} onChange={(event) => onFiltersChange({ ...filters, showClosed: event.target.checked })}
className="h-4 w-4 accent-cyan-400" className="h-4 w-4 accent-amber-400"
/> />
Show closed Show closed
</label> </label>

View file

@ -7,7 +7,7 @@ interface ChipProps {
const CHIP_TONE_CLASS: Record<NonNullable<ChipProps['tone']>, string> = { const CHIP_TONE_CLASS: Record<NonNullable<ChipProps['tone']>, string> = {
default: 'border-border-soft bg-surface-muted/75 text-text-body', default: 'border-border-soft bg-surface-muted/75 text-text-body',
status: 'border-cyan-300/30 bg-cyan-500/20 text-cyan-50', status: 'border-zinc-300/30 bg-zinc-500/20 text-zinc-100',
priority: 'border-amber-300/30 bg-amber-500/20 text-amber-50', priority: 'border-amber-300/30 bg-amber-500/20 text-amber-50',
}; };

View file

@ -5,8 +5,8 @@ const config: Config = {
theme: { theme: {
extend: { extend: {
fontFamily: { fontFamily: {
ui: ['Segoe UI', 'Inter', 'system-ui', 'sans-serif'], ui: ['var(--font-ui)', 'Segoe UI', 'Inter', 'system-ui', 'sans-serif'],
mono: ['JetBrains Mono', 'Consolas', 'monospace'], mono: ['var(--font-mono)', 'Consolas', 'monospace'],
}, },
colors: { colors: {
bg: 'var(--color-bg)', bg: 'var(--color-bg)',

View file

@ -9,11 +9,12 @@ async function read(relativePath) {
return fs.readFile(path.join(ROOT, relativePath), 'utf8'); return fs.readFile(path.join(ROOT, relativePath), 'utf8');
} }
test('kanban board uses intentional horizontal scroll affordances', async () => { test('kanban board uses expandable vertical swimlanes', async () => {
const board = await read('src/components/kanban/kanban-board.tsx'); const board = await read('src/components/kanban/kanban-board.tsx');
assert.match(board, /snap-x/); assert.match(board, /aria-expanded/);
assert.match(board, /overflow-x-auto/); assert.match(board, /onActivateStatus/);
assert.match(board, /max-h-\[50vh\]/);
}); });
test('kanban page defines mobile detail drawer behavior', async () => { test('kanban page defines mobile detail drawer behavior', async () => {
@ -21,6 +22,8 @@ test('kanban page defines mobile detail drawer behavior', async () => {
assert.match(page, /fixed inset-0/); assert.match(page, /fixed inset-0/);
assert.match(page, /lg:hidden/); assert.match(page, /lg:hidden/);
assert.match(page, /lg:grid-cols-\[minmax\(0,1fr\)_minmax\(22rem,26rem\)\]/);
assert.match(page, /lg:border-l/);
}); });
test('kanban controls use fluid full-width sizing on small viewports', async () => { test('kanban controls use fluid full-width sizing on small viewports', async () => {