hermes-agent/web/src/index.css
Austin Pickett edb2d91057
feat(web): migrate dashboard checkboxes to @nous-research/ui + DS polish (#28814)
* feat(web): migrate dashboard checkboxes to @nous-research/ui + DS polish

Replaces the hand-rolled shadcn-style `Checkbox` in `web/src/components/ui/`
with the Nous DS `Checkbox` (Radix-backed) from `@nous-research/ui`, bumps
the DS to 0.14.2, and picks up two regressions surfaced by the bump.

Checkbox migration
- bump `@nous-research/ui` 0.14.0 → ^0.14.2 and remove
  `web/src/components/ui/checkbox.tsx`
- migrate `ProfilesPage` and `ModelPickerDialog` to the DS Checkbox API
  (`onCheckedChange`, paired `<Label htmlFor>`)
- expose `Checkbox` on the dashboard plugin SDK
  (`web/src/plugins/registry.ts`) so plugin bundles can use the same
  DS component
- migrate the kanban dashboard plugin's 7 native `<input type="checkbox">`
  call sites to the SDK `Checkbox`, with a native-input fallback shim so
  the bundle still renders against older hosts that predate the SDK export

Fix: missing font registrations after the 0.14.x split
- import `@nous-research/ui/styles/fonts.css` before `globals.css` in
  `web/src/index.css`. As of 0.14.x, `globals.css` only declares the
  `--font-*` variables (Collapse, Mondwest, Rules Compressed/Expanded);
  the `@font-face` registrations now live in a separate `fonts.css`, so
  without this import the DS components silently fall back to a system
  font stack and look unstyled.

Fix: right-align page header toolbars on sm+ viewports
- The mobile dashboard polish in #28127 flipped four pages'
  `setEnd(...)` wrappers from `justify-end` to `w-full ... justify-start`
  so toolbars stack below the title and align left on small screens.
  But the outer `end` slot in `PageHeaderProvider` already has
  `sm:justify-end`, and that has no effect when its only child is
  `w-full` — once a flex child fills the row, the parent's `justify-*`
  can't move it. The toolbar pinned to the *left* of the right-side
  `sm:max-w-md` (~448px) slot, making the buttons appear to float a
  couple-hundred pixels off the right edge on Analytics, Models, Logs,
  and Plugins.
- Re-add `sm:justify-end` on the inner wrapper of each affected page,
  preserving the mobile stacked layout.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(nix): update web npmDeps hash for package-lock bump

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(nix): refresh npm lockfile hashes

* chore(ci): re-trigger checks after nix lockfile hash fix

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-20 08:00:17 -04:00

236 lines
8.4 KiB
CSS

@import 'tailwindcss';
/* `fonts.css` must come BEFORE `globals.css`: as of @nous-research/ui 0.14.x,
`globals.css` only declares the `--font-*` CSS variables (Collapse, Rules
Compressed/Expanded, Mondwest). The `@font-face` registrations live in
`fonts.css`, so without this import the DS variables resolve to font
families the browser never loads and components fall back to a system
stack (Tabs, Segmented, Typography, Buttons, etc. all look unstyled). */
@import '@nous-research/ui/styles/fonts.css';
@import '@nous-research/ui/styles/globals.css';
/* Scan the published design-system bundle so its utility classes survive
Tailwind's JIT purge. */
@source '../node_modules/@nous-research/ui/dist';
/* ------------------------------------------------------------------ */
/* JetBrains Mono — bundled for the embedded TUI (/chat tab). */
/* Gives the terminal a proper monospace font even on systems where */
/* the user doesn't have one installed locally; xterm.js picks it up */
/* via ChatPage's `fontFamily` option. */
/* Apache-2.0. */
/* ------------------------------------------------------------------ */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts-terminal/JetBrainsMono-Regular.woff2') format('woff2');
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts-terminal/JetBrainsMono-Bold.woff2') format('woff2');
}
@font-face {
font-family: 'JetBrains Mono';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('/fonts-terminal/JetBrainsMono-Italic.woff2') format('woff2');
}
/* ------------------------------------------------------------------ */
/* Hermes Agent — Nous DS with the LENS_0 (Hermes teal) lens applied */
/* statically. Mirrors nousnet-web/(hermes-agent)/layout.tsx so the */
/* canonical Hermes palette is the default — teal canvas + cream */
/* accent — without relying on leva/gsap at runtime. */
/* ------------------------------------------------------------------ */
:root {
/* LENS_0 — from design-language/src/ui/components/overlays/index.tsx.
These are the defaults for the `default` (Hermes Teal) dashboard theme;
ThemeProvider rewrites them as inline styles when a user switches themes. */
--foreground: color-mix(in srgb, #ffffff 0%, transparent);
--foreground-base: #ffffff;
--foreground-alpha: 0;
--midground: color-mix(in srgb, #ffe6cb 100%, transparent);
--midground-base: #ffe6cb;
--midground-alpha: 1;
--background: color-mix(in srgb, #041c1c 100%, transparent);
--background-base: #041c1c;
--background-alpha: 1;
/* Consumed by <Backdrop />; also theme-switchable. */
--warm-glow: rgba(255, 189, 56, 0.35);
--noise-opacity-mul: 1;
/* Typography tokens — rewritten by ThemeProvider. Defaults match the
system stack so themes that don't override look native. */
--theme-font-sans: system-ui, -apple-system, "Segoe UI", Roboto,
"Helvetica Neue", Arial, sans-serif;
--theme-font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo,
Consolas, monospace;
--theme-font-display: var(--theme-font-sans);
--theme-base-size: 15px;
--theme-line-height: 1.55;
--theme-letter-spacing: 0;
/* Layout tokens. */
--radius: 0.5rem;
--theme-radius: 0.5rem;
--theme-spacing-mul: 1;
--theme-density: comfortable;
}
/* Theme tokens cascade into the document root so every descendant inherits
the font stack, base size, and letter spacing without explicit calls. */
html {
font-family: var(--theme-font-sans);
font-size: var(--theme-base-size);
line-height: var(--theme-line-height);
letter-spacing: var(--theme-letter-spacing);
height: 100dvh;
max-height: 100dvh;
overflow: hidden;
}
body {
font-family: var(--theme-font-sans);
min-height: 0;
height: 100%;
margin: 0;
overflow: hidden;
}
code, kbd, pre, samp, .font-mono, .font-mono-ui {
font-family: var(--theme-font-mono);
}
/* Density: scale the shadcn spacing utilities via a multiplier. The DS
components use `p-N` / `gap-N` / `space-*` classes which resolve against
Tailwind's spacing scale; multiplying `--spacing` at :root scales them
all proportionally in Tailwind v4. */
@theme inline {
--spacing: calc(0.25rem * var(--theme-spacing-mul, 1));
}
#root {
min-height: 0;
height: 100%;
max-height: 100%;
overflow: hidden;
}
/* Nousnet's hermes-agent layout bumps `small` and `code` to readable
dashboard sizes. Keep in sync. */
small { font-size: 1.0625rem; }
code { font-size: 0.875rem; }
/* Shadcn-compat tokens.
The dashboard's page code predates the Nous DS and uses shadcn-style
utility classes (bg-card, text-muted-foreground, border-border, etc.)
extensively. Rather than rewrite every call site, we expose those
tokens on top of the Nous palette so classes continue to resolve. */
@theme inline {
/* Remap foreground to midground so `text-foreground` / `bg-foreground`
stay visible — in LENS_0, `--foreground` itself has alpha 0. */
--color-foreground: var(--midground);
--color-card: color-mix(in srgb, var(--midground-base) 4%, var(--background-base));
--color-card-foreground: var(--midground);
--color-primary: var(--midground);
--color-primary-foreground: var(--background-base);
--color-secondary: color-mix(in srgb, var(--midground-base) 6%, var(--background-base));
--color-secondary-foreground: var(--midground);
--color-muted: color-mix(in srgb, var(--midground-base) 8%, var(--background-base));
--color-muted-foreground: color-mix(in srgb, var(--midground-base) 55%, transparent);
--color-accent: color-mix(in srgb, var(--midground-base) 10%, var(--background-base));
--color-accent-foreground: var(--midground);
--color-destructive: #fb2c36;
--color-destructive-foreground: #ffffff;
--color-success: #4ade80;
--color-warning: #ffbd38;
--color-border: color-mix(in srgb, var(--midground-base) 15%, transparent);
--color-input: color-mix(in srgb, var(--midground-base) 15%, transparent);
--color-ring: var(--midground);
--color-popover: color-mix(in srgb, var(--midground-base) 4%, var(--background-base));
--color-popover-foreground: var(--midground);
--radius-sm: calc(var(--theme-radius) - 4px);
--radius-md: calc(var(--theme-radius) - 2px);
--radius-lg: var(--theme-radius);
--radius-xl: calc(var(--theme-radius) + 4px);
}
/* Toast animations used by `components/Toast.tsx`. */
@keyframes toast-in {
from { opacity: 0; transform: translateX(16px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes toast-out {
from { opacity: 1; transform: translateX(0); }
to { opacity: 0; transform: translateX(16px); }
}
/* Generic fade + dialog entrance used by popovers and confirm dialogs. */
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes dialog-in {
from { opacity: 0; transform: translateY(4px) scale(0.98); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
/* Hide scrollbar utility — used by the header's overflow-x nav row. */
.scrollbar-none {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-none::-webkit-scrollbar {
display: none;
}
/* Plus-lighter blend used by logos/titles for a subtle glow. */
.blend-lighter {
mix-blend-mode: plus-lighter;
}
/* System UI-monospace stack — distinct from `font-courier` (Courier
Prime), used for dense data readouts where the display font would
break the grid. Routes through the theme's mono stack so themes
with a different monospace (JetBrains Mono, IBM Plex Mono, etc.)
still apply here. */
.font-mono-ui {
font-family: var(--theme-font-mono);
}
/* Subtle grain overlay for badges. */
.grain {
position: relative;
}
.grain::after {
content: '';
position: absolute;
inset: 0;
opacity: 0.12;
pointer-events: none;
background: repeating-conic-gradient(currentColor 0% 25%, #0000 0% 50%) 0 0 /
2px 2px;
}
/* When a theme provides `assets.bg`, the backdrop's <div> renders it as
a CSS background; the default filler <img> is hidden to prevent
double-compositing. Unset → initial → empty, so the :not() selector
matches and the default image stays visible. */
:root:not([style*="--theme-asset-bg:"]) .theme-default-filler {
display: block;
}
:root[style*="--theme-asset-bg:"] .theme-default-filler {
display: none;
}