diff --git a/CHANGELOG.md b/CHANGELOG.md index 526c8c47..734914eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +- Flexoki themes for Shiki syntax highlighting for consistency with the app color schema. + ## [1.1.3] - 2025-12-14 diff --git a/packages/desktop/src-tauri/Cargo.lock b/packages/desktop/src-tauri/Cargo.lock index 303a4b4e..f331b419 100644 --- a/packages/desktop/src-tauri/Cargo.lock +++ b/packages/desktop/src-tauri/Cargo.lock @@ -2847,7 +2847,7 @@ dependencies = [ [[package]] name = "openchamber-desktop" -version = "1.1.2" +version = "1.1.3" dependencies = [ "anyhow", "axum", diff --git a/packages/ui/src/components/chat/MarkdownRenderer.tsx b/packages/ui/src/components/chat/MarkdownRenderer.tsx index 0bfe734c..7a79dfd2 100644 --- a/packages/ui/src/components/chat/MarkdownRenderer.tsx +++ b/packages/ui/src/components/chat/MarkdownRenderer.tsx @@ -5,7 +5,9 @@ import type { Part } from '@opencode-ai/sdk'; import { cn } from '@/lib/utils'; import { RiFileCopyLine, RiCheckLine, RiDownloadLine } from '@remixicon/react'; -const SHIKI_THEMES = ['vitesse-light', 'vitesse-dark'] as const; +import { flexokiStreamdownThemes } from '@/lib/shiki/flexokiThemes'; + +const SHIKI_THEMES = flexokiStreamdownThemes; // Table utility functions const extractTableData = (tableEl: HTMLTableElement): { headers: string[]; rows: string[][] } => { @@ -243,6 +245,50 @@ const CodeBlockWrapper: React.FC = ({ children, className const [copied, setCopied] = React.useState(false); const codeRef = React.useRef(null); + const normalizedStyle = React.useMemo(() => { + if (!style) return style; + + const next: React.CSSProperties = { ...style }; + + const normalizeDeclarationString = ( + raw: unknown + ): { value?: string; vars: Record } => { + if (typeof raw !== 'string') return { value: undefined, vars: {} }; + + const [valuePart, ...rest] = raw.split(';').map((p) => p.trim()).filter(Boolean); + const vars: Record = {}; + for (const decl of rest) { + const idx = decl.indexOf(':'); + if (idx === -1) continue; + const prop = decl.slice(0, idx).trim(); + const value = decl.slice(idx + 1).trim(); + if (!prop.startsWith('--') || value.length === 0) continue; + vars[prop] = value; + } + return { value: valuePart, vars }; + }; + + const bg = normalizeDeclarationString((style as React.CSSProperties).backgroundColor); + if (bg.value) { + next.backgroundColor = bg.value; + (next as Record)['--shiki-light-bg'] = bg.value; + } + for (const [k, v] of Object.entries(bg.vars)) { + (next as Record)[k] = v; + } + + const fg = normalizeDeclarationString((style as React.CSSProperties).color); + if (fg.value) { + next.color = fg.value; + (next as Record)['--shiki-light'] = fg.value; + } + for (const [k, v] of Object.entries(fg.vars)) { + (next as Record)[k] = v; + } + + return next; + }, [style]); + const getCodeContent = (): string => { if (!codeRef.current) return ''; const codeEl = codeRef.current.querySelector('code'); @@ -267,11 +313,7 @@ const CodeBlockWrapper: React.FC = ({ children, className
         {children}
       
diff --git a/packages/ui/src/components/views/PierreDiffViewer.tsx b/packages/ui/src/components/views/PierreDiffViewer.tsx index 06e4a8a0..4f21d6bf 100644 --- a/packages/ui/src/components/views/PierreDiffViewer.tsx +++ b/packages/ui/src/components/views/PierreDiffViewer.tsx @@ -4,6 +4,8 @@ import { parseDiffFromFile, type FileContents, type FileDiffMetadata } from '@pi import { useOptionalThemeSystem } from '@/contexts/useThemeSystem'; import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay'; +import { ensureFlexokiThemesRegistered } from '@/lib/shiki/registerFlexokiThemes'; +import { flexokiThemeNames } from '@/lib/shiki/flexokiThemes'; interface PierreDiffViewerProps { original: string; @@ -51,6 +53,8 @@ export const PierreDiffViewer: React.FC = ({ const themeSystem = useOptionalThemeSystem(); const isDark = themeSystem?.currentTheme?.metadata?.variant === 'dark'; + ensureFlexokiThemesRegistered(); + // Cache the last computed diff to avoid recomputing on every render const diffCacheRef = useRef<{ key: string; @@ -90,8 +94,8 @@ export const PierreDiffViewer: React.FC = ({ const options = useMemo(() => ({ theme: { - dark: 'vitesse-dark' as const, - light: 'vitesse-light' as const, + dark: flexokiThemeNames.dark, + light: flexokiThemeNames.light, }, themeType: isDark ? ('dark' as const) : ('light' as const), diffStyle: renderSideBySide ? ('split' as const) : ('unified' as const), diff --git a/packages/ui/src/contexts/DiffWorkerProvider.tsx b/packages/ui/src/contexts/DiffWorkerProvider.tsx index ce82d75b..e67da7d7 100644 --- a/packages/ui/src/contexts/DiffWorkerProvider.tsx +++ b/packages/ui/src/contexts/DiffWorkerProvider.tsx @@ -4,6 +4,8 @@ import type { SupportedLanguages } from '@pierre/diffs'; import { useOptionalThemeSystem } from './useThemeSystem'; import { workerFactory } from '@/lib/diff/workerFactory'; +import { ensureFlexokiThemesRegistered } from '@/lib/shiki/registerFlexokiThemes'; +import { flexokiThemeNames } from '@/lib/shiki/flexokiThemes'; // Only preload the most common languages - others load on demand const PRELOAD_LANGS: SupportedLanguages[] = [ @@ -21,10 +23,12 @@ export const DiffWorkerProvider: React.FC = ({ children const themeSystem = useOptionalThemeSystem(); const isDark = themeSystem?.currentTheme?.metadata?.variant === 'dark'; + ensureFlexokiThemesRegistered(); + const highlighterOptions = useMemo(() => ({ theme: { - dark: 'vitesse-dark' as const, - light: 'vitesse-light' as const, + dark: flexokiThemeNames.dark, + light: flexokiThemeNames.light, }, themeType: isDark ? ('dark' as const) : ('light' as const), langs: PRELOAD_LANGS, diff --git a/packages/ui/src/index.css b/packages/ui/src/index.css index 329ba9c8..bd83853c 100644 --- a/packages/ui/src/index.css +++ b/packages/ui/src/index.css @@ -1301,6 +1301,21 @@ html:not(.dark) .chat-scroll { font-family: var(--font-mono); } +/* Streamdown code blocks: ensure light/dark Shiki vars work even when Tailwind doesn't scan Streamdown's internal class names. */ +.streamdown-content [data-streamdown="code-block-body"] { + background-color: var(--shiki-light-bg, transparent); + color: var(--shiki-light, inherit); +} + +.dark .streamdown-content [data-streamdown="code-block-body"] { + background-color: var(--shiki-dark-bg, var(--shiki-light-bg, transparent)); + color: var(--shiki-dark, var(--shiki-light, inherit)); +} + +.dark .streamdown-content [data-streamdown="code-block-body"] span[style*="--shiki-dark"] { + color: var(--shiki-dark) !important; +} + /* Fix list styling - override Tailwind reset */ .streamdown-content ul { list-style-type: disc; diff --git a/packages/ui/src/lib/shiki/flexokiThemes.ts b/packages/ui/src/lib/shiki/flexokiThemes.ts new file mode 100644 index 00000000..20615709 --- /dev/null +++ b/packages/ui/src/lib/shiki/flexokiThemes.ts @@ -0,0 +1,94 @@ +import flexokiDarkRawJson from './themes/flexoki-dark.json'; +import flexokiLightRawJson from './themes/flexoki-light.json'; + +export const FLEXOKI_SHIKI_DARK_THEME_NAME = 'flexoki-dark'; +export const FLEXOKI_SHIKI_LIGHT_THEME_NAME = 'flexoki-light'; + +type VSCodeTokenColorRule = { + name?: string; + scope?: string | string[]; + settings: Record; +}; + +type VSCodeTextMateTheme = { + name: string; + type: 'dark' | 'light'; + colors?: Record; + tokenColors?: VSCodeTokenColorRule[]; + semanticHighlighting?: boolean; + semanticTokenColors?: Record; +}; + +type ShikiThemeRegistrationResolvedLike = VSCodeTextMateTheme & { + settings: VSCodeTokenColorRule[]; + fg: string; + bg: string; +}; + +const flexokiDarkRaw = flexokiDarkRawJson as VSCodeTextMateTheme; +const flexokiLightRaw = flexokiLightRawJson as VSCodeTextMateTheme; + +function withStableStringId(value: T, id: string): T { + Object.defineProperty(value, 'toString', { + value: () => id, + enumerable: false, + }); + + Object.defineProperty(value, Symbol.toPrimitive, { + value: () => id, + enumerable: false, + }); + + return value; +} + +function toResolvedTheme( + raw: VSCodeTextMateTheme, + name: string, + type: VSCodeTextMateTheme['type'] +): ShikiThemeRegistrationResolvedLike { + const bg = raw.colors?.['editor.background']; + const fg = raw.colors?.['editor.foreground']; + + if (!bg || !fg) { + throw new Error( + `Flexoki Shiki theme "${name}" is missing editor.background/editor.foreground` + ); + } + + const settings = raw.tokenColors ?? []; + + return { + ...raw, + name, + type, + fg, + bg, + settings, + }; +} + +export const flexokiDarkTheme = toResolvedTheme( + flexokiDarkRaw, + FLEXOKI_SHIKI_DARK_THEME_NAME, + 'dark' +); + +export const flexokiLightTheme = toResolvedTheme( + flexokiLightRaw, + FLEXOKI_SHIKI_LIGHT_THEME_NAME, + 'light' +); + +withStableStringId(flexokiDarkTheme, FLEXOKI_SHIKI_DARK_THEME_NAME); +withStableStringId(flexokiLightTheme, FLEXOKI_SHIKI_LIGHT_THEME_NAME); + +export const flexokiThemeNames = { + dark: FLEXOKI_SHIKI_DARK_THEME_NAME, + light: FLEXOKI_SHIKI_LIGHT_THEME_NAME, +} as const; + +export const flexokiStreamdownThemes = [ + flexokiLightTheme, + flexokiDarkTheme, +] as const; diff --git a/packages/ui/src/lib/shiki/registerFlexokiThemes.ts b/packages/ui/src/lib/shiki/registerFlexokiThemes.ts new file mode 100644 index 00000000..4270cddb --- /dev/null +++ b/packages/ui/src/lib/shiki/registerFlexokiThemes.ts @@ -0,0 +1,15 @@ +import { registerCustomTheme } from '@pierre/diffs'; + +import { flexokiDarkTheme, flexokiLightTheme, flexokiThemeNames } from './flexokiThemes'; + +let hasRegistered = false; + +export function ensureFlexokiThemesRegistered(): void { + if (hasRegistered) return; + + registerCustomTheme(flexokiThemeNames.dark, async () => flexokiDarkTheme); + registerCustomTheme(flexokiThemeNames.light, async () => flexokiLightTheme); + + hasRegistered = true; +} + diff --git a/packages/ui/src/lib/shiki/themes/flexoki-dark.json b/packages/ui/src/lib/shiki/themes/flexoki-dark.json new file mode 100644 index 00000000..53e0144b --- /dev/null +++ b/packages/ui/src/lib/shiki/themes/flexoki-dark.json @@ -0,0 +1,547 @@ +{ + "name": "Flexoki", + "type": "dark", + "colors": { + "editor.background": "#100F0F", + "editor.foreground": "#CECDC3", + "editor.hoverHighlightBackground": "#343331", + "editor.lineHighlightBackground": "#1C1B1A", + "editor.selectionBackground": "#CECDC333", + "editor.selectionHighlightBackground": "#CECDC333", + "editor.findMatchBackground": "#AD8301", + "editor.findMatchHighlightBackground": "#AD8301cc", + "editor.findRangeHighlightBackground": "#1C1B1A", + "editor.inactiveSelectionBackground": "#282726", + "editor.lineHighlightBorder": "#282726", + "editor.rangeHighlightBackground": "#403E3C", + "notifications.background": "#282726", + "editorInlayHint.typeBackground": "#343331", + "editorInlayHint.typeForeground": "#CECDC3", + "editorWhitespace.foreground": "#403E3C", + "editorIndentGuide.background1": "#343331", + "editorHoverWidget.background": "#282726", + "editorLineNumber.activeForeground": "#CECDC3", + "editorLineNumber.foreground": "#403E3C", + "editorGutter.background": "#100F0F", + "editorGutter.modifiedBackground": "#3AA99F", + "editorGutter.addedBackground": "#879A39", + "editorGutter.deletedBackground": "#D14D41", + "editorBracketMatch.background": "#282726", + "editorBracketMatch.border": "#343331", + "editorError.foreground": "#D14D41", + "editorWarning.foreground": "#DA702C", + "editorInfo.foreground": "#4385BE", + "diffEditor.insertedTextBackground": "#66800B99", + "diffEditor.removedTextBackground": "#AF302999", + "editorGroupHeader.tabsBackground": "#100F0F", + "editorGroup.border": "#343331", + "tab.activeBackground": "#100F0F", + "tab.inactiveBackground": "#1C1B1A", + "tab.inactiveForeground": "#878580", + "tab.activeForeground": "#CECDC3", + "tab.hoverBackground": "#343331", + "tab.unfocusedHoverBackground": "#343331", + "tab.border": "#343331", + "tab.activeModifiedBorder": "#D0A215", + "tab.inactiveModifiedBorder": "#4385BE", + "tab.unfocusedActiveModifiedBorder": "#AD8301", + "tab.unfocusedInactiveModifiedBorder": "#205EA6", + "editorWidget.background": "#1C1B1A", + "editorWidget.border": "#343331", + "editorSuggestWidget.background": "#100F0F", + "editorSuggestWidget.border": "#343331", + "editorSuggestWidget.foreground": "#CECDC3", + "editorSuggestWidget.highlightForeground": "#878580", + "editorSuggestWidget.selectedBackground": "#343331", + "peekView.border": "#343331", + "peekViewEditor.background": "#100F0F", + "peekViewEditor.matchHighlightBackground": "#403E3C", + "peekViewResult.background": "#1C1B1A", + "peekViewResult.fileForeground": "#CECDC3", + "peekViewResult.lineForeground": "#878580", + "peekViewResult.matchHighlightBackground": "#403E3C", + "peekViewResult.selectionBackground": "#282726", + "peekViewResult.selectionForeground": "#575653", + "peekViewTitle.background": "#343331", + "peekViewTitleDescription.foreground": "#878580", + "peekViewTitleLabel.foreground": "#CECDC3", + "merge.currentHeaderBackground": "#879A39", + "merge.currentContentBackground": "#66800B", + "merge.incomingHeaderBackground": "#3AA99F", + "merge.incomingContentBackground": "#24837B", + "merge.border": "#343331", + "merge.commonContentBackground": "#403E3C", + "merge.commonHeaderBackground": "#343331", + "panel.background": "#100F0F", + "panel.border": "#343331", + "panelTitle.activeBorder": "#403E3C", + "panelTitle.activeForeground": "#CECDC3", + "panelTitle.inactiveForeground": "#878580", + "statusBar.background": "#100F0F", + "statusBar.foreground": "#CECDC3", + "statusBar.border": "#343331", + "statusBar.debuggingBackground": "#D14D41", + "statusBar.debuggingForeground": "#CECDC3", + "statusBar.noFolderBackground": "#403E3C", + "statusBar.noFolderForeground": "#575653", + "titleBar.activeBackground": "#100F0F", + "titleBar.activeForeground": "#CECDC3", + "titleBar.inactiveBackground": "#1C1B1A", + "titleBar.inactiveForeground": "#878580", + "titleBar.border": "#343331", + "menu.foreground": "#CECDC3", + "menu.background": "#100F0F", + "menu.selectionForeground": "#CECDC3", + "menu.selectionBackground": "#343331", + "menu.border": "#343331", + "editorInlayHint.foreground": "#878580", + "editorInlayHint.background": "#343331", + "terminal.foreground": "#CECDC3", + "terminal.background": "#100F0F", + "terminalCursor.foreground": "#CECDC3", + "terminalCursor.background": "#100F0F", + "terminal.ansiRed": "#D14D41", + "terminal.ansiGreen": "#879A39", + "terminal.ansiYellow": "#D0A215", + "terminal.ansiBlue": "#4385BE", + "terminal.ansiMagenta": "#3AA99F", + "terminal.ansiCyan": "#3AA99F", + "activityBar.background": "#100F0F", + "activityBar.foreground": "#CECDC3", + "activityBar.inactiveForeground": "#878580", + "activityBar.activeBorder": "#CECDC3", + "activityBar.border": "#343331", + "sideBar.background": "#100F0F", + "sideBar.foreground": "#CECDC3", + "sideBar.border": "#343331", + "sideBarTitle.foreground": "#CECDC3", + "sideBarSectionHeader.background": "#1C1B1A", + "sideBarSectionHeader.foreground": "#CECDC3", + "sideBarSectionHeader.border": "#343331", + "sideBar.activeBackground": "#403E3C", + "sideBar.activeForeground": "#CECDC3", + "sideBar.hoverBackground": "#343331", + "sideBar.hoverForeground": "#878580", + "sideBar.folderIcon.foreground": "#879A39", + "sideBar.fileIcon.foreground": "#4385BE", + "list.warningForeground": "#DA702C", + "list.errorForeground": "#D14D41", + "list.inactiveSelectionBackground": "#343331", + "list.activeSelectionBackground": "#403E3C", + "list.inactiveSelectionForeground": "#CECDC3", + "list.activeSelectionForeground": "#CECDC3", + "list.hoverForeground": "#CECDC3", + "list.hoverBackground": "#343331", + "input.background": "#1C1B1A", + "input.foreground": "#CECDC3", + "input.border": "#343331", + "input.placeholderForeground": "#878580", + "inputOption.activeBorder": "#343331", + "inputOption.activeBackground": "#282726", + "inputOption.activeForeground": "#CECDC3", + "inputValidation.infoBackground": "#3AA99F", + "inputValidation.infoBorder": "#24837B", + "inputValidation.warningBackground": "#DA702C", + "inputValidation.warningBorder": "#BC5215", + "inputValidation.errorBackground": "#D14D41", + "inputValidation.errorBorder": "#AF3029", + "dropdown.background": "#1C1B1A", + "dropdown.foreground": "#CECDC3", + "dropdown.border": "#343331", + "dropdown.listBackground": "#100F0F", + "badge.background": "#3AA99F", + "activityBarBadge.background": "#3AA99F", + "button.background": "#3AA99F", + "button.foreground": "#100F0F", + "badge.foreground": "#100F0F", + "activityBarBadge.foreground": "#100F0F" + }, + "tokenColors": [ + { + "name": "plain", + "scope": ["source", "support.type.property-name.css"], + "settings": { + "foreground": "#CECDC3" + } + }, + { + "name": "classes", + "scope": ["entity.name.type.class"], + "settings": { + "foreground": "#DA702C" + } + }, + { + "name": "interfaces", + "scope": ["entity.name.type.interface", "entity.name.type"], + "settings": { + "foreground": "#D0A215" + } + }, + { + "name": "structs", + "scope": ["entity.name.type.struct"], + "settings": { + "foreground": "#DA702C" + } + }, + { + "name": "enums", + "scope": ["entity.name.type.enum"], + "settings": { + "foreground": "#DA702C" + } + }, + { + "name": "keys", + "scope": ["meta.object-literal.key", "support.type.property-name"], + "settings": { + "foreground": "#DA702C" + } + }, + { + "name": "methods", + "scope": ["entity.name.function.method", "meta.function.method"], + "settings": { + "foreground": "#879A39" + } + }, + { + "name": "functions", + "scope": [ + "entity.name.function", + "support.function", + "meta.function-call.generic" + ], + "settings": { + "foreground": "#DA702C", + "fontStyle": "bold" + } + }, + { + "name": "variables", + "scope": ["variable", "meta.variable", "variable.other.object.property"], + "settings": { + "foreground": "#CECDC3" + } + }, + { + "name": "variablesOther", + "scope": ["variable.other.object", "variable.other.readwrite.alias"], + "settings": { + "foreground": "#879A39" + } + }, + { + "name": "globalVariables", + "scope": ["variable.other.global", "variable.language.this"], + "settings": { + "foreground": "#CE5D97" + } + }, + { + "name": "localVariables", + "scope": ["variable.other.local"], + "settings": { + "foreground": "#282726" + } + }, + { + "name": "parameters", + "scope": ["variable.parameter", "meta.parameter"], + "settings": { + "foreground": "#CECDC3" + } + }, + { + "name": "properties", + "scope": ["variable.other.property", "meta.property"], + "settings": { + "foreground": "#4385BE" + } + }, + { + "name": "strings", + "scope": [ + "string", + "string.other.link", + "markup.inline.raw.string.markdown" + ], + "settings": { + "foreground": "#3AA99F" + } + }, + { + "name": "stringEscapeSequences", + "scope": ["constant.character.escape", "constant.other.placeholder"], + "settings": { + "foreground": "#CECDC3" + } + }, + { + "name": "keywords", + "scope": ["keyword"], + "settings": { + "foreground": "#879A39" + } + }, + { + "name": "keywordsControl", + "scope": [ + "keyword.control.import", + "keyword.control.from", + "keyword.import" + ], + "settings": { + "foreground": "#D14D41" + } + }, + { + "name": "storageModifiers", + "scope": ["storage.modifier", "keyword.modifier", "storage.type"], + "settings": { + "foreground": "#4385BE" + } + }, + { + "name": "comments", + "scope": ["comment", "punctuation.definition.comment"], + "settings": { + "foreground": "#878580" + } + }, + { + "name": "docComments", + "scope": ["comment.documentation", "comment.line.documentation"], + "settings": { + "foreground": "#575653" + } + }, + { + "name": "numbers", + "scope": ["constant.numeric"], + "settings": { + "foreground": "#8B7EC8" + } + }, + { + "name": "booleans", + "scope": ["constant.language.boolean", "constant.language.json"], + "settings": { + "foreground": "#D0A215" + } + }, + { + "name": "operators", + "scope": ["keyword.operator"], + "settings": { + "foreground": "#D14D41" + } + }, + { + "name": "macros", + "scope": ["entity.name.function.preprocessor", "meta.preprocessor"], + "settings": { + "foreground": "#4385BE" + } + }, + { + "name": "preprocessor", + "scope": ["meta.preprocessor"], + "settings": { + "foreground": "#CE5D97" + } + }, + { + "name": "urls", + "scope": ["markup.underline.link"], + "settings": { + "foreground": "#4385BE" + } + }, + { + "name": "tags", + "scope": ["entity.name.tag"], + "settings": { + "foreground": "#4385BE" + } + }, + { + "name": "jsxTags", + "scope": ["support.class.component"], + "settings": { + "foreground": "#CE5D97" + } + }, + { + "name": "attributes", + "scope": ["entity.other.attribute-name", "meta.attribute"], + "settings": { + "foreground": "#D0A215" + } + }, + { + "name": "types", + "scope": ["support.type"], + "settings": { + "foreground": "#D0A215" + } + }, + { + "name": "constants", + "scope": ["variable.other.constant", "variable.readonly"], + "settings": { + "foreground": "#CECDC3" + } + }, + { + "name": "labels", + "scope": ["entity.name.label", "punctuation.definition.label"], + "settings": { + "foreground": "#CE5D97" + } + }, + { + "name": "namespaces", + "scope": [ + "entity.name.namespace", + "storage.modifier.namespace", + "markup.bold.markdown" + ], + "settings": { + "foreground": "#D0A215" + } + }, + { + "name": "modules", + "scope": ["entity.name.module", "storage.modifier.module"], + "settings": { + "foreground": "#D14D41" + } + }, + { + "name": "typeParameters", + "scope": ["variable.type.parameter", "variable.parameter.type"], + "settings": { + "foreground": "#DA702C" + } + }, + { + "name": "exceptions", + "scope": ["keyword.control.exception", "keyword.control.trycatch"], + "settings": { + "foreground": "#CE5D97" + } + }, + { + "name": "decorators", + "scope": [ + "meta.decorator", + "punctuation.decorator", + "entity.name.function.decorator" + ], + "settings": { + "foreground": "#D0A215" + } + }, + { + "name": "calls", + "scope": ["variable.function"], + "settings": { + "foreground": "#CECDC3" + } + }, + { + "name": "punctuation", + "scope": [ + "punctuation", + "punctuation.terminator", + "punctuation.definition.tag", + "punctuation.separator", + "punctuation.definition.string", + "punctuation.section.block" + ], + "settings": { + "foreground": "#878580" + } + }, + { + "name": "yellow", + "scope": [ + "storage.type.numeric.go", + "storage.type.byte.go", + "storage.type.boolean.go", + "storage.type.string.go", + "storage.type.uintptr.go", + "storage.type.error.go", + "storage.type.rune.go", + "constant.language.go", + "support.class.dart", + "keyword.other.documentation", + "storage.modifier.import.java", + "punctuation.definition.list.begin.markdown", + "punctuation.definition.quote.begin.markdown", + "meta.separator.markdown", + "entity.name.section.markdown" + ], + "settings": { + "foreground": "#D0A215" + } + }, + { + "name": "green", + "scope": [], + "settings": { + "foreground": "#879A39" + } + }, + { + "name": "cyan", + "scope": [ + "markup.italic.markdown", + "support.type.python", + "variable.legacy.builtin.python", + "support.constant.property-value.css", + "storage.modifier.attribute.swift" + ], + "settings": { + "foreground": "#3AA99F" + } + }, + { + "name": "blue", + "scope": [], + "settings": { + "foreground": "#4385BE" + } + }, + { + "name": "purple", + "scope": ["keyword.channel.go", "keyword.other.platform.os.swift"], + "settings": { + "foreground": "#8B7EC8" + } + }, + { + "name": "magenta", + "scope": ["punctuation.definition.heading.markdown"], + "settings": { + "foreground": "#CE5D97" + } + }, + { + "name": "red", + "scope": [], + "settings": { + "foreground": "#D14D41" + } + }, + { + "name": "orange", + "scope": [], + "settings": { + "foreground": "#DA702C" + } + } + ] +} diff --git a/packages/ui/src/lib/shiki/themes/flexoki-light.json b/packages/ui/src/lib/shiki/themes/flexoki-light.json new file mode 100644 index 00000000..05e618b3 --- /dev/null +++ b/packages/ui/src/lib/shiki/themes/flexoki-light.json @@ -0,0 +1,547 @@ +{ + "name": "Flexoki", + "type": "light", + "colors": { + "editor.background": "#FFFCF0", + "editor.foreground": "#100F0F", + "editor.hoverHighlightBackground": "#DAD8CE", + "editor.lineHighlightBackground": "#F2F0E5", + "editor.selectionBackground": "#100F0F44", + "editor.selectionHighlightBackground": "#100F0F44", + "editor.findMatchBackground": "#D0A215", + "editor.findMatchHighlightBackground": "#D0A215cc", + "editor.findRangeHighlightBackground": "#F2F0E5", + "editor.inactiveSelectionBackground": "#E6E4D9", + "editor.lineHighlightBorder": "#E6E4D9", + "editor.rangeHighlightBackground": "#CECDC3", + "notifications.background": "#E6E4D9", + "editorInlayHint.typeBackground": "#DAD8CE", + "editorInlayHint.typeForeground": "#100F0F", + "editorWhitespace.foreground": "#CECDC3", + "editorIndentGuide.background1": "#DAD8CE", + "editorHoverWidget.background": "#E6E4D9", + "editorLineNumber.activeForeground": "#100F0F", + "editorLineNumber.foreground": "#CECDC3", + "editorGutter.background": "#FFFCF0", + "editorGutter.modifiedBackground": "#24837B", + "editorGutter.addedBackground": "#66800B", + "editorGutter.deletedBackground": "#AF3029", + "editorBracketMatch.background": "#E6E4D9", + "editorBracketMatch.border": "#DAD8CE", + "editorError.foreground": "#AF3029", + "editorWarning.foreground": "#BC5215", + "editorInfo.foreground": "#205EA6", + "diffEditor.insertedTextBackground": "#879A3999", + "diffEditor.removedTextBackground": "#D14D4199", + "editorGroupHeader.tabsBackground": "#FFFCF0", + "editorGroup.border": "#DAD8CE", + "tab.activeBackground": "#FFFCF0", + "tab.inactiveBackground": "#F2F0E5", + "tab.inactiveForeground": "#6F6E69", + "tab.activeForeground": "#100F0F", + "tab.hoverBackground": "#DAD8CE", + "tab.unfocusedHoverBackground": "#DAD8CE", + "tab.border": "#DAD8CE", + "tab.activeModifiedBorder": "#AD8301", + "tab.inactiveModifiedBorder": "#205EA6", + "tab.unfocusedActiveModifiedBorder": "#D0A215", + "tab.unfocusedInactiveModifiedBorder": "#4385BE", + "editorWidget.background": "#F2F0E5", + "editorWidget.border": "#DAD8CE", + "editorSuggestWidget.background": "#FFFCF0", + "editorSuggestWidget.border": "#DAD8CE", + "editorSuggestWidget.foreground": "#100F0F", + "editorSuggestWidget.highlightForeground": "#6F6E69", + "editorSuggestWidget.selectedBackground": "#DAD8CE", + "peekView.border": "#DAD8CE", + "peekViewEditor.background": "#FFFCF0", + "peekViewEditor.matchHighlightBackground": "#CECDC3", + "peekViewResult.background": "#F2F0E5", + "peekViewResult.fileForeground": "#100F0F", + "peekViewResult.lineForeground": "#6F6E69", + "peekViewResult.matchHighlightBackground": "#CECDC3", + "peekViewResult.selectionBackground": "#E6E4D9", + "peekViewResult.selectionForeground": "#B7B5AC", + "peekViewTitle.background": "#DAD8CE", + "peekViewTitleDescription.foreground": "#6F6E69", + "peekViewTitleLabel.foreground": "#100F0F", + "merge.currentHeaderBackground": "#66800B", + "merge.currentContentBackground": "#879A39", + "merge.incomingHeaderBackground": "#24837B", + "merge.incomingContentBackground": "#3AA99F", + "merge.border": "#DAD8CE", + "merge.commonContentBackground": "#CECDC3", + "merge.commonHeaderBackground": "#DAD8CE", + "panel.background": "#FFFCF0", + "panel.border": "#DAD8CE", + "panelTitle.activeBorder": "#CECDC3", + "panelTitle.activeForeground": "#100F0F", + "panelTitle.inactiveForeground": "#6F6E69", + "statusBar.background": "#FFFCF0", + "statusBar.foreground": "#100F0F", + "statusBar.border": "#DAD8CE", + "statusBar.debuggingBackground": "#AF3029", + "statusBar.debuggingForeground": "#100F0F", + "statusBar.noFolderBackground": "#CECDC3", + "statusBar.noFolderForeground": "#B7B5AC", + "titleBar.activeBackground": "#FFFCF0", + "titleBar.activeForeground": "#100F0F", + "titleBar.inactiveBackground": "#F2F0E5", + "titleBar.inactiveForeground": "#6F6E69", + "titleBar.border": "#DAD8CE", + "menu.foreground": "#100F0F", + "menu.background": "#FFFCF0", + "menu.selectionForeground": "#100F0F", + "menu.selectionBackground": "#DAD8CE", + "menu.border": "#DAD8CE", + "editorInlayHint.foreground": "#6F6E69", + "editorInlayHint.background": "#DAD8CE", + "terminal.foreground": "#100F0F", + "terminal.background": "#FFFCF0", + "terminalCursor.foreground": "#100F0F", + "terminalCursor.background": "#FFFCF0", + "terminal.ansiRed": "#AF3029", + "terminal.ansiGreen": "#66800B", + "terminal.ansiYellow": "#AD8301", + "terminal.ansiBlue": "#205EA6", + "terminal.ansiMagenta": "#24837B", + "terminal.ansiCyan": "#24837B", + "activityBar.background": "#FFFCF0", + "activityBar.foreground": "#100F0F", + "activityBar.inactiveForeground": "#6F6E69", + "activityBar.activeBorder": "#100F0F", + "activityBar.border": "#DAD8CE", + "sideBar.background": "#FFFCF0", + "sideBar.foreground": "#100F0F", + "sideBar.border": "#DAD8CE", + "sideBarTitle.foreground": "#100F0F", + "sideBarSectionHeader.background": "#F2F0E5", + "sideBarSectionHeader.foreground": "#100F0F", + "sideBarSectionHeader.border": "#DAD8CE", + "sideBar.activeBackground": "#CECDC3", + "sideBar.activeForeground": "#100F0F", + "sideBar.hoverBackground": "#DAD8CE", + "sideBar.hoverForeground": "#6F6E69", + "sideBar.folderIcon.foreground": "#66800B", + "sideBar.fileIcon.foreground": "#205EA6", + "list.warningForeground": "#BC5215", + "list.errorForeground": "#AF3029", + "list.inactiveSelectionBackground": "#DAD8CE", + "list.activeSelectionBackground": "#CECDC3", + "list.inactiveSelectionForeground": "#100F0F", + "list.activeSelectionForeground": "#100F0F", + "list.hoverForeground": "#100F0F", + "list.hoverBackground": "#DAD8CE", + "input.background": "#F2F0E5", + "input.foreground": "#100F0F", + "input.border": "#DAD8CE", + "input.placeholderForeground": "#6F6E69", + "inputOption.activeBorder": "#DAD8CE", + "inputOption.activeBackground": "#E6E4D9", + "inputOption.activeForeground": "#100F0F", + "inputValidation.infoBackground": "#24837B", + "inputValidation.infoBorder": "#3AA99F", + "inputValidation.warningBackground": "#BC5215", + "inputValidation.warningBorder": "#DA702C", + "inputValidation.errorBackground": "#AF3029", + "inputValidation.errorBorder": "#D14D41", + "dropdown.background": "#F2F0E5", + "dropdown.foreground": "#100F0F", + "dropdown.border": "#DAD8CE", + "dropdown.listBackground": "#FFFCF0", + "badge.background": "#24837B", + "activityBarBadge.background": "#24837B", + "button.background": "#24837B", + "button.foreground": "#FFFCF0", + "badge.foreground": "#FFFCF0", + "activityBarBadge.foreground": "#FFFCF0" + }, + "tokenColors": [ + { + "name": "plain", + "scope": ["source", "support.type.property-name.css"], + "settings": { + "foreground": "#100F0F" + } + }, + { + "name": "classes", + "scope": ["entity.name.type.class"], + "settings": { + "foreground": "#BC5215" + } + }, + { + "name": "interfaces", + "scope": ["entity.name.type.interface", "entity.name.type"], + "settings": { + "foreground": "#AD8301" + } + }, + { + "name": "structs", + "scope": ["entity.name.type.struct"], + "settings": { + "foreground": "#BC5215" + } + }, + { + "name": "enums", + "scope": ["entity.name.type.enum"], + "settings": { + "foreground": "#BC5215" + } + }, + { + "name": "keys", + "scope": ["meta.object-literal.key", "support.type.property-name"], + "settings": { + "foreground": "#BC5215" + } + }, + { + "name": "methods", + "scope": ["entity.name.function.method", "meta.function.method"], + "settings": { + "foreground": "#66800B" + } + }, + { + "name": "functions", + "scope": [ + "entity.name.function", + "support.function", + "meta.function-call.generic" + ], + "settings": { + "foreground": "#BC5215", + "fontStyle": "bold" + } + }, + { + "name": "variables", + "scope": ["variable", "meta.variable", "variable.other.object.property"], + "settings": { + "foreground": "#100F0F" + } + }, + { + "name": "variablesOther", + "scope": ["variable.other.object", "variable.other.readwrite.alias"], + "settings": { + "foreground": "#66800B" + } + }, + { + "name": "globalVariables", + "scope": ["variable.other.global", "variable.language.this"], + "settings": { + "foreground": "#A02F6F" + } + }, + { + "name": "localVariables", + "scope": ["variable.other.local"], + "settings": { + "foreground": "#E6E4D9" + } + }, + { + "name": "parameters", + "scope": ["variable.parameter", "meta.parameter"], + "settings": { + "foreground": "#100F0F" + } + }, + { + "name": "properties", + "scope": ["variable.other.property", "meta.property"], + "settings": { + "foreground": "#205EA6" + } + }, + { + "name": "strings", + "scope": [ + "string", + "string.other.link", + "markup.inline.raw.string.markdown" + ], + "settings": { + "foreground": "#24837B" + } + }, + { + "name": "stringEscapeSequences", + "scope": ["constant.character.escape", "constant.other.placeholder"], + "settings": { + "foreground": "#100F0F" + } + }, + { + "name": "keywords", + "scope": ["keyword"], + "settings": { + "foreground": "#66800B" + } + }, + { + "name": "keywordsControl", + "scope": [ + "keyword.control.import", + "keyword.control.from", + "keyword.import" + ], + "settings": { + "foreground": "#AF3029" + } + }, + { + "name": "storageModifiers", + "scope": ["storage.modifier", "keyword.modifier", "storage.type"], + "settings": { + "foreground": "#205EA6" + } + }, + { + "name": "comments", + "scope": ["comment", "punctuation.definition.comment"], + "settings": { + "foreground": "#6F6E69" + } + }, + { + "name": "docComments", + "scope": ["comment.documentation", "comment.line.documentation"], + "settings": { + "foreground": "#B7B5AC" + } + }, + { + "name": "numbers", + "scope": ["constant.numeric"], + "settings": { + "foreground": "#5E409D" + } + }, + { + "name": "booleans", + "scope": ["constant.language.boolean", "constant.language.json"], + "settings": { + "foreground": "#AD8301" + } + }, + { + "name": "operators", + "scope": ["keyword.operator"], + "settings": { + "foreground": "#AF3029" + } + }, + { + "name": "macros", + "scope": ["entity.name.function.preprocessor", "meta.preprocessor"], + "settings": { + "foreground": "#205EA6" + } + }, + { + "name": "preprocessor", + "scope": ["meta.preprocessor"], + "settings": { + "foreground": "#A02F6F" + } + }, + { + "name": "urls", + "scope": ["markup.underline.link"], + "settings": { + "foreground": "#205EA6" + } + }, + { + "name": "tags", + "scope": ["entity.name.tag"], + "settings": { + "foreground": "#205EA6" + } + }, + { + "name": "jsxTags", + "scope": ["support.class.component"], + "settings": { + "foreground": "#A02F6F" + } + }, + { + "name": "attributes", + "scope": ["entity.other.attribute-name", "meta.attribute"], + "settings": { + "foreground": "#AD8301" + } + }, + { + "name": "types", + "scope": ["support.type"], + "settings": { + "foreground": "#AD8301" + } + }, + { + "name": "constants", + "scope": ["variable.other.constant", "variable.readonly"], + "settings": { + "foreground": "#100F0F" + } + }, + { + "name": "labels", + "scope": ["entity.name.label", "punctuation.definition.label"], + "settings": { + "foreground": "#A02F6F" + } + }, + { + "name": "namespaces", + "scope": [ + "entity.name.namespace", + "storage.modifier.namespace", + "markup.bold.markdown" + ], + "settings": { + "foreground": "#AD8301" + } + }, + { + "name": "modules", + "scope": ["entity.name.module", "storage.modifier.module"], + "settings": { + "foreground": "#AF3029" + } + }, + { + "name": "typeParameters", + "scope": ["variable.type.parameter", "variable.parameter.type"], + "settings": { + "foreground": "#BC5215" + } + }, + { + "name": "exceptions", + "scope": ["keyword.control.exception", "keyword.control.trycatch"], + "settings": { + "foreground": "#A02F6F" + } + }, + { + "name": "decorators", + "scope": [ + "meta.decorator", + "punctuation.decorator", + "entity.name.function.decorator" + ], + "settings": { + "foreground": "#AD8301" + } + }, + { + "name": "calls", + "scope": ["variable.function"], + "settings": { + "foreground": "#100F0F" + } + }, + { + "name": "punctuation", + "scope": [ + "punctuation", + "punctuation.terminator", + "punctuation.definition.tag", + "punctuation.separator", + "punctuation.definition.string", + "punctuation.section.block" + ], + "settings": { + "foreground": "#6F6E69" + } + }, + { + "name": "yellow", + "scope": [ + "storage.type.numeric.go", + "storage.type.byte.go", + "storage.type.boolean.go", + "storage.type.string.go", + "storage.type.uintptr.go", + "storage.type.error.go", + "storage.type.rune.go", + "constant.language.go", + "support.class.dart", + "keyword.other.documentation", + "storage.modifier.import.java", + "punctuation.definition.list.begin.markdown", + "punctuation.definition.quote.begin.markdown", + "meta.separator.markdown", + "entity.name.section.markdown" + ], + "settings": { + "foreground": "#AD8301" + } + }, + { + "name": "green", + "scope": [], + "settings": { + "foreground": "#66800B" + } + }, + { + "name": "cyan", + "scope": [ + "markup.italic.markdown", + "support.type.python", + "variable.legacy.builtin.python", + "support.constant.property-value.css", + "storage.modifier.attribute.swift" + ], + "settings": { + "foreground": "#24837B" + } + }, + { + "name": "blue", + "scope": [], + "settings": { + "foreground": "#205EA6" + } + }, + { + "name": "purple", + "scope": ["keyword.channel.go", "keyword.other.platform.os.swift"], + "settings": { + "foreground": "#5E409D" + } + }, + { + "name": "magenta", + "scope": ["punctuation.definition.heading.markdown"], + "settings": { + "foreground": "#A02F6F" + } + }, + { + "name": "red", + "scope": [], + "settings": { + "foreground": "#AF3029" + } + }, + { + "name": "orange", + "scope": [], + "settings": { + "foreground": "#BC5215" + } + } + ] +} diff --git a/packages/ui/src/types/streamdown.d.ts b/packages/ui/src/types/streamdown.d.ts index 3030ac56..cc3587c5 100644 --- a/packages/ui/src/types/streamdown.d.ts +++ b/packages/ui/src/types/streamdown.d.ts @@ -6,7 +6,7 @@ declare module 'streamdown' { mode?: 'streaming' | 'static'; className?: string; - shikiTheme?: readonly [string, string] | [string, string]; + shikiTheme?: readonly [string | object, string | object]; controls?: boolean | { code?: boolean;