feat(frontend): restyle ThothII to the Omics Portal (GSD) design system
Adopt the portal's design language so the app embeds seamlessly into its header/sidebar chrome later: - Token layer rewritten as raw OKLCH triplets (the previous oklch()-wrapped vars produced invalid colors; the UI was effectively unstyled). Values mirror GSD: Manrope + Fraunces fonts, #cb333b red brand, warm off-white surfaces, pill buttons, brand focus rings. Dark tokens follow .dark or the portal's [data-bs-theme=dark]. - Layout: no left sidebar, no header (the portal supplies them). Conversation column flush-left with a slim F1-F8 phase strip; session rail moved to the RIGHT, mirroring the portal's left sidebar (red section label, red-tint active item). Editorial empty state. - Transcript component now actually renders the streamed assistant turns (the store accumulated them but nothing displayed them). Toaster mounted for errors (matchMedia polyfill added to the jsdom test setup). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+162
-73
@@ -1,89 +1,178 @@
|
||||
@import "tw-animate-css";
|
||||
@import "shadcn/tailwind.css";
|
||||
@import "@fontsource-variable/geist";
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/*
|
||||
* GSD theme — mirrors the Omics Portal design system (Manrope + Fraunces, warm
|
||||
* off-white surfaces, #cb333b red). Tokens are RAW OKLCH triplets (L C H) so the
|
||||
* Tailwind v3 config can wrap them as `oklch(var(--token) / <alpha-value>)` and
|
||||
* opacity utilities (bg-primary/80, …) keep working. Dark tokens follow either a
|
||||
* `.dark` class or the portal's `[data-bs-theme="dark"]`, ready for embedding.
|
||||
*/
|
||||
@layer base {
|
||||
.theme {
|
||||
--font-heading: var(--font-sans);
|
||||
--font-sans: 'Geist Variable', sans-serif
|
||||
}
|
||||
:root {
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.97 0 0);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--chart-1: oklch(0.87 0 0);
|
||||
--chart-2: oklch(0.556 0 0);
|
||||
--chart-3: oklch(0.439 0 0);
|
||||
--chart-4: oklch(0.371 0 0);
|
||||
--chart-5: oklch(0.269 0 0);
|
||||
--radius: 0.625rem;
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0)
|
||||
--font-sans: "Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, Arial, sans-serif;
|
||||
--font-heading: "Fraunces", "Source Serif Pro", Georgia, "Times New Roman", serif;
|
||||
|
||||
--background: 0.9918 0.0011 17.2; /* surface */
|
||||
--foreground: 0.2678 0.0097 355.6; /* text */
|
||||
--card: 0.9985 0.0006 17.2;
|
||||
--card-foreground: 0.2678 0.0097 355.6;
|
||||
--popover: 0.9985 0.0006 17.2;
|
||||
--popover-foreground: 0.2678 0.0097 355.6;
|
||||
--primary: 0.5587 0.1881 23.2; /* gsd red */
|
||||
--primary-foreground: 0.9918 0.0011 17.2;
|
||||
--primary-hover: 0.5095 0.1812 24.1;
|
||||
--secondary: 0.9709 0.0011 17.2; /* surface-alt */
|
||||
--secondary-foreground: 0.2678 0.0097 355.6;
|
||||
--muted: 0.9709 0.0011 17.2;
|
||||
--muted-foreground: 0.5133 0.0088 345.6;
|
||||
--accent: 0.9408 0.0011 17.2; /* sunken */
|
||||
--accent-foreground: 0.2678 0.0097 355.6;
|
||||
--destructive: 0.5587 0.1881 23.2;
|
||||
--destructive-foreground: 0.9918 0.0011 17.2;
|
||||
--border: 0.9093 0.0035 354.7;
|
||||
--input: 0.9093 0.0035 354.7;
|
||||
--ring: 0.5587 0.1881 23.2;
|
||||
--success: 0.7577 0.1581 165.0;
|
||||
--warning: 0.8523 0.1386 78.9;
|
||||
--info: 0.7035 0.1128 221.3;
|
||||
--radius: 0.5rem;
|
||||
--sidebar: 0.9709 0.0011 17.2;
|
||||
--sidebar-foreground: 0.2678 0.0097 355.6;
|
||||
--sidebar-primary: 0.5587 0.1881 23.2;
|
||||
--sidebar-primary-foreground: 0.9918 0.0011 17.2;
|
||||
--sidebar-accent: 0.9408 0.0011 17.2;
|
||||
--sidebar-accent-foreground: 0.2678 0.0097 355.6;
|
||||
--sidebar-border: 0.9093 0.0035 354.7;
|
||||
--sidebar-ring: 0.5587 0.1881 23.2;
|
||||
}
|
||||
.dark {
|
||||
--background: oklch(0.145 0 0);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.205 0 0);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.205 0 0);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.922 0 0);
|
||||
--primary-foreground: oklch(0.205 0 0);
|
||||
--secondary: oklch(0.269 0 0);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.269 0 0);
|
||||
--muted-foreground: oklch(0.708 0 0);
|
||||
--accent: oklch(0.269 0 0);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.556 0 0);
|
||||
--chart-1: oklch(0.87 0 0);
|
||||
--chart-2: oklch(0.556 0 0);
|
||||
--chart-3: oklch(0.439 0 0);
|
||||
--chart-4: oklch(0.371 0 0);
|
||||
--chart-5: oklch(0.269 0 0);
|
||||
--sidebar: oklch(0.205 0 0);
|
||||
--sidebar-foreground: oklch(0.985 0 0);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.269 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.556 0 0)
|
||||
|
||||
.dark,
|
||||
[data-bs-theme="dark"] {
|
||||
--background: 0.2178 0 90;
|
||||
--foreground: 0.9310 0 90;
|
||||
--card: 0.2350 0 90;
|
||||
--card-foreground: 0.9310 0 90;
|
||||
--popover: 0.2350 0 90;
|
||||
--popover-foreground: 0.9310 0 90;
|
||||
--primary: 0.6023 0.1848 20.3;
|
||||
--primary-foreground: 0.9310 0 90;
|
||||
--primary-hover: 0.6897 0.1779 16.9;
|
||||
--secondary: 0.2972 0 90;
|
||||
--secondary-foreground: 0.9310 0 90;
|
||||
--muted: 0.2972 0 90;
|
||||
--muted-foreground: 0.7826 0 90;
|
||||
--accent: 0.3485 0 90;
|
||||
--accent-foreground: 0.9310 0 90;
|
||||
--destructive: 0.6023 0.1848 20.3;
|
||||
--destructive-foreground: 0.9310 0 90;
|
||||
--border: 0.3715 0 90;
|
||||
--input: 0.3715 0 90;
|
||||
--ring: 0.6897 0.1779 16.9;
|
||||
--sidebar: 0.2350 0 90;
|
||||
--sidebar-foreground: 0.9310 0 90;
|
||||
--sidebar-primary: 0.6023 0.1848 20.3;
|
||||
--sidebar-primary-foreground: 0.9310 0 90;
|
||||
--sidebar-accent: 0.3485 0 90;
|
||||
--sidebar-accent-foreground: 0.9310 0 90;
|
||||
--sidebar-border: 0.3715 0 90;
|
||||
--sidebar-ring: 0.6897 0.1779 16.9;
|
||||
}
|
||||
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
|
||||
html {
|
||||
@apply font-sans;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-background text-foreground antialiased;
|
||||
font-feature-settings: "ss01", "cv11";
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-family: var(--font-heading);
|
||||
font-optical-sizing: auto;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: oklch(var(--primary) / 0.16);
|
||||
}
|
||||
|
||||
/* Thin, brand-tinted scrollbars */
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: oklch(var(--border)) transparent;
|
||||
}
|
||||
*::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background: oklch(var(--border));
|
||||
border-radius: 9999px;
|
||||
border: 2px solid transparent;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
*::-webkit-scrollbar-thumb:hover {
|
||||
background: oklch(var(--muted-foreground) / 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Minimal markdown prose for assistant turns (no typography plugin installed).
|
||||
* Scoped so it never leaks into widgets.
|
||||
*/
|
||||
@layer components {
|
||||
.thot-prose {
|
||||
color: oklch(var(--foreground));
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.65;
|
||||
}
|
||||
.thot-prose > :first-child { margin-top: 0; }
|
||||
.thot-prose > :last-child { margin-bottom: 0; }
|
||||
.thot-prose p { margin: 0.6em 0; }
|
||||
.thot-prose h1, .thot-prose h2, .thot-prose h3 {
|
||||
font-family: var(--font-heading);
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
margin: 1.1em 0 0.5em;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.thot-prose h1 { font-size: 1.4rem; }
|
||||
.thot-prose h2 { font-size: 1.2rem; }
|
||||
.thot-prose h3 { font-size: 1.05rem; }
|
||||
.thot-prose ul, .thot-prose ol { margin: 0.6em 0; padding-left: 1.3em; }
|
||||
.thot-prose li { margin: 0.25em 0; }
|
||||
.thot-prose a { color: oklch(var(--primary)); text-decoration: underline; text-underline-offset: 2px; }
|
||||
.thot-prose code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
font-size: 0.85em;
|
||||
background: oklch(var(--muted));
|
||||
padding: 0.12em 0.4em;
|
||||
border-radius: 0.3rem;
|
||||
}
|
||||
.thot-prose pre {
|
||||
background: oklch(var(--muted));
|
||||
padding: 0.9rem 1rem;
|
||||
border-radius: var(--radius);
|
||||
overflow-x: auto;
|
||||
border: 1px solid oklch(var(--border));
|
||||
}
|
||||
.thot-prose pre code { background: transparent; padding: 0; }
|
||||
.thot-prose blockquote {
|
||||
border-left: 2px solid oklch(var(--border));
|
||||
padding-left: 0.9em;
|
||||
color: oklch(var(--muted-foreground));
|
||||
margin: 0.7em 0;
|
||||
}
|
||||
.thot-prose table { border-collapse: collapse; width: 100%; margin: 0.7em 0; font-size: 0.875rem; }
|
||||
.thot-prose th, .thot-prose td { border: 1px solid oklch(var(--border)); padding: 0.4em 0.6em; text-align: left; }
|
||||
.thot-prose th { background: oklch(var(--muted)); font-weight: 600; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user