Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Binary file added web/public/fonts/Geist-Bold.woff2
Binary file not shown.
Binary file added web/public/fonts/Geist-Medium.woff2
Binary file not shown.
Binary file added web/public/fonts/Geist-Regular.woff2
Binary file not shown.
Binary file added web/public/fonts/GeistMono-Medium.woff2
Binary file not shown.
Binary file added web/public/fonts/GeistMono-Regular.woff2
Binary file not shown.
7 changes: 7 additions & 0 deletions web/public/fonts/NOTICE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Vendored fonts

Geist and Geist Mono are © Vercel, Inc., licensed under SIL Open Font License 1.1.

Source: https://github.com/vercel/geist-font

Vendored locally per the air-gap constraint (no CDN font loads in production).
27 changes: 27 additions & 0 deletions web/src/tokens/colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// web/src/tokens/colors.ts
export const colors = {
bgPage: '#FBFAF6',
bgElev: '#FFFFFF',
bgSubtle: '#F4F2EC',
bgDeep: '#ECE7DB',
bgTint: '#FAF6EA',
ink1: '#15110A',
ink2: '#4A4540',
ink3: '#918A80',
ink4: '#C8C2B6',
hair: '#E6E1D4',
hairStrong: '#D4CDB8',
acc: '#2A4365',
accDim: '#1F3147',
accSoft: 'rgba(42, 67, 101, 0.08)',
accMid: 'rgba(42, 67, 101, 0.18)',
warn: '#B4814A',
warnBg: 'rgba(180, 129, 74, 0.08)',
danger: '#B85A4F',
dangerBg: 'rgba(184, 90, 79, 0.08)',
good: '#5C8862',
goodBg: 'rgba(92, 136, 98, 0.08)',
info: '#4F6F8E',
} as const;

export type ColorToken = keyof typeof colors;
8 changes: 8 additions & 0 deletions web/src/tokens/elevation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// web/src/tokens/elevation.ts
export const elevation = {
e1: '0 1px 2px rgba(21,17,10,0.04), 0 0 0 1px #E6E1D4',
e2: '0 2px 4px rgba(21,17,10,0.05), 0 8px 16px rgba(21,17,10,0.04), 0 0 0 1px #E6E1D4',
e3: '0 4px 12px rgba(21,17,10,0.07), 0 16px 32px rgba(21,17,10,0.06), 0 0 0 1px #D4CDB8',
} as const;

export type ElevationToken = keyof typeof elevation;
5 changes: 5 additions & 0 deletions web/src/tokens/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// web/src/tokens/index.ts
export { colors, type ColorToken } from './colors';
export { typography, type TypographyToken } from './typography';
export { spacing, type SpacingToken } from './spacing';
export { elevation, type ElevationToken } from './elevation';
11 changes: 11 additions & 0 deletions web/src/tokens/spacing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// web/src/tokens/spacing.ts
export const spacing = {
s1: 4,
s2: 8,
s3: 12,
s4: 16,
s5: 24,
s6: 32,
} as const;

export type SpacingToken = keyof typeof spacing;
15 changes: 15 additions & 0 deletions web/src/tokens/typography.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// web/src/tokens/typography.ts
export const typography = {
ffSans: '"Geist", "Inter", system-ui, sans-serif',
ffMono: '"Geist Mono", "JetBrains Mono", ui-monospace, monospace',
micro: 10,
meta: 11,
body: 13,
lead: 14,
h3: 15,
h2: 18,
h1: 24,
display: 30,
} as const;

export type TypographyToken = keyof typeof typography;
16 changes: 16 additions & 0 deletions web/tests/_helpers/render.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// web/tests/_helpers/render.tsx
import type { ReactElement } from 'react';
import { render as rtlRender, type RenderOptions } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

export function render(ui: ReactElement, options?: RenderOptions) {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false, gcTime: 0 } },
});
return rtlRender(
<QueryClientProvider client={queryClient}>{ui}</QueryClientProvider>,
options,
);
}

export * from '@testing-library/react';
2 changes: 2 additions & 0 deletions web/tests/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// web/tests/setup.ts
import '@testing-library/jest-dom/vitest';
8 changes: 8 additions & 0 deletions web/tests/unit/smoke.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// web/tests/unit/smoke.test.ts
import { describe, it, expect } from 'vitest';

describe('vitest smoke', () => {
it('arithmetic still works', () => {
expect(1 + 1).toBe(2);
});
});
25 changes: 25 additions & 0 deletions web/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// web/vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import { fileURLToPath } from 'node:url';

export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
test: {
environment: 'jsdom',
setupFiles: ['./tests/setup.ts'],
globals: true,
css: false,
coverage: {
provider: 'v8',
reporter: ['text', 'lcov'],
include: ['src/**/*.{ts,tsx}'],
exclude: ['src/main.tsx', 'src/**/*.d.ts'],
},
},
});
Loading