mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-30 11:52:04 +00:00
fix(web): theme terminal foreground and restore backdrop plugin slot
Make Nous Blue terminal text readable without the inversion layer, re-mount the backdrop plugin slot, and drop unused backdrop CSS vars from theme apply. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
57d98ebed7
commit
10374bb7a2
7 changed files with 44 additions and 39 deletions
|
|
@ -486,6 +486,13 @@ export default function App() {
|
|||
>
|
||||
<SelectionSwitcher />
|
||||
|
||||
<div
|
||||
aria-hidden
|
||||
className="pointer-events-none fixed inset-0 z-0"
|
||||
>
|
||||
<PluginSlot name="backdrop" />
|
||||
</div>
|
||||
|
||||
<header
|
||||
className={cn(
|
||||
"lg:hidden fixed top-0 left-0 right-0 z-40 min-h-14",
|
||||
|
|
|
|||
|
|
@ -317,12 +317,6 @@ function FontSection({ fontChoices, fontId, setFont }: FontSectionProps) {
|
|||
}
|
||||
|
||||
function ThemeSwatch({ theme }: { theme: DashboardTheme }) {
|
||||
// Inverted themes (Nous Blue / future lens themes) author their palette
|
||||
// pre-inversion — `#FFAC02` reads as `#0053FD` blue once the foreground-
|
||||
// difference layer flips the page. The picker can't replay that math
|
||||
// cheaply, so themes opt-in to an explicit `swatchColors` triplet that
|
||||
// mirrors the on-screen result. Falls back to the raw palette hexes for
|
||||
// every other theme so existing dark-theme swatches are untouched.
|
||||
const [c1, c2, c3] = theme.swatchColors ?? [
|
||||
theme.palette.background.hex,
|
||||
theme.palette.midground.hex,
|
||||
|
|
|
|||
|
|
@ -58,14 +58,19 @@ function generateChannelId(scope?: string): string {
|
|||
// with cream foreground — we intentionally don't pick monokai or a loud
|
||||
// theme, because the TUI's skin engine already paints the content; the
|
||||
// terminal chrome just needs to sit quietly inside the dashboard.
|
||||
// `background` is omitted here — it's supplied dynamically from the active
|
||||
// theme's `terminalBackground` field so users can control it via YAML themes.
|
||||
const TERMINAL_THEME_STATIC = {
|
||||
foreground: "#f0e6d2",
|
||||
cursor: "#f0e6d2",
|
||||
cursorAccent: "#0d2626",
|
||||
selectionBackground: "#f0e6d244",
|
||||
};
|
||||
const DEFAULT_TERMINAL_BACKGROUND = "#000000";
|
||||
const DEFAULT_TERMINAL_FOREGROUND = "#f0e6d2";
|
||||
|
||||
function buildTerminalTheme(background: string, foreground: string) {
|
||||
return {
|
||||
background,
|
||||
foreground,
|
||||
cursor: foreground,
|
||||
cursorAccent: background,
|
||||
selectionBackground:
|
||||
foreground.length === 7 ? `${foreground}44` : foreground,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS width for xterm font tiers.
|
||||
|
|
@ -193,10 +198,11 @@ export default function ChatPage({ isActive = true }: { isActive?: boolean }) {
|
|||
);
|
||||
|
||||
const { theme } = useTheme();
|
||||
const terminalBg = theme.terminalBackground ?? "#000000";
|
||||
const terminalBg = theme.terminalBackground ?? DEFAULT_TERMINAL_BACKGROUND;
|
||||
const terminalFg = theme.terminalForeground ?? DEFAULT_TERMINAL_FOREGROUND;
|
||||
const terminalTheme = useMemo(
|
||||
() => ({ ...TERMINAL_THEME_STATIC, background: terminalBg }),
|
||||
[terminalBg],
|
||||
() => buildTerminalTheme(terminalBg, terminalFg),
|
||||
[terminalBg, terminalFg],
|
||||
);
|
||||
|
||||
// The dashboard keeps ChatPage mounted persistently so the PTY survives tab
|
||||
|
|
@ -897,12 +903,12 @@ export default function ChatPage({ isActive = true }: { isActive?: boolean }) {
|
|||
}, [isActive]);
|
||||
|
||||
// Keep the live xterm theme in sync when the active theme's terminal
|
||||
// background changes (e.g. user switches to a custom YAML theme mid-session).
|
||||
// colors change (e.g. user switches to a custom YAML theme mid-session).
|
||||
useEffect(() => {
|
||||
const term = termRef.current;
|
||||
if (!term) return;
|
||||
term.options.theme = { ...TERMINAL_THEME_STATIC, background: terminalBg };
|
||||
}, [terminalBg]);
|
||||
term.options.theme = terminalTheme;
|
||||
}, [terminalTheme]);
|
||||
|
||||
// Layout:
|
||||
// outer flex column — sits inside the dashboard's content area
|
||||
|
|
@ -1065,7 +1071,7 @@ export default function ChatPage({ isActive = true }: { isActive?: boolean }) {
|
|||
"bottom-2 right-2 px-2 py-1 text-xs sm:bottom-3 sm:right-3 sm:px-2.5 sm:py-1.5",
|
||||
"lg:bottom-4 lg:right-4",
|
||||
)}
|
||||
style={{ color: TERMINAL_THEME_STATIC.foreground }}
|
||||
style={{ color: terminalFg }}
|
||||
>
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
<Copy className="h-3 w-3 shrink-0" />
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ import React, { Fragment, useEffect, useState } from "react";
|
|||
* these in their manifest's `slots` field get wired in automatically.
|
||||
*
|
||||
* Shell-wide slots:
|
||||
* - `backdrop` — optional full-viewport background decoration
|
||||
* - `backdrop` — optional full-viewport background decoration;
|
||||
* mounted behind shell chrome at z-0
|
||||
* - `header-left` — injected before the Hermes brand in the top bar
|
||||
* - `header-right` — injected before the theme/language switchers
|
||||
* - `header-banner` — injected below the top nav bar, full-width
|
||||
|
|
|
|||
|
|
@ -82,8 +82,6 @@ function paletteVars(palette: ThemePalette): Record<string, string> {
|
|||
...layerVars("background", palette.background),
|
||||
...layerVars("midground", palette.midground),
|
||||
...layerVars("foreground", palette.foreground),
|
||||
"--warm-glow": palette.warmGlow,
|
||||
"--noise-opacity-mul": String(palette.noiseOpacity),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -391,11 +389,15 @@ function applyTheme(theme: DashboardTheme) {
|
|||
applyCustomCSS(theme.customCSS);
|
||||
applyLayoutVariant(theme.layoutVariant);
|
||||
|
||||
// Terminal background — read by ChatPage via useTheme(); also available as CSS var.
|
||||
// Terminal colors — read by ChatPage via useTheme(); also available as CSS vars.
|
||||
root.style.setProperty(
|
||||
"--theme-terminal-background",
|
||||
theme.terminalBackground ?? "#000000",
|
||||
);
|
||||
root.style.setProperty(
|
||||
"--theme-terminal-foreground",
|
||||
theme.terminalForeground ?? "#f0e6d2",
|
||||
);
|
||||
|
||||
// Re-assert the font override last: theme application just rewrote
|
||||
// --theme-font-sans/-display, so an active override has to win again.
|
||||
|
|
|
|||
|
|
@ -199,6 +199,7 @@ export const nousBlueTheme: DashboardTheme = {
|
|||
typography: DEFAULT_TYPOGRAPHY,
|
||||
layout: DEFAULT_LAYOUT,
|
||||
terminalBackground: "#f5f8fc",
|
||||
terminalForeground: "#170d02",
|
||||
seriesColors: {
|
||||
inputTokenAccent: "#001934",
|
||||
outputTokenAccent: "#0053fd",
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ export type ThemeLayoutVariant = "standard" | "cockpit" | "tiled";
|
|||
* emitted as a CSS var (`--theme-asset-<name>`). Plugin slots and
|
||||
* shell chrome may consume these via CSS. */
|
||||
export interface ThemeAssets {
|
||||
/** Full-viewport background image URL. */
|
||||
/** Full-viewport background image URL. Exposed as `--theme-asset-bg` for
|
||||
* the `backdrop` plugin slot or theme `customCSS`. */
|
||||
bg?: string;
|
||||
/** Hero render (Gundam, mascot, wallpaper) — for plugin sidebars/overlays. */
|
||||
hero?: string;
|
||||
|
|
@ -120,13 +121,7 @@ export interface ThemeComponentStyles {
|
|||
* `--series-input-token` / `--series-output-token` CSS vars consumed
|
||||
* inline by pages that render input-vs-output token flows. Themes can
|
||||
* omit either field to inherit the default token defined in
|
||||
* `index.css` (Hermes-teal `#ffe6cb` for input, `#34d399` for output).
|
||||
*
|
||||
* Inverted-lens themes (e.g. Nous Blue) must pre-invert these hex
|
||||
* values so they read as their intended visual color after the FG
|
||||
* difference layer flips them (`out = 255 − channel`). E.g. to make
|
||||
* output paint as Nous-blue `#0053FD` on screen, set
|
||||
* `outputTokenAccent: "#FFAC02"` — the difference math reverses it. */
|
||||
* `index.css` (Hermes-teal `#ffe6cb` for input, `#34d399` for output). */
|
||||
export interface ThemeSeriesColors {
|
||||
/** Input-tokens series accent (Analytics chart bars + table values). */
|
||||
inputTokenAccent?: string;
|
||||
|
|
@ -177,18 +172,17 @@ export interface DashboardTheme {
|
|||
/** Per-component CSS-var overrides. See `ThemeComponentStyles`. */
|
||||
componentStyles?: ThemeComponentStyles;
|
||||
colorOverrides?: ThemeColorOverrides;
|
||||
/** Data-series accent colors for Analytics/Models token charts.
|
||||
* See `ThemeSeriesColors` for inversion-aware values. */
|
||||
/** Data-series accent colors for Analytics/Models token charts. */
|
||||
seriesColors?: ThemeSeriesColors;
|
||||
/** Explicit 3-color swatch override for the theme picker. Use when the
|
||||
* palette's raw hex values don't reflect what users see on screen —
|
||||
* e.g. inverted "lens" themes whose foreground-difference layer flips
|
||||
* the authored colors to their visual complements. Order matches the
|
||||
/** Explicit 3-color swatch override for the theme picker. Order matches the
|
||||
* default swatch cells: [background, midground, warmGlow]. */
|
||||
swatchColors?: [string, string, string];
|
||||
/** Background color for the embedded terminal pane (xterm.js).
|
||||
* Hex string. Defaults to `"#000000"` when absent. */
|
||||
terminalBackground?: string;
|
||||
/** Default text/cursor color for the embedded terminal pane (xterm.js).
|
||||
* Hex string. Defaults to `"#f0e6d2"` when absent. */
|
||||
terminalForeground?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue