From 95794779d6425c071ade6f98681bafa2a70c3e87 Mon Sep 17 00:00:00 2001 From: Amir Raminfar Date: Sun, 19 Jul 2026 18:38:36 -0700 Subject: [PATCH] feat: Add theme-aware ANSI color palette for log viewer (#4849) Co-authored-by: Claude --- assets/auto-imports.d.ts | 2 ++ .../components/LogViewer/GroupedLogItem.vue | 9 ----- assets/components/LogViewer/SimpleLogItem.vue | 9 ----- assets/main.css | 36 +++++++++++++++++++ assets/utils/ansi.ts | 30 ++++++++++++++++ assets/utils/index.ts | 1 + 6 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 assets/utils/ansi.ts diff --git a/assets/auto-imports.d.ts b/assets/auto-imports.d.ts index 72404e5a..91db872a 100644 --- a/assets/auto-imports.d.ts +++ b/assets/auto-imports.d.ts @@ -17,6 +17,7 @@ declare global { const autoResetRef: typeof import('@vueuse/core').autoResetRef const automaticRedirect: typeof import('./stores/settings').automaticRedirect const collapseNav: typeof import('./stores/settings').collapseNav + const colorize: typeof import('./utils/index').colorize const compact: typeof import('./stores/settings').compact const computed: typeof import('vue').computed const computedAsync: typeof import('@vueuse/core').computedAsync @@ -461,6 +462,7 @@ declare module 'vue' { readonly autoResetRef: UnwrapRef readonly automaticRedirect: UnwrapRef readonly collapseNav: UnwrapRef + readonly colorize: UnwrapRef readonly compact: UnwrapRef readonly computed: UnwrapRef readonly computedAsync: UnwrapRef diff --git a/assets/components/LogViewer/GroupedLogItem.vue b/assets/components/LogViewer/GroupedLogItem.vue index 5cb47e41..1d74c11f 100644 --- a/assets/components/LogViewer/GroupedLogItem.vue +++ b/assets/components/LogViewer/GroupedLogItem.vue @@ -14,13 +14,6 @@ diff --git a/assets/components/LogViewer/SimpleLogItem.vue b/assets/components/LogViewer/SimpleLogItem.vue index dbd66726..35147498 100644 --- a/assets/components/LogViewer/SimpleLogItem.vue +++ b/assets/components/LogViewer/SimpleLogItem.vue @@ -9,17 +9,8 @@ diff --git a/assets/main.css b/assets/main.css index 72da8ab8..091b1f50 100644 --- a/assets/main.css +++ b/assets/main.css @@ -57,6 +57,24 @@ --color-error: var(--color-red); --color-error-content: oklch(98% 0.01 30); + /* ANSI log palette tuned for legibility on the dark background */ + --ansi-black: oklch(45% 0 0); + --ansi-red: oklch(65% 0.2 25); + --ansi-green: oklch(72% 0.16 150); + --ansi-yellow: oklch(80% 0.13 85); + --ansi-blue: oklch(70% 0.14 250); + --ansi-magenta: oklch(68% 0.19 330); + --ansi-cyan: oklch(75% 0.11 200); + --ansi-white: oklch(89% 0 0); + --ansi-bright-black: oklch(60% 0 0); + --ansi-bright-red: oklch(72% 0.2 25); + --ansi-bright-green: oklch(82% 0.17 150); + --ansi-bright-yellow: oklch(88% 0.14 95); + --ansi-bright-blue: oklch(78% 0.13 250); + --ansi-bright-magenta: oklch(75% 0.19 330); + --ansi-bright-cyan: oklch(85% 0.11 200); + --ansi-bright-white: oklch(100% 0 0); + --radius-selector: 1rem; --radius-field: 0.25rem; --radius-box: 0.5rem; @@ -97,6 +115,24 @@ --color-error: var(--color-red); --color-error-content: oklch(98% 0.01 30); + /* ANSI log palette tuned for legibility on the light background */ + --ansi-black: oklch(25% 0 0); + --ansi-red: oklch(52% 0.2 25); + --ansi-green: oklch(52% 0.15 150); + --ansi-yellow: oklch(60% 0.13 75); + --ansi-blue: oklch(50% 0.17 255); + --ansi-magenta: oklch(50% 0.2 330); + --ansi-cyan: oklch(55% 0.1 210); + --ansi-white: oklch(70% 0 0); + --ansi-bright-black: oklch(45% 0 0); + --ansi-bright-red: oklch(58% 0.21 25); + --ansi-bright-green: oklch(58% 0.16 150); + --ansi-bright-yellow: oklch(62% 0.13 85); + --ansi-bright-blue: oklch(55% 0.16 255); + --ansi-bright-magenta: oklch(56% 0.2 330); + --ansi-bright-cyan: oklch(60% 0.1 210); + --ansi-bright-white: oklch(85% 0 0); + --radius-selector: 1rem; --radius-field: 0.25rem; --radius-box: 0.5rem; diff --git a/assets/utils/ansi.ts b/assets/utils/ansi.ts new file mode 100644 index 00000000..0022dd63 --- /dev/null +++ b/assets/utils/ansi.ts @@ -0,0 +1,30 @@ +import AnsiConvertor from "ansi-to-html"; + +// Theme-aware ANSI palette. Values are CSS variables defined per DaisyUI theme in main.css, +// so log colors stay legible on both light and dark backgrounds. The `colors` map merges over +// the library's 256-color defaults, so indices 16-255 keep their standard values. +const ansiConvertor = new AnsiConvertor({ + escapeXML: false, + fg: "var(--color-base-content)", + bg: "var(--color-base-100)", + colors: { + 0: "var(--ansi-black)", + 1: "var(--ansi-red)", + 2: "var(--ansi-green)", + 3: "var(--ansi-yellow)", + 4: "var(--ansi-blue)", + 5: "var(--ansi-magenta)", + 6: "var(--ansi-cyan)", + 7: "var(--ansi-white)", + 8: "var(--ansi-bright-black)", + 9: "var(--ansi-bright-red)", + 10: "var(--ansi-bright-green)", + 11: "var(--ansi-bright-yellow)", + 12: "var(--ansi-bright-blue)", + 13: "var(--ansi-bright-magenta)", + 14: "var(--ansi-bright-cyan)", + 15: "var(--ansi-bright-white)", + }, +}); + +export const colorize = (value: string): string => ansiConvertor.toHtml(value); diff --git a/assets/utils/index.ts b/assets/utils/index.ts index 54dba30d..febf6166 100644 --- a/assets/utils/index.ts +++ b/assets/utils/index.ts @@ -2,3 +2,4 @@ export { formatDuration, toRelativeTime } from "./date"; export { getDeep, isObject, flattenJSON, flattenJSONToMap, arrayEquals } from "./object"; export { useExponentialMovingAverage, useSimpleRefHistory } from "./reactive"; export { formatBytes, stripVersion, hashCode } from "./format"; +export { colorize } from "./ansi";