feat(frontend): wire Vite app to FastAPI parser with NDJSON streaming + Upload page

This commit is contained in:
Tyler
2026-06-19 17:31:59 -06:00
parent 999889ecb3
commit 3d3bdfb07c
44 changed files with 7811 additions and 0 deletions
+187
View File
@@ -0,0 +1,187 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
/* Refined Apple-HIG dark — true black with a whisper of blue */
--background: 240 6% 4%; /* #0a0a0c */
--foreground: 240 6% 96%; /* #f5f5f7 */
--card: 240 5% 8%; /* #131316 */
--card-foreground: 240 6% 96%;
--popover: 240 5% 9%;
--popover-foreground: 240 6% 96%;
--muted: 240 4% 12%; /* #1e1e21 */
--muted-foreground: 240 4% 61%; /* #9a9a9f */
--secondary: 240 4% 12%;
--secondary-foreground: 240 6% 96%;
--accent: 217 100% 56%; /* #1a73ff — electric, more committed than stock */
--accent-foreground: 0 0% 100%;
--primary: 217 100% 56%;
--primary-foreground: 0 0% 100%;
--destructive: 1 100% 60%; /* #ff453a */
--destructive-foreground: 0 0% 100%;
--success: 142 71% 50%; /* #30d158 */
--success-foreground: 144 70% 10%;
--warning: 38 100% 56%; /* #ff9f0a */
--warning-foreground: 26 80% 14%;
--border: 240 4% 14%; /* #232327 */
--input: 240 4% 14%;
--ring: 217 100% 56%;
--sidebar: 240 6% 5%;
--sidebar-foreground: 240 6% 96%;
--sidebar-accent: 217 100% 56%;
--sidebar-border: 240 4% 12%;
--radius: 0.75rem; /* 12px */
}
* {
@apply border-border;
}
html, body, #root {
height: 100%;
}
body {
@apply bg-background text-foreground;
font-feature-settings: "ss01", "cv11", "calt";
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
/* A single, precise light source anchored top-right.
One light, not two — an instrument, not a wash. */
body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
z-index: 0;
background: radial-gradient(
55rem 35rem at 100% -15%,
hsla(218, 100%, 58%, 0.085),
transparent 62%
);
}
/* Fine grain — the substrate of a precision instrument. */
body::after {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
z-index: 0;
opacity: 0.045;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}
/* Custom scrollbar — minimal, hairline, Apple-style */
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: hsl(var(--border));
border-radius: 999px;
border: 2px solid transparent;
background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover {
background: hsl(var(--muted-foreground) / 0.4);
background-clip: content-box;
}
/* Focus ring — accent, 2px, with offset */
:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 2px;
border-radius: 6px;
}
}
@layer components {
/* Tabular numerals everywhere a number is shown */
.num {
font-variant-numeric: tabular-nums;
font-feature-settings: "tnum", "ss01";
}
/* Display face — used for KPI numbers and data emphasis */
.display {
font-family: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;
font-variant-numeric: tabular-nums;
letter-spacing: -0.04em;
}
/* Hairline — a 1px separator that reads as a divider, not a border */
.hairline {
border-color: hsl(var(--border) / 0.6);
}
/* Soft card surface with a 1px hairline + subtle inner highlight */
.surface {
background-color: hsl(var(--card));
border: 1px solid hsl(var(--border));
box-shadow:
inset 0 1px 0 0 hsl(0 0% 100% / 0.035),
0 1px 2px 0 hsl(0 0% 0% / 0.5);
}
/* Active nav indicator — a thin left-aligned accent line */
.nav-active {
background-color: hsl(var(--muted) / 0.6);
color: hsl(var(--foreground));
}
.nav-active::before {
content: "";
position: absolute;
left: -0.75rem;
top: 0.5rem;
bottom: 0.5rem;
width: 2px;
border-radius: 2px;
background-color: hsl(var(--accent));
box-shadow: 0 0 12px hsl(var(--accent) / 0.5);
}
/* Keyboard hint chip */
.kbd {
display: inline-flex;
align-items: center;
gap: 0.15rem;
height: 1.375rem;
padding: 0 0.4rem;
border-radius: 0.375rem;
border: 1px solid hsl(var(--border));
background: hsl(var(--muted) / 0.5);
color: hsl(var(--muted-foreground));
font-family: "Geist Mono", ui-monospace, monospace;
font-size: 10.5px;
font-weight: 500;
letter-spacing: 0.04em;
line-height: 1;
}
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
}