mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 06:04:51 +00:00
Add theme-configurable HTML export colors (from PR #387)
- Add optional 'export' section to theme JSON with pageBg, cardBg, infoBg - If not specified, colors are auto-derived from userMessageBg - Add export colors to dark.json and light.json - Update theme-schema.json and TypeBox schema - Add documentation to docs/theme.md - Add margin-top back to tool-output for spacing between header and content
This commit is contained in:
parent
d612bc45f5
commit
6267720660
7 changed files with 104 additions and 6 deletions
|
|
@ -104,6 +104,27 @@ These create a visual hierarchy: off → minimal → low → medium → high →
|
||||||
|
|
||||||
**Total: 50 color tokens** (all required)
|
**Total: 50 color tokens** (all required)
|
||||||
|
|
||||||
|
### HTML Export Colors (optional)
|
||||||
|
|
||||||
|
The `export` section is optional and controls colors used when exporting sessions to HTML via `/export`. If not specified, these colors are automatically derived from `userMessageBg` based on luminance detection.
|
||||||
|
|
||||||
|
| Token | Purpose |
|
||||||
|
|-------|---------|
|
||||||
|
| `pageBg` | Page background color |
|
||||||
|
| `cardBg` | Card/container background (headers, stats boxes) |
|
||||||
|
| `infoBg` | Info sections background (system prompt, notices, compaction) |
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"export": {
|
||||||
|
"pageBg": "#18181e",
|
||||||
|
"cardBg": "#1e1e24",
|
||||||
|
"infoBg": "#3c3728"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Theme Format
|
## Theme Format
|
||||||
|
|
||||||
Themes are defined in JSON files with the following structure:
|
Themes are defined in JSON files with the following structure:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import type { AgentState } from "@mariozechner/pi-agent-core";
|
||||||
import { existsSync, readFileSync, writeFileSync } from "fs";
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
||||||
import { basename, join } from "path";
|
import { basename, join } from "path";
|
||||||
import { APP_NAME, getExportTemplateDir } from "../../config.js";
|
import { APP_NAME, getExportTemplateDir } from "../../config.js";
|
||||||
import { getResolvedThemeColors } from "../../modes/interactive/theme/theme.js";
|
import { getResolvedThemeColors, getThemeExportColors } from "../../modes/interactive/theme/theme.js";
|
||||||
import { SessionManager } from "../session-manager.js";
|
import { SessionManager } from "../session-manager.js";
|
||||||
|
|
||||||
export interface ExportOptions {
|
export interface ExportOptions {
|
||||||
|
|
@ -86,12 +86,14 @@ function generateThemeVars(themeName?: string): string {
|
||||||
lines.push(`--${key}: ${value};`);
|
lines.push(`--${key}: ${value};`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add derived export colors
|
// Use explicit theme export colors if available, otherwise derive from userMessageBg
|
||||||
|
const themeExport = getThemeExportColors(themeName);
|
||||||
const userMessageBg = colors.userMessageBg || "#343541";
|
const userMessageBg = colors.userMessageBg || "#343541";
|
||||||
const exportColors = deriveExportColors(userMessageBg);
|
const derivedColors = deriveExportColors(userMessageBg);
|
||||||
lines.push(`--exportPageBg: ${exportColors.pageBg};`);
|
|
||||||
lines.push(`--exportCardBg: ${exportColors.cardBg};`);
|
lines.push(`--exportPageBg: ${themeExport.pageBg ?? derivedColors.pageBg};`);
|
||||||
lines.push(`--exportInfoBg: ${exportColors.infoBg};`);
|
lines.push(`--exportCardBg: ${themeExport.cardBg ?? derivedColors.cardBg};`);
|
||||||
|
lines.push(`--exportInfoBg: ${themeExport.infoBg ?? derivedColors.infoBg};`);
|
||||||
|
|
||||||
return lines.join("\n ");
|
return lines.join("\n ");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,6 +363,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.tool-output {
|
.tool-output {
|
||||||
|
margin-top: var(--line-height);
|
||||||
color: var(--toolOutput);
|
color: var(--toolOutput);
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
|
|
|
||||||
|
|
@ -76,5 +76,10 @@
|
||||||
"thinkingXhigh": "#d183e8",
|
"thinkingXhigh": "#d183e8",
|
||||||
|
|
||||||
"bashMode": "green"
|
"bashMode": "green"
|
||||||
|
},
|
||||||
|
"export": {
|
||||||
|
"pageBg": "#18181e",
|
||||||
|
"cardBg": "#1e1e24",
|
||||||
|
"infoBg": "#3c3728"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,5 +75,10 @@
|
||||||
"thinkingXhigh": "#8b008b",
|
"thinkingXhigh": "#8b008b",
|
||||||
|
|
||||||
"bashMode": "green"
|
"bashMode": "green"
|
||||||
|
},
|
||||||
|
"export": {
|
||||||
|
"pageBg": "#f8f8f8",
|
||||||
|
"cardBg": "#ffffff",
|
||||||
|
"infoBg": "#fffae6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -267,6 +267,25 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"export": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Optional colors for HTML export (defaults derived from userMessageBg if not specified)",
|
||||||
|
"properties": {
|
||||||
|
"pageBg": {
|
||||||
|
"$ref": "#/$defs/colorValue",
|
||||||
|
"description": "Page background color"
|
||||||
|
},
|
||||||
|
"cardBg": {
|
||||||
|
"$ref": "#/$defs/colorValue",
|
||||||
|
"description": "Card/container background color"
|
||||||
|
},
|
||||||
|
"infoBg": {
|
||||||
|
"$ref": "#/$defs/colorValue",
|
||||||
|
"description": "Info sections background (system prompt, notices)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,13 @@ const ThemeJsonSchema = Type.Object({
|
||||||
// Bash Mode (1 color)
|
// Bash Mode (1 color)
|
||||||
bashMode: ColorValueSchema,
|
bashMode: ColorValueSchema,
|
||||||
}),
|
}),
|
||||||
|
export: Type.Optional(
|
||||||
|
Type.Object({
|
||||||
|
pageBg: Type.Optional(ColorValueSchema),
|
||||||
|
cardBg: Type.Optional(ColorValueSchema),
|
||||||
|
infoBg: Type.Optional(ColorValueSchema),
|
||||||
|
}),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
type ThemeJson = Static<typeof ThemeJsonSchema>;
|
type ThemeJson = Static<typeof ThemeJsonSchema>;
|
||||||
|
|
@ -737,6 +744,44 @@ export function isLightTheme(themeName?: string): boolean {
|
||||||
return themeName === "light";
|
return themeName === "light";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get explicit export colors from theme JSON, if specified.
|
||||||
|
* Returns undefined for each color that isn't explicitly set.
|
||||||
|
*/
|
||||||
|
export function getThemeExportColors(themeName?: string): {
|
||||||
|
pageBg?: string;
|
||||||
|
cardBg?: string;
|
||||||
|
infoBg?: string;
|
||||||
|
} {
|
||||||
|
const name = themeName ?? getDefaultTheme();
|
||||||
|
try {
|
||||||
|
const themeJson = loadThemeJson(name);
|
||||||
|
const exportSection = themeJson.export;
|
||||||
|
if (!exportSection) return {};
|
||||||
|
|
||||||
|
const vars = themeJson.vars ?? {};
|
||||||
|
const resolve = (value: string | number | undefined): string | undefined => {
|
||||||
|
if (value === undefined) return undefined;
|
||||||
|
if (typeof value === "number") return ansi256ToHex(value);
|
||||||
|
if (value.startsWith("$")) {
|
||||||
|
const resolved = vars[value];
|
||||||
|
if (resolved === undefined) return undefined;
|
||||||
|
if (typeof resolved === "number") return ansi256ToHex(resolved);
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
pageBg: resolve(exportSection.pageBg),
|
||||||
|
cardBg: resolve(exportSection.cardBg),
|
||||||
|
infoBg: resolve(exportSection.infoBg),
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// TUI Helpers
|
// TUI Helpers
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue