Initial public release
This commit is contained in:
@@ -0,0 +1,758 @@
|
||||
import type { Theme } from '@/types/theme';
|
||||
import { SEMANTIC_TYPOGRAPHY } from '@/lib/typography';
|
||||
|
||||
const hexToRgb = (value: string | undefined | null): string | null => {
|
||||
if (!value || typeof value !== 'string') {
|
||||
return null;
|
||||
}
|
||||
const normalized = value.trim();
|
||||
if (!normalized.startsWith('#')) {
|
||||
return null;
|
||||
}
|
||||
let hex = normalized.slice(1);
|
||||
if (hex.length === 3 || hex.length === 4) {
|
||||
hex = hex
|
||||
.split('')
|
||||
.map((char) => char + char)
|
||||
.join('');
|
||||
}
|
||||
if (hex.length === 8) {
|
||||
hex = hex.slice(0, 6);
|
||||
}
|
||||
if (hex.length !== 6) {
|
||||
return null;
|
||||
}
|
||||
const int = Number.parseInt(hex, 16);
|
||||
if (Number.isNaN(int)) {
|
||||
return null;
|
||||
}
|
||||
const r = (int >> 16) & 255;
|
||||
const g = (int >> 8) & 255;
|
||||
const b = int & 255;
|
||||
return `${r} ${g} ${b}`;
|
||||
};
|
||||
|
||||
export class CSSVariableGenerator {
|
||||
private inheritanceMap: Map<string, string> = new Map();
|
||||
|
||||
constructor() {
|
||||
this.initializeInheritanceMap();
|
||||
}
|
||||
|
||||
generate(theme: Theme): string {
|
||||
const cssVars: string[] = [];
|
||||
|
||||
cssVars.push(...this.generateTailwindVariables(theme));
|
||||
|
||||
cssVars.push(...this.generatePrimaryColors(theme.colors.primary));
|
||||
cssVars.push(...this.generateSurfaceColors(theme.colors.surface));
|
||||
cssVars.push(...this.generateInteractiveColors(theme.colors.interactive));
|
||||
cssVars.push(...this.generateStatusColors(theme.colors.status));
|
||||
|
||||
cssVars.push(...this.generateSyntaxColors(theme.colors.syntax));
|
||||
|
||||
cssVars.push(...this.generateComponentColors(theme.colors, theme));
|
||||
|
||||
cssVars.push(...this.generateTypographyVariables());
|
||||
|
||||
if (theme.config) {
|
||||
cssVars.push(...this.generateConfigVariables(theme.config));
|
||||
}
|
||||
|
||||
return cssVars.join('\n');
|
||||
}
|
||||
|
||||
private generateTailwindVariables(theme: Theme): string[] {
|
||||
const vars: string[] = [];
|
||||
|
||||
vars.push(` --background: ${theme.colors.surface.background} !important;`);
|
||||
vars.push(` --foreground: ${theme.colors.surface.foreground} !important;`);
|
||||
|
||||
vars.push(` --muted: ${theme.colors.surface.muted} !important;`);
|
||||
vars.push(` --muted-foreground: ${theme.colors.surface.mutedForeground} !important;`);
|
||||
|
||||
vars.push(` --card: ${theme.colors.surface.elevated} !important;`);
|
||||
vars.push(` --card-foreground: ${theme.colors.surface.elevatedForeground} !important;`);
|
||||
|
||||
vars.push(` --popover: ${theme.colors.surface.elevated} !important;`);
|
||||
vars.push(` --popover-foreground: ${theme.colors.surface.elevatedForeground} !important;`);
|
||||
|
||||
vars.push(` --border: ${theme.colors.interactive.border} !important;`);
|
||||
vars.push(` --input: ${theme.colors.interactive.border} !important;`);
|
||||
|
||||
vars.push(` --primary: ${theme.colors.primary.base} !important;`);
|
||||
vars.push(` --primary-foreground: ${theme.colors.primary.foreground} !important;`);
|
||||
|
||||
vars.push(` --secondary: ${theme.colors.surface.muted} !important;`);
|
||||
vars.push(` --secondary-foreground: ${theme.colors.surface.mutedForeground} !important;`);
|
||||
|
||||
vars.push(` --accent: ${theme.colors.surface.subtle} !important;`);
|
||||
vars.push(` --accent-foreground: ${theme.colors.surface.foreground} !important;`);
|
||||
|
||||
vars.push(` --destructive: ${theme.colors.status.error} !important;`);
|
||||
vars.push(` --destructive-foreground: ${theme.colors.status.errorForeground} !important;`);
|
||||
|
||||
vars.push(` --ring: ${theme.colors.interactive.focusRing} !important;`);
|
||||
|
||||
if (theme.config?.radius?.md) {
|
||||
vars.push(` --radius: ${theme.config.radius.md} !important;`);
|
||||
}
|
||||
|
||||
const sidebarBaseRgb = hexToRgb(theme.colors.surface.muted);
|
||||
const sidebarAccentRgb = hexToRgb(theme.colors.surface.subtle);
|
||||
const sidebarBorderRgb = hexToRgb(theme.colors.interactive.border);
|
||||
|
||||
vars.push(` --sidebar-base: ${theme.colors.surface.muted} !important;`);
|
||||
if (sidebarBaseRgb) {
|
||||
vars.push(` --sidebar-base-rgb: ${sidebarBaseRgb} !important;`);
|
||||
}
|
||||
vars.push(` --sidebar: var(--sidebar-base) !important;`);
|
||||
vars.push(` --sidebar-foreground: ${theme.colors.surface.mutedForeground} !important;`);
|
||||
vars.push(` --sidebar-primary: ${theme.colors.primary.base} !important;`);
|
||||
vars.push(` --sidebar-primary-foreground: ${theme.colors.primary.foreground} !important;`);
|
||||
vars.push(` --sidebar-accent-base: ${theme.colors.surface.subtle} !important;`);
|
||||
if (sidebarAccentRgb) {
|
||||
vars.push(` --sidebar-accent-base-rgb: ${sidebarAccentRgb} !important;`);
|
||||
}
|
||||
vars.push(` --sidebar-accent: var(--sidebar-accent-base) !important;`);
|
||||
vars.push(` --sidebar-accent-foreground: ${theme.colors.surface.foreground} !important;`);
|
||||
vars.push(` --sidebar-border: ${theme.colors.interactive.border} !important;`);
|
||||
if (sidebarBorderRgb) {
|
||||
vars.push(` --sidebar-border-rgb: ${sidebarBorderRgb} !important;`);
|
||||
}
|
||||
vars.push(` --sidebar-ring: ${theme.colors.interactive.focusRing} !important;`);
|
||||
|
||||
const isDark = theme.metadata.variant === 'dark';
|
||||
const strongAlpha = isDark ? 0.8 : 0.95;
|
||||
const softAlpha = isDark ? 0.7 : 0.9;
|
||||
|
||||
if (sidebarBaseRgb) {
|
||||
vars.push(
|
||||
` --sidebar-overlay-strong: rgb(${sidebarBaseRgb} / ${strongAlpha}) !important;`,
|
||||
);
|
||||
vars.push(
|
||||
` --sidebar-overlay-soft: rgb(${sidebarBaseRgb} / ${softAlpha}) !important;`,
|
||||
);
|
||||
} else {
|
||||
const base = theme.colors.surface.muted;
|
||||
vars.push(
|
||||
` --sidebar-overlay-strong: ${this.opacity(base, strongAlpha)} !important;`,
|
||||
);
|
||||
vars.push(
|
||||
` --sidebar-overlay-soft: ${this.opacity(base, softAlpha)} !important;`,
|
||||
);
|
||||
}
|
||||
|
||||
if (theme.colors.charts?.series && Array.isArray(theme.colors.charts.series)) {
|
||||
theme.colors.charts.series.forEach((color: string, i: number) => {
|
||||
vars.push(` --chart-${i + 1}: ${color};`);
|
||||
});
|
||||
}
|
||||
|
||||
if (theme.colors.loading) {
|
||||
vars.push(` --loading-spinner: ${theme.colors.loading.spinner || theme.colors.primary.base};`);
|
||||
vars.push(` --loading-spinner-track: ${theme.colors.loading.spinnerTrack || theme.colors.surface.muted};`);
|
||||
} else {
|
||||
vars.push(` --loading-spinner: ${theme.colors.primary.base};`);
|
||||
vars.push(` --loading-spinner-track: ${theme.colors.surface.muted};`);
|
||||
}
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
apply(theme: Theme): void {
|
||||
const cssVars = this.generate(theme);
|
||||
const style = document.createElement('style');
|
||||
style.id = 'opencode-theme-variables';
|
||||
|
||||
let styleContent = '';
|
||||
if (theme.metadata.variant === 'dark') {
|
||||
|
||||
styleContent = `:root {\n${cssVars}\n}\n\n.dark {\n${cssVars}\n}`;
|
||||
document.documentElement.classList.add('dark');
|
||||
document.documentElement.classList.remove('light');
|
||||
} else {
|
||||
|
||||
styleContent = `:root {\n${cssVars}\n}\n\n:root:not(.dark) {\n${cssVars}\n}`;
|
||||
document.documentElement.classList.remove('dark');
|
||||
document.documentElement.classList.add('light');
|
||||
}
|
||||
|
||||
style.textContent = styleContent;
|
||||
|
||||
const existing = document.getElementById('opencode-theme-variables');
|
||||
if (existing) {
|
||||
existing.remove();
|
||||
}
|
||||
|
||||
document.head.appendChild(style);
|
||||
|
||||
document.documentElement.setAttribute('data-theme', theme.metadata.variant);
|
||||
}
|
||||
|
||||
private generatePrimaryColors(primary: Theme['colors']['primary']): string[] {
|
||||
const vars: string[] = [];
|
||||
vars.push(` --primary-base: ${primary.base};`);
|
||||
vars.push(` --primary-hover: ${primary.hover || this.darken(primary.base, 10)};`);
|
||||
vars.push(` --primary-active: ${primary.active || this.darken(primary.base, 20)};`);
|
||||
vars.push(` --primary-foreground: ${primary.foreground || '#ffffff'};`);
|
||||
vars.push(` --primary-muted: ${primary.muted || this.opacity(primary.base, 0.5)};`);
|
||||
vars.push(` --primary-emphasis: ${primary.emphasis || this.lighten(primary.base, 10)};`);
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateSurfaceColors(surface: Theme['colors']['surface']): string[] {
|
||||
const vars: string[] = [];
|
||||
vars.push(` --surface-background: ${surface.background};`);
|
||||
vars.push(` --surface-foreground: ${surface.foreground};`);
|
||||
vars.push(` --surface-muted: ${surface.muted};`);
|
||||
vars.push(` --surface-muted-foreground: ${surface.mutedForeground};`);
|
||||
vars.push(` --surface-elevated: ${surface.elevated};`);
|
||||
vars.push(` --surface-elevated-foreground: ${surface.elevatedForeground};`);
|
||||
vars.push(` --surface-overlay: ${surface.overlay};`);
|
||||
vars.push(` --surface-subtle: ${surface.subtle};`);
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateInteractiveColors(interactive: Theme['colors']['interactive']): string[] {
|
||||
const vars: string[] = [];
|
||||
vars.push(` --interactive-border: ${interactive.border};`);
|
||||
vars.push(` --interactive-border-hover: ${interactive.borderHover};`);
|
||||
vars.push(` --interactive-border-focus: ${interactive.borderFocus};`);
|
||||
vars.push(` --interactive-selection: ${interactive.selection};`);
|
||||
vars.push(` --interactive-selection-foreground: ${interactive.selectionForeground};`);
|
||||
vars.push(` --interactive-focus: ${interactive.focus};`);
|
||||
vars.push(` --interactive-focus-ring: ${interactive.focusRing};`);
|
||||
vars.push(` --interactive-cursor: ${interactive.cursor};`);
|
||||
vars.push(` --interactive-hover: ${interactive.hover};`);
|
||||
vars.push(` --interactive-active: ${interactive.active};`);
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateStatusColors(status: Theme['colors']['status']): string[] {
|
||||
const vars: string[] = [];
|
||||
|
||||
vars.push(` --status-error: ${status.error};`);
|
||||
vars.push(` --status-error-foreground: ${status.errorForeground};`);
|
||||
vars.push(` --status-error-background: ${status.errorBackground};`);
|
||||
vars.push(` --status-error-border: ${status.errorBorder};`);
|
||||
|
||||
vars.push(` --status-warning: ${status.warning};`);
|
||||
vars.push(` --status-warning-foreground: ${status.warningForeground};`);
|
||||
vars.push(` --status-warning-background: ${status.warningBackground};`);
|
||||
vars.push(` --status-warning-border: ${status.warningBorder};`);
|
||||
|
||||
vars.push(` --status-success: ${status.success};`);
|
||||
vars.push(` --status-success-foreground: ${status.successForeground};`);
|
||||
vars.push(` --status-success-background: ${status.successBackground};`);
|
||||
vars.push(` --status-success-border: ${status.successBorder};`);
|
||||
|
||||
vars.push(` --status-info: ${status.info};`);
|
||||
vars.push(` --status-info-foreground: ${status.infoForeground};`);
|
||||
vars.push(` --status-info-background: ${status.infoBackground};`);
|
||||
vars.push(` --status-info-border: ${status.infoBorder};`);
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateSyntaxColors(syntax: Theme['colors']['syntax']): string[] {
|
||||
const vars: string[] = [];
|
||||
|
||||
vars.push(` --syntax-background: ${syntax.base.background};`);
|
||||
vars.push(` --syntax-foreground: ${syntax.base.foreground};`);
|
||||
vars.push(` --syntax-comment: ${syntax.base.comment};`);
|
||||
vars.push(` --syntax-keyword: ${syntax.base.keyword};`);
|
||||
vars.push(` --syntax-string: ${syntax.base.string};`);
|
||||
vars.push(` --syntax-number: ${syntax.base.number};`);
|
||||
vars.push(` --syntax-function: ${syntax.base.function};`);
|
||||
vars.push(` --syntax-variable: ${syntax.base.variable};`);
|
||||
vars.push(` --syntax-type: ${syntax.base.type};`);
|
||||
vars.push(` --syntax-operator: ${syntax.base.operator};`);
|
||||
|
||||
const tokens = this.generateSyntaxTokens(syntax);
|
||||
for (const [key, value] of Object.entries(tokens)) {
|
||||
vars.push(` --syntax-${this.kebabCase(key)}: ${value};`);
|
||||
}
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateSyntaxTokens(syntax: Theme['colors']['syntax']): Record<string, string> {
|
||||
const base = syntax.base;
|
||||
const tokens = syntax.tokens || {};
|
||||
|
||||
return {
|
||||
|
||||
commentDoc: tokens.commentDoc || this.lighten(base.comment, 10),
|
||||
|
||||
stringEscape: tokens.stringEscape || this.darken(base.string, 20),
|
||||
stringInterpolation: tokens.stringInterpolation || base.variable,
|
||||
stringRegex: tokens.stringRegex || this.adjustHue(base.string, 15),
|
||||
|
||||
keywordControl: tokens.keywordControl || base.keyword,
|
||||
keywordOperator: tokens.keywordOperator || base.operator,
|
||||
keywordImport: tokens.keywordImport || this.lighten(base.keyword, 10),
|
||||
keywordReturn: tokens.keywordReturn || this.emphasize(base.keyword),
|
||||
|
||||
functionCall: tokens.functionCall || this.lighten(base.function, 5),
|
||||
functionBuiltin: tokens.functionBuiltin || this.darken(base.function, 10),
|
||||
method: tokens.method || base.function,
|
||||
methodCall: tokens.methodCall || this.lighten(base.function, 5),
|
||||
|
||||
variableBuiltin: tokens.variableBuiltin || this.emphasize(base.variable),
|
||||
variableProperty: tokens.variableProperty || this.lighten(base.variable, 10),
|
||||
variableReadonly: tokens.variableReadonly || base.number,
|
||||
parameter: tokens.parameter || base.variable,
|
||||
|
||||
typePrimitive: tokens.typePrimitive || this.darken(base.type, 10),
|
||||
typeInterface: tokens.typeInterface || base.type,
|
||||
className: tokens.className || this.emphasize(base.type),
|
||||
enum: tokens.enum || base.type,
|
||||
|
||||
boolean: tokens.boolean || base.number,
|
||||
null: tokens.null || this.opacity(base.number, 0.7),
|
||||
constant: tokens.constant || base.number,
|
||||
|
||||
punctuation: tokens.punctuation || this.opacity(base.foreground, 0.7),
|
||||
delimiter: tokens.delimiter || this.opacity(base.foreground, 0.8),
|
||||
bracket: tokens.bracket || base.foreground,
|
||||
|
||||
tag: tokens.tag || base.keyword,
|
||||
tagAttribute: tokens.tagAttribute || base.variable,
|
||||
tagAttributeValue: tokens.tagAttributeValue || base.string,
|
||||
tagBracket: tokens.tagBracket || this.opacity(base.foreground, 0.8),
|
||||
|
||||
decorator: tokens.decorator || base.function,
|
||||
annotation: tokens.annotation || base.function,
|
||||
|
||||
namespace: tokens.namespace || this.opacity(base.type, 0.8),
|
||||
module: tokens.module || this.opacity(base.type, 0.8),
|
||||
|
||||
...tokens
|
||||
};
|
||||
}
|
||||
|
||||
private generateComponentColors(colors: Theme['colors'], theme: Theme): string[] {
|
||||
const vars: string[] = [];
|
||||
|
||||
if (colors.markdown) {
|
||||
vars.push(...this.generateMarkdownColors(colors.markdown, theme));
|
||||
} else {
|
||||
|
||||
vars.push(...this.generateDefaultMarkdownColors(theme));
|
||||
}
|
||||
|
||||
if (colors.chat) {
|
||||
vars.push(...this.generateChatColors(colors.chat, theme));
|
||||
} else {
|
||||
vars.push(...this.generateDefaultChatColors(theme));
|
||||
}
|
||||
|
||||
if (colors.tools) {
|
||||
vars.push(...this.generateToolColors(colors.tools, theme));
|
||||
} else {
|
||||
vars.push(...this.generateDefaultToolColors(theme));
|
||||
}
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateMarkdownColors(markdown: Record<string, string>, theme: Theme): string[] {
|
||||
const vars: string[] = [];
|
||||
const primary = theme.colors.primary.base;
|
||||
const chatBackground = theme.colors.chat?.background || theme.colors.surface.background;
|
||||
|
||||
vars.push(` --markdown-heading1: ${markdown.heading1 || primary};`);
|
||||
vars.push(` --markdown-heading2: ${markdown.heading2 || this.opacity(primary, 0.9)};`);
|
||||
vars.push(` --markdown-heading3: ${markdown.heading3 || this.opacity(primary, 0.8)};`);
|
||||
vars.push(` --markdown-heading4: ${markdown.heading4 || theme.colors.surface.foreground};`);
|
||||
vars.push(` --markdown-link: ${markdown.link || primary};`);
|
||||
vars.push(` --markdown-link-hover: ${markdown.linkHover || theme.colors.primary.hover || this.darken(primary, 10)};`);
|
||||
vars.push(` --markdown-inline-code: ${markdown.inlineCode || theme.colors.syntax.base.string};`);
|
||||
vars.push(` --markdown-inline-code-bg: ${markdown.inlineCodeBackground || chatBackground};`);
|
||||
vars.push(` --markdown-blockquote: ${markdown.blockquote || theme.colors.surface.mutedForeground};`);
|
||||
vars.push(` --markdown-blockquote-border: ${markdown.blockquoteBorder || theme.colors.interactive.border};`);
|
||||
vars.push(` --markdown-list-marker: ${markdown.listMarker || this.opacity(primary, 0.6)};`);
|
||||
vars.push(` --markdown-bold: ${markdown.bold || theme.colors.surface.foreground};`);
|
||||
vars.push(` --markdown-italic: ${markdown.italic || this.opacity(theme.colors.surface.foreground, 0.9)};`);
|
||||
vars.push(` --markdown-strikethrough: ${markdown.strikethrough || theme.colors.surface.mutedForeground};`);
|
||||
vars.push(` --markdown-hr: ${markdown.hr || theme.colors.interactive.border};`);
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateDefaultMarkdownColors(theme: Theme): string[] {
|
||||
const vars: string[] = [];
|
||||
const primary = theme.colors.primary.base;
|
||||
const chatBackground = theme.colors.chat?.background || theme.colors.surface.background;
|
||||
|
||||
vars.push(` --markdown-heading1: ${primary};`);
|
||||
vars.push(` --markdown-heading2: ${this.opacity(primary, 0.9)};`);
|
||||
vars.push(` --markdown-heading3: ${this.opacity(primary, 0.8)};`);
|
||||
vars.push(` --markdown-heading4: ${theme.colors.surface.foreground};`);
|
||||
vars.push(` --markdown-link: ${primary};`);
|
||||
vars.push(` --markdown-link-hover: ${theme.colors.primary.hover || this.darken(primary, 10)};`);
|
||||
vars.push(` --markdown-inline-code: ${theme.colors.syntax.base.string};`);
|
||||
vars.push(` --markdown-inline-code-bg: ${chatBackground};`);
|
||||
vars.push(` --markdown-blockquote: ${theme.colors.surface.mutedForeground};`);
|
||||
vars.push(` --markdown-blockquote-border: ${theme.colors.interactive.border};`);
|
||||
vars.push(` --markdown-list-marker: ${this.opacity(primary, 0.6)};`);
|
||||
vars.push(` --markdown-bold: ${theme.colors.surface.foreground};`);
|
||||
vars.push(` --markdown-italic: ${this.opacity(theme.colors.surface.foreground, 0.9)};`);
|
||||
vars.push(` --markdown-strikethrough: ${theme.colors.surface.mutedForeground};`);
|
||||
vars.push(` --markdown-hr: ${theme.colors.interactive.border};`);
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateChatColors(chat: Record<string, string>, theme: Theme): string[] {
|
||||
const vars: string[] = [];
|
||||
const chatBackground = chat.background || theme.colors.surface.background;
|
||||
|
||||
vars.push(` --chat-background: ${chatBackground};`);
|
||||
vars.push(` --chat-user-message: ${chat.userMessage || theme.colors.surface.foreground};`);
|
||||
vars.push(` --chat-user-message-bg: ${chat.userMessageBackground || theme.colors.surface.elevated};`);
|
||||
vars.push(` --chat-assistant-message: ${chat.assistantMessage || theme.colors.surface.foreground};`);
|
||||
vars.push(` --chat-assistant-message-bg: ${chat.assistantMessageBackground || theme.colors.surface.muted};`);
|
||||
vars.push(` --chat-timestamp: ${chat.timestamp || theme.colors.surface.mutedForeground};`);
|
||||
vars.push(` --chat-divider: ${chat.divider || theme.colors.interactive.border};`);
|
||||
vars.push(` --chat-typing: ${chat.typing || theme.colors.surface.mutedForeground};`);
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateDefaultChatColors(theme: Theme): string[] {
|
||||
const vars: string[] = [];
|
||||
|
||||
vars.push(` --chat-background: ${theme.colors.surface.background};`);
|
||||
vars.push(` --chat-user-message: ${theme.colors.surface.foreground};`);
|
||||
vars.push(` --chat-user-message-bg: ${theme.colors.surface.elevated};`);
|
||||
vars.push(` --chat-assistant-message: ${theme.colors.surface.foreground};`);
|
||||
vars.push(` --chat-assistant-message-bg: ${theme.colors.surface.muted};`);
|
||||
vars.push(` --chat-timestamp: ${theme.colors.surface.mutedForeground};`);
|
||||
vars.push(` --chat-divider: ${theme.colors.interactive.border};`);
|
||||
vars.push(` --chat-typing: ${theme.colors.surface.mutedForeground};`);
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateToolColors(tools: Theme['colors']['tools'], theme: Theme): string[] {
|
||||
const vars: string[] = [];
|
||||
|
||||
vars.push(` --tools-background: ${tools?.background || this.opacity(theme.colors.surface.muted, 0.2)};`);
|
||||
vars.push(` --tools-border: ${tools?.border || this.opacity(theme.colors.interactive.border, 0.3)};`);
|
||||
vars.push(` --tools-header-hover: ${tools?.headerHover || this.opacity(theme.colors.surface.muted, 0.3)};`);
|
||||
vars.push(` --tools-icon: ${tools?.icon || theme.colors.surface.mutedForeground};`);
|
||||
vars.push(` --tools-title: ${tools?.title || theme.colors.surface.foreground};`);
|
||||
vars.push(` --tools-description: ${tools?.description || this.opacity(theme.colors.surface.mutedForeground, 0.6)};`);
|
||||
|
||||
if (tools?.edit) {
|
||||
vars.push(` --tools-edit-added: ${tools.edit.added || theme.colors.status.success};`);
|
||||
vars.push(` --tools-edit-added-bg: ${tools.edit.addedBackground || theme.colors.status.successBackground};`);
|
||||
vars.push(` --tools-edit-removed: ${tools.edit.removed || theme.colors.status.error};`);
|
||||
vars.push(` --tools-edit-removed-bg: ${tools.edit.removedBackground || theme.colors.status.errorBackground};`);
|
||||
vars.push(` --tools-edit-modified: ${tools.edit.modified || theme.colors.status.info};`);
|
||||
vars.push(` --tools-edit-modified-bg: ${tools.edit.modifiedBackground || theme.colors.status.infoBackground};`);
|
||||
vars.push(` --tools-edit-line-number: ${tools.edit.lineNumber || this.opacity(theme.colors.surface.mutedForeground, 0.6)};`);
|
||||
} else {
|
||||
vars.push(` --tools-edit-added: ${theme.colors.status.success};`);
|
||||
vars.push(` --tools-edit-added-bg: ${theme.colors.status.successBackground};`);
|
||||
vars.push(` --tools-edit-removed: ${theme.colors.status.error};`);
|
||||
vars.push(` --tools-edit-removed-bg: ${theme.colors.status.errorBackground};`);
|
||||
vars.push(` --tools-edit-modified: ${theme.colors.status.info};`);
|
||||
vars.push(` --tools-edit-modified-bg: ${theme.colors.status.infoBackground};`);
|
||||
vars.push(` --tools-edit-line-number: ${this.opacity(theme.colors.surface.mutedForeground, 0.6)};`);
|
||||
}
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateDefaultToolColors(theme: Theme): string[] {
|
||||
const vars: string[] = [];
|
||||
|
||||
vars.push(` --tools-background: ${this.opacity(theme.colors.surface.muted, 0.2)};`);
|
||||
vars.push(` --tools-border: ${this.opacity(theme.colors.interactive.border, 0.3)};`);
|
||||
vars.push(` --tools-header-hover: ${this.opacity(theme.colors.surface.muted, 0.3)};`);
|
||||
vars.push(` --tools-icon: ${theme.colors.surface.mutedForeground};`);
|
||||
vars.push(` --tools-title: ${theme.colors.surface.foreground};`);
|
||||
vars.push(` --tools-description: ${this.opacity(theme.colors.surface.mutedForeground, 0.6)};`);
|
||||
|
||||
vars.push(` --tools-edit-added: ${theme.colors.status.success};`);
|
||||
vars.push(` --tools-edit-added-bg: ${this.addTransparency(this.removeTransparency(theme.colors.status.successBackground), 0.15)};`);
|
||||
vars.push(` --tools-edit-removed: ${theme.colors.status.error};`);
|
||||
vars.push(` --tools-edit-removed-bg: ${this.addTransparency(this.removeTransparency(theme.colors.status.errorBackground), 0.15)};`);
|
||||
vars.push(` --tools-edit-modified: ${theme.colors.status.info};`);
|
||||
vars.push(` --tools-edit-modified-bg: ${this.addTransparency(this.removeTransparency(theme.colors.status.infoBackground), 0.15)};`);
|
||||
vars.push(` --tools-edit-line-number: ${this.opacity(theme.colors.surface.mutedForeground, 0.6)};`);
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateConfigVariables(config: Theme['config']): string[] {
|
||||
const vars: string[] = [];
|
||||
|
||||
if (!config) return vars;
|
||||
|
||||
if (config.fonts) {
|
||||
if (config.fonts.sans) {
|
||||
vars.push(` --font-sans: ${config.fonts.sans};`);
|
||||
vars.push(` --font-family-sans: ${config.fonts.sans};`);
|
||||
}
|
||||
if (config.fonts.mono) {
|
||||
vars.push(` --font-mono: ${config.fonts.mono};`);
|
||||
vars.push(` --font-family-mono: ${config.fonts.mono};`);
|
||||
}
|
||||
if (config.fonts.heading) vars.push(` --font-heading: ${config.fonts.heading};`);
|
||||
}
|
||||
|
||||
if (config.radius) {
|
||||
if (config.radius.none) vars.push(` --radius-none: ${config.radius.none};`);
|
||||
if (config.radius.sm) vars.push(` --radius-sm: ${config.radius.sm};`);
|
||||
if (config.radius.md) vars.push(` --radius-md: ${config.radius.md};`);
|
||||
if (config.radius.lg) vars.push(` --radius-lg: ${config.radius.lg};`);
|
||||
if (config.radius.xl) vars.push(` --radius-xl: ${config.radius.xl};`);
|
||||
if (config.radius.full) vars.push(` --radius-full: ${config.radius.full};`);
|
||||
}
|
||||
|
||||
if (config.transitions) {
|
||||
if (config.transitions.fast) vars.push(` --transition-fast: ${config.transitions.fast};`);
|
||||
if (config.transitions.normal) vars.push(` --transition-normal: ${config.transitions.normal};`);
|
||||
if (config.transitions.slow) vars.push(` --transition-slow: ${config.transitions.slow};`);
|
||||
}
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
private generateTypographyVariables(): string[] {
|
||||
const vars: string[] = [];
|
||||
|
||||
vars.push(' /* Semantic Typography Variables */');
|
||||
vars.push(' --ui-regular-font-weight: 400;');
|
||||
|
||||
vars.push(' /* Markdown content - all markdown elements use same size */');
|
||||
vars.push(` --text-markdown: ${SEMANTIC_TYPOGRAPHY.markdown};`);
|
||||
vars.push(' /* Code content - all code elements use same size */');
|
||||
vars.push(` --text-code: ${SEMANTIC_TYPOGRAPHY.code};`);
|
||||
vars.push(' /* UI headers - dialog titles, panel headers */');
|
||||
vars.push(` --text-ui-header: ${SEMANTIC_TYPOGRAPHY.uiHeader};`);
|
||||
vars.push(' /* UI labels - buttons, menus, navigation */');
|
||||
vars.push(` --text-ui-label: ${SEMANTIC_TYPOGRAPHY.uiLabel};`);
|
||||
vars.push(' /* Metadata - timestamps, status, helper text */');
|
||||
vars.push(` --text-meta: ${SEMANTIC_TYPOGRAPHY.meta};`);
|
||||
vars.push(' /* Micro text - badges, shortcuts, indicators */');
|
||||
vars.push(` --text-micro: ${SEMANTIC_TYPOGRAPHY.micro};`);
|
||||
|
||||
vars.push(' /* Heading line height and letter spacing */');
|
||||
vars.push(' --h1-line-height: 1.25rem;');
|
||||
vars.push(' --h2-line-height: 1.25rem;');
|
||||
vars.push(' --h3-line-height: 1.5rem;');
|
||||
vars.push(' --h4-line-height: 1.5rem;');
|
||||
vars.push(' --h5-line-height: 1.5rem;');
|
||||
vars.push(' --h6-line-height: 1.5rem;');
|
||||
vars.push(' --h1-letter-spacing: -0.025em;');
|
||||
vars.push(' --h2-letter-spacing: -0.02em;');
|
||||
vars.push(' --h3-letter-spacing: -0.015em;');
|
||||
vars.push(' --h4-letter-spacing: -0.01em;');
|
||||
vars.push(' --h5-letter-spacing: 0;');
|
||||
vars.push(' --h6-letter-spacing: 0.01em;');
|
||||
|
||||
vars.push(' /* UI element line height and letter spacing */');
|
||||
vars.push(' --ui-button-line-height: 1.375rem;');
|
||||
vars.push(' --ui-button-letter-spacing: 0.02em;');
|
||||
vars.push(' --ui-button-font-weight: 500;');
|
||||
vars.push(' --ui-label-line-height: 1rem;');
|
||||
vars.push(' --ui-label-letter-spacing: 0.03em;');
|
||||
vars.push(' --ui-label-font-weight: 500;');
|
||||
vars.push(' --ui-caption-line-height: 1rem;');
|
||||
vars.push(' --ui-caption-letter-spacing: 0.025em;');
|
||||
vars.push(' --ui-caption-font-weight: var(--ui-regular-font-weight, 400);');
|
||||
|
||||
vars.push(' /* Markdown line height and letter spacing */');
|
||||
vars.push(' --markdown-body-line-height: 1.5rem;');
|
||||
vars.push(' --markdown-body-letter-spacing: 0;');
|
||||
vars.push(' --markdown-body-font-weight: var(--ui-regular-font-weight, 400);');
|
||||
vars.push(' --markdown-h1-line-height: 1.25rem;');
|
||||
vars.push(' --markdown-h1-letter-spacing: -0.025em;');
|
||||
vars.push(' --markdown-h2-line-height: 1.25rem;');
|
||||
vars.push(' --markdown-h2-letter-spacing: -0.02em;');
|
||||
vars.push(' --markdown-h3-line-height: 1.5rem;');
|
||||
vars.push(' --markdown-h3-letter-spacing: -0.015em;');
|
||||
vars.push(' --markdown-h4-line-height: 1.5rem;');
|
||||
vars.push(' --markdown-h4-letter-spacing: -0.01em;');
|
||||
vars.push(' --markdown-h5-line-height: 1.5rem;');
|
||||
vars.push(' --markdown-h5-letter-spacing: 0;');
|
||||
vars.push(' --markdown-h6-line-height: 1.5rem;');
|
||||
vars.push(' --markdown-h6-letter-spacing: 0.01em;');
|
||||
vars.push(' --markdown-list-line-height: 1.375rem;');
|
||||
vars.push(' --markdown-code-block-line-height: 1rem;');
|
||||
|
||||
vars.push(' --ui-button-small-line-height: 1.25rem;');
|
||||
vars.push(' --ui-button-small-letter-spacing: 0.02em;');
|
||||
vars.push(' --ui-button-small-font-weight: 500;');
|
||||
vars.push(' --markdown-body-small-line-height: 1.375rem;');
|
||||
vars.push(' --markdown-body-small-letter-spacing: 0;');
|
||||
vars.push(' --markdown-body-small-font-weight: var(--ui-regular-font-weight, 400);');
|
||||
|
||||
vars.push(' --ui-button-large-line-height: 1.5rem;');
|
||||
vars.push(' --ui-button-large-letter-spacing: 0.02em;');
|
||||
vars.push(' --ui-button-large-font-weight: 500;');
|
||||
vars.push(' --markdown-body-large-line-height: 1.625rem;');
|
||||
vars.push(' --markdown-body-large-letter-spacing: 0;');
|
||||
vars.push(' --markdown-body-large-font-weight: var(--ui-regular-font-weight, 400);');
|
||||
|
||||
vars.push(' /* Code line height and letter spacing */');
|
||||
vars.push(' --code-inline-line-height: 1rem;');
|
||||
vars.push(' --code-inline-letter-spacing: 0;');
|
||||
vars.push(' --code-inline-font-weight: 400;');
|
||||
vars.push(' --code-block-line-height: 1.4rem;');
|
||||
vars.push(' --code-block-letter-spacing: 0;');
|
||||
vars.push(' --code-block-font-weight: 400;');
|
||||
vars.push(' --code-line-numbers-line-height: 1.25rem;');
|
||||
vars.push(' --code-line-numbers-letter-spacing: 0;');
|
||||
vars.push(' --code-line-numbers-font-weight: 400;');
|
||||
|
||||
vars.push(' /* Additional UI element line height and letter spacing */');
|
||||
vars.push(' --ui-badge-line-height: 1rem;');
|
||||
vars.push(' --ui-badge-letter-spacing: 0.025em;');
|
||||
vars.push(' --ui-badge-font-weight: 500;');
|
||||
vars.push(' --ui-tooltip-line-height: 1rem;');
|
||||
vars.push(' --ui-tooltip-letter-spacing: 0.025em;');
|
||||
vars.push(' --ui-tooltip-font-weight: var(--ui-regular-font-weight, 400);');
|
||||
vars.push(' --ui-input-line-height: 1.375rem;');
|
||||
vars.push(' --ui-input-letter-spacing: 0.02em;');
|
||||
vars.push(' --ui-input-font-weight: var(--ui-regular-font-weight, 400);');
|
||||
vars.push(' --ui-helper-text-line-height: 1rem;');
|
||||
vars.push(' --ui-helper-text-letter-spacing: 0.025em;');
|
||||
vars.push(' --ui-helper-text-font-weight: var(--ui-regular-font-weight, 400);');
|
||||
|
||||
vars.push(' /* Additional markdown line height and letter spacing */');
|
||||
vars.push(' --markdown-blockquote-line-height: 1.5rem;');
|
||||
vars.push(' --markdown-blockquote-letter-spacing: 0;');
|
||||
vars.push(' --markdown-blockquote-font-weight: var(--ui-regular-font-weight, 400);');
|
||||
vars.push(' --markdown-list-letter-spacing: 0;');
|
||||
vars.push(' --markdown-list-font-weight: var(--ui-regular-font-weight, 400);');
|
||||
vars.push(' --markdown-link-line-height: 1.5rem;');
|
||||
vars.push(' --markdown-link-letter-spacing: 0;');
|
||||
vars.push(' --markdown-link-font-weight: var(--ui-regular-font-weight, 400);');
|
||||
vars.push(' --markdown-code-line-height: 1.35;');
|
||||
vars.push(' --markdown-code-letter-spacing: 0;');
|
||||
vars.push(' --markdown-code-font-weight: 400;');
|
||||
vars.push(' --markdown-code-block-letter-spacing: 0;');
|
||||
vars.push(' --markdown-code-block-font-weight: 400;');
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
private initializeInheritanceMap(): void {
|
||||
|
||||
this.inheritanceMap.set('header.background', 'surface.background');
|
||||
this.inheritanceMap.set('header.foreground', 'surface.foreground');
|
||||
this.inheritanceMap.set('header.logoTint', 'primary.base');
|
||||
this.inheritanceMap.set('header.divider', 'interactive.border');
|
||||
|
||||
this.inheritanceMap.set('sidebar.background', 'surface.muted');
|
||||
this.inheritanceMap.set('sidebar.foreground', 'surface.mutedForeground');
|
||||
this.inheritanceMap.set('sidebar.hover', 'interactive.hover');
|
||||
this.inheritanceMap.set('sidebar.active', 'primary.base');
|
||||
this.inheritanceMap.set('sidebar.activeForeground', 'primary.foreground');
|
||||
|
||||
}
|
||||
|
||||
private opacity(color: string, alpha: number): string {
|
||||
if (color.startsWith('#')) {
|
||||
return `${color}${Math.round(alpha * 255).toString(16).padStart(2, '0')}`;
|
||||
}
|
||||
if (color.startsWith('rgb')) {
|
||||
return color.replace('rgb', 'rgba').replace(')', `, ${alpha})`);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
private removeTransparency(color: string): string {
|
||||
if (color.startsWith('#')) {
|
||||
|
||||
if (color.length === 9) {
|
||||
return color.slice(0, 7);
|
||||
}
|
||||
|
||||
if (color.length === 5) {
|
||||
return color.slice(0, 4);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
if (color.startsWith('rgba')) {
|
||||
|
||||
return color.replace('rgba', 'rgb').replace(/,\s*[\d.]+\)$/, ')');
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
private addTransparency(color: string, opacity: number): string {
|
||||
if (color.startsWith('#')) {
|
||||
|
||||
const hex = color.slice(1);
|
||||
if (hex.length === 3) {
|
||||
|
||||
const r = parseInt(hex[0] + hex[0], 16);
|
||||
const g = parseInt(hex[1] + hex[1], 16);
|
||||
const b = parseInt(hex[2] + hex[2], 16);
|
||||
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
||||
} else if (hex.length === 6) {
|
||||
|
||||
const r = parseInt(hex.slice(0, 2), 16);
|
||||
const g = parseInt(hex.slice(2, 4), 16);
|
||||
const b = parseInt(hex.slice(4, 6), 16);
|
||||
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
||||
}
|
||||
}
|
||||
if (color.startsWith('rgb')) {
|
||||
|
||||
return color.replace('rgb', 'rgba').replace(')', `, ${opacity})`);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
private darken(color: string, percent: number): string {
|
||||
|
||||
if (color.startsWith('#')) {
|
||||
const num = parseInt(color.slice(1), 16);
|
||||
const amt = Math.round(2.55 * percent);
|
||||
const R = (num >> 16) - amt;
|
||||
const G = (num >> 8 & 0x00FF) - amt;
|
||||
const B = (num & 0x0000FF) - amt;
|
||||
return '#' + (0x1000000 + (R < 255 ? R < 0 ? 0 : R : 255) * 0x10000 +
|
||||
(G < 255 ? G < 0 ? 0 : G : 255) * 0x100 +
|
||||
(B < 255 ? B < 0 ? 0 : B : 255)).toString(16).slice(1);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
private lighten(color: string, percent: number): string {
|
||||
|
||||
if (color.startsWith('#')) {
|
||||
const num = parseInt(color.slice(1), 16);
|
||||
const amt = Math.round(2.55 * percent);
|
||||
const R = (num >> 16) + amt;
|
||||
const G = (num >> 8 & 0x00FF) + amt;
|
||||
const B = (num & 0x0000FF) + amt;
|
||||
return '#' + (0x1000000 + (R < 255 ? R < 0 ? 0 : R : 255) * 0x10000 +
|
||||
(G < 255 ? G < 0 ? 0 : G : 255) * 0x100 +
|
||||
(B < 255 ? B < 0 ? 0 : B : 255)).toString(16).slice(1);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
private adjustHue(color: string, degrees: number): string {
|
||||
|
||||
return this.lighten(color, degrees / 10);
|
||||
}
|
||||
|
||||
private emphasize(color: string): string {
|
||||
|
||||
return this.lighten(color, 15);
|
||||
}
|
||||
|
||||
private kebabCase(str: string): string {
|
||||
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,445 @@
|
||||
import type { Theme } from '@/types/theme';
|
||||
|
||||
interface MonacoTokenRule {
|
||||
token: string;
|
||||
foreground?: string;
|
||||
fontStyle?: string;
|
||||
}
|
||||
|
||||
interface MonacoThemeData {
|
||||
base: 'vs' | 'vs-dark';
|
||||
inherit: boolean;
|
||||
rules: MonacoTokenRule[];
|
||||
colors: Record<string, string>;
|
||||
}
|
||||
|
||||
type Monaco = {
|
||||
editor: {
|
||||
defineTheme: (themeName: string, themeData: MonacoThemeData) => void;
|
||||
};
|
||||
};
|
||||
|
||||
const MONACO_LIGHT_THEME_ID = 'openchamber-flexoki-light';
|
||||
const MONACO_DARK_THEME_ID = 'openchamber-flexoki-dark';
|
||||
|
||||
let lastRegisteredThemeId: string | null = null;
|
||||
|
||||
const getMonacoFromGlobal = (): Monaco | null => {
|
||||
if (typeof window === 'undefined') return null;
|
||||
const anyWindow = window as typeof window & { monaco?: Monaco };
|
||||
if (anyWindow.monaco?.editor?.defineTheme) return anyWindow.monaco;
|
||||
return null;
|
||||
};
|
||||
|
||||
const flexokiDarkTheme: MonacoThemeData = {
|
||||
base: 'vs-dark',
|
||||
inherit: true,
|
||||
rules: [
|
||||
|
||||
{ token: '', foreground: 'CECDC3' },
|
||||
{ token: 'source', foreground: 'CECDC3' },
|
||||
|
||||
{ token: 'comment', foreground: '878580' },
|
||||
{ token: 'comment.block', foreground: '878580' },
|
||||
{ token: 'comment.line', foreground: '878580' },
|
||||
{ token: 'comment.block.documentation', foreground: '575653' },
|
||||
|
||||
{ token: 'string', foreground: '3AA99F' },
|
||||
{ token: 'string.quoted', foreground: '3AA99F' },
|
||||
{ token: 'string.template', foreground: '3AA99F' },
|
||||
{ token: 'string.regexp', foreground: '3AA99F' },
|
||||
|
||||
{ token: 'string.escape', foreground: 'CECDC3' },
|
||||
{ token: 'constant.character.escape', foreground: 'CECDC3' },
|
||||
|
||||
{ token: 'number', foreground: '8B7EC8' },
|
||||
{ token: 'number.hex', foreground: '8B7EC8' },
|
||||
{ token: 'number.float', foreground: '8B7EC8' },
|
||||
{ token: 'constant.numeric', foreground: '8B7EC8' },
|
||||
|
||||
{ token: 'constant.language', foreground: 'D0A215' },
|
||||
{ token: 'constant.language.boolean', foreground: 'D0A215' },
|
||||
{ token: 'constant.language.null', foreground: 'D0A215' },
|
||||
|
||||
{ token: 'keyword', foreground: '4385BE' },
|
||||
{ token: 'keyword.control', foreground: '4385BE' },
|
||||
{ token: 'keyword.other', foreground: '4385BE' },
|
||||
|
||||
{ token: 'keyword.control.import', foreground: 'D14D41' },
|
||||
{ token: 'keyword.control.from', foreground: 'D14D41' },
|
||||
{ token: 'keyword.control.export', foreground: 'D14D41' },
|
||||
|
||||
{ token: 'keyword.control.exception', foreground: 'CE5D97' },
|
||||
{ token: 'keyword.control.trycatch', foreground: 'CE5D97' },
|
||||
|
||||
{ token: 'keyword.operator', foreground: 'D14D41' },
|
||||
{ token: 'operator', foreground: 'D14D41' },
|
||||
|
||||
{ token: 'storage', foreground: '4385BE' },
|
||||
{ token: 'storage.type', foreground: '4385BE' },
|
||||
{ token: 'storage.modifier', foreground: '4385BE' },
|
||||
|
||||
{ token: 'entity.name.function', foreground: 'DA702C', fontStyle: 'bold' },
|
||||
{ token: 'support.function', foreground: 'DA702C', fontStyle: 'bold' },
|
||||
{ token: 'meta.function-call', foreground: 'DA702C' },
|
||||
|
||||
{ token: 'entity.name.function.method', foreground: '879A39' },
|
||||
|
||||
{ token: 'entity.name.class', foreground: 'DA702C' },
|
||||
{ token: 'entity.name.type.class', foreground: 'DA702C' },
|
||||
{ token: 'support.class', foreground: 'DA702C' },
|
||||
|
||||
{ token: 'entity.name.type', foreground: 'D0A215' },
|
||||
{ token: 'entity.name.type.interface', foreground: 'D0A215' },
|
||||
{ token: 'support.type', foreground: 'D0A215' },
|
||||
|
||||
{ token: 'entity.name.type.struct', foreground: 'DA702C' },
|
||||
{ token: 'entity.name.type.enum', foreground: 'DA702C' },
|
||||
|
||||
{ token: 'entity.name.type.parameter', foreground: 'DA702C' },
|
||||
|
||||
{ token: 'variable', foreground: 'CECDC3' },
|
||||
{ token: 'variable.other', foreground: 'CECDC3' },
|
||||
{ token: 'variable.parameter', foreground: 'CECDC3' },
|
||||
|
||||
{ token: 'variable.other.object', foreground: '879A39' },
|
||||
{ token: 'variable.other.readwrite.alias', foreground: '879A39' },
|
||||
|
||||
{ token: 'variable.language', foreground: 'CE5D97' },
|
||||
{ token: 'variable.language.this', foreground: 'CE5D97' },
|
||||
{ token: 'variable.language.super', foreground: 'CE5D97' },
|
||||
|
||||
{ token: 'variable.other.property', foreground: '4385BE' },
|
||||
{ token: 'support.variable.property', foreground: '4385BE' },
|
||||
|
||||
{ token: 'variable.other.constant', foreground: 'CECDC3' },
|
||||
|
||||
{ token: 'meta.object-literal.key', foreground: 'DA702C' },
|
||||
{ token: 'support.type.property-name', foreground: 'DA702C' },
|
||||
|
||||
{ token: 'entity.name.tag', foreground: '4385BE' },
|
||||
{ token: 'tag', foreground: '4385BE' },
|
||||
|
||||
{ token: 'support.class.component', foreground: 'CE5D97' },
|
||||
|
||||
{ token: 'entity.other.attribute-name', foreground: 'D0A215' },
|
||||
|
||||
{ token: 'entity.name.namespace', foreground: 'D0A215' },
|
||||
|
||||
{ token: 'entity.name.module', foreground: 'D14D41' },
|
||||
|
||||
{ token: 'meta.decorator', foreground: 'D0A215' },
|
||||
{ token: 'entity.name.function.decorator', foreground: 'D0A215' },
|
||||
|
||||
{ token: 'entity.name.label', foreground: 'CE5D97' },
|
||||
|
||||
{ token: 'meta.preprocessor', foreground: 'CE5D97' },
|
||||
{ token: 'entity.name.function.preprocessor', foreground: '4385BE' },
|
||||
|
||||
{ token: 'punctuation', foreground: '878580' },
|
||||
{ token: 'delimiter', foreground: '878580' },
|
||||
{ token: 'delimiter.bracket', foreground: '878580' },
|
||||
|
||||
{ token: 'markup.heading', foreground: 'D0A215' },
|
||||
{ token: 'markup.bold', foreground: 'D0A215', fontStyle: 'bold' },
|
||||
{ token: 'markup.italic', foreground: '3AA99F', fontStyle: 'italic' },
|
||||
{ token: 'markup.underline.link', foreground: '4385BE' },
|
||||
{ token: 'markup.inline.raw', foreground: '3AA99F' },
|
||||
|
||||
{ token: 'invalid', foreground: 'D14D41' },
|
||||
{ token: 'invalid.illegal', foreground: 'D14D41' },
|
||||
|
||||
{ token: 'string.key.json', foreground: 'DA702C' },
|
||||
{ token: 'string.value.json', foreground: '3AA99F' },
|
||||
|
||||
{ token: 'support.type.property-name.css', foreground: 'CECDC3' },
|
||||
{ token: 'support.constant.property-value.css', foreground: '3AA99F' },
|
||||
|
||||
{ token: 'type', foreground: 'D0A215' },
|
||||
{ token: 'type.identifier', foreground: 'D0A215' },
|
||||
{ token: 'identifier', foreground: 'CECDC3' },
|
||||
],
|
||||
colors: {
|
||||
|
||||
'editor.background': '#100F0F',
|
||||
'editor.foreground': '#CECDC3',
|
||||
'editor.lineHighlightBackground': '#1C1B1A',
|
||||
'editor.selectionBackground': '#CECDC333',
|
||||
'editor.selectionHighlightBackground': '#CECDC333',
|
||||
'editor.inactiveSelectionBackground': '#282726',
|
||||
'editor.findMatchBackground': '#AD8301',
|
||||
'editor.findMatchHighlightBackground': '#AD8301cc',
|
||||
'editor.hoverHighlightBackground': '#343331',
|
||||
'editor.rangeHighlightBackground': '#403E3C',
|
||||
'editorCursor.foreground': '#CECDC3',
|
||||
|
||||
'editorLineNumber.foreground': '#403E3C',
|
||||
'editorLineNumber.activeForeground': '#CECDC3',
|
||||
|
||||
'editorGutter.background': '#100F0F',
|
||||
'editorGutter.modifiedBackground': '#3AA99F',
|
||||
'editorGutter.addedBackground': '#879A39',
|
||||
'editorGutter.deletedBackground': '#D14D41',
|
||||
|
||||
'diffEditor.insertedTextBackground': '#66800B25',
|
||||
'diffEditor.removedTextBackground': '#AF302925',
|
||||
'diffEditor.insertedLineBackground': '#66800B15',
|
||||
'diffEditor.removedLineBackground': '#AF302915',
|
||||
'diffEditor.insertedTextBorder': '#00000000',
|
||||
'diffEditor.removedTextBorder': '#00000000',
|
||||
|
||||
'editorBracketMatch.background': '#282726',
|
||||
'editorBracketMatch.border': '#343331',
|
||||
|
||||
'editorWhitespace.foreground': '#403E3C',
|
||||
'editorIndentGuide.background1': '#343331',
|
||||
'editorIndentGuide.activeBackground1': '#575653',
|
||||
|
||||
'editorWidget.background': '#1C1B1A',
|
||||
'editorWidget.border': '#343331',
|
||||
'editorSuggestWidget.background': '#100F0F',
|
||||
'editorSuggestWidget.border': '#343331',
|
||||
'editorSuggestWidget.foreground': '#CECDC3',
|
||||
'editorSuggestWidget.selectedBackground': '#343331',
|
||||
'editorHoverWidget.background': '#282726',
|
||||
'editorHoverWidget.border': '#343331',
|
||||
|
||||
'editorInlayHint.foreground': '#878580',
|
||||
'editorInlayHint.background': '#343331',
|
||||
|
||||
'editorError.foreground': '#D14D41',
|
||||
'editorWarning.foreground': '#DA702C',
|
||||
'editorInfo.foreground': '#4385BE',
|
||||
|
||||
'input.background': '#1C1B1A',
|
||||
'input.foreground': '#CECDC3',
|
||||
'input.border': '#343331',
|
||||
'input.placeholderForeground': '#878580',
|
||||
|
||||
'dropdown.background': '#1C1B1A',
|
||||
'dropdown.foreground': '#CECDC3',
|
||||
'dropdown.border': '#343331',
|
||||
'dropdown.listBackground': '#100F0F',
|
||||
|
||||
'focusBorder': '#343331',
|
||||
|
||||
'scrollbarSlider.background': '#34333180',
|
||||
'scrollbarSlider.hoverBackground': '#403E3C',
|
||||
'scrollbarSlider.activeBackground': '#575653',
|
||||
},
|
||||
};
|
||||
|
||||
const flexokiLightTheme: MonacoThemeData = {
|
||||
base: 'vs',
|
||||
inherit: true,
|
||||
rules: [
|
||||
|
||||
{ token: '', foreground: '100F0F' },
|
||||
{ token: 'source', foreground: '100F0F' },
|
||||
|
||||
{ token: 'comment', foreground: '6F6E69' },
|
||||
{ token: 'comment.block', foreground: '6F6E69' },
|
||||
{ token: 'comment.line', foreground: '6F6E69' },
|
||||
{ token: 'comment.block.documentation', foreground: 'B7B5AC' },
|
||||
|
||||
{ token: 'string', foreground: '24837B' },
|
||||
{ token: 'string.quoted', foreground: '24837B' },
|
||||
{ token: 'string.template', foreground: '24837B' },
|
||||
{ token: 'string.regexp', foreground: '24837B' },
|
||||
|
||||
{ token: 'string.escape', foreground: '100F0F' },
|
||||
{ token: 'constant.character.escape', foreground: '100F0F' },
|
||||
|
||||
{ token: 'number', foreground: '5E409D' },
|
||||
{ token: 'number.hex', foreground: '5E409D' },
|
||||
{ token: 'number.float', foreground: '5E409D' },
|
||||
{ token: 'constant.numeric', foreground: '5E409D' },
|
||||
|
||||
{ token: 'constant.language', foreground: 'AD8301' },
|
||||
{ token: 'constant.language.boolean', foreground: 'AD8301' },
|
||||
{ token: 'constant.language.null', foreground: 'AD8301' },
|
||||
|
||||
{ token: 'keyword', foreground: '205EA6' },
|
||||
{ token: 'keyword.control', foreground: '205EA6' },
|
||||
{ token: 'keyword.other', foreground: '205EA6' },
|
||||
|
||||
{ token: 'keyword.control.import', foreground: 'AF3029' },
|
||||
{ token: 'keyword.control.from', foreground: 'AF3029' },
|
||||
{ token: 'keyword.control.export', foreground: 'AF3029' },
|
||||
|
||||
{ token: 'keyword.control.exception', foreground: 'A02F6F' },
|
||||
{ token: 'keyword.control.trycatch', foreground: 'A02F6F' },
|
||||
|
||||
{ token: 'keyword.operator', foreground: 'AF3029' },
|
||||
{ token: 'operator', foreground: 'AF3029' },
|
||||
|
||||
{ token: 'storage', foreground: '205EA6' },
|
||||
{ token: 'storage.type', foreground: '205EA6' },
|
||||
{ token: 'storage.modifier', foreground: '205EA6' },
|
||||
|
||||
{ token: 'entity.name.function', foreground: 'BC5215', fontStyle: 'bold' },
|
||||
{ token: 'support.function', foreground: 'BC5215', fontStyle: 'bold' },
|
||||
{ token: 'meta.function-call', foreground: 'BC5215' },
|
||||
|
||||
{ token: 'entity.name.function.method', foreground: '66800B' },
|
||||
|
||||
{ token: 'entity.name.class', foreground: 'BC5215' },
|
||||
{ token: 'entity.name.type.class', foreground: 'BC5215' },
|
||||
{ token: 'support.class', foreground: 'BC5215' },
|
||||
|
||||
{ token: 'entity.name.type', foreground: 'AD8301' },
|
||||
{ token: 'entity.name.type.interface', foreground: 'AD8301' },
|
||||
{ token: 'support.type', foreground: 'AD8301' },
|
||||
|
||||
{ token: 'entity.name.type.struct', foreground: 'BC5215' },
|
||||
{ token: 'entity.name.type.enum', foreground: 'BC5215' },
|
||||
|
||||
{ token: 'entity.name.type.parameter', foreground: 'BC5215' },
|
||||
|
||||
{ token: 'variable', foreground: '100F0F' },
|
||||
{ token: 'variable.other', foreground: '100F0F' },
|
||||
{ token: 'variable.parameter', foreground: '100F0F' },
|
||||
|
||||
{ token: 'variable.other.object', foreground: '66800B' },
|
||||
{ token: 'variable.other.readwrite.alias', foreground: '66800B' },
|
||||
|
||||
{ token: 'variable.language', foreground: 'A02F6F' },
|
||||
{ token: 'variable.language.this', foreground: 'A02F6F' },
|
||||
{ token: 'variable.language.super', foreground: 'A02F6F' },
|
||||
|
||||
{ token: 'variable.other.property', foreground: '205EA6' },
|
||||
{ token: 'support.variable.property', foreground: '205EA6' },
|
||||
|
||||
{ token: 'variable.other.constant', foreground: '100F0F' },
|
||||
|
||||
{ token: 'meta.object-literal.key', foreground: 'BC5215' },
|
||||
{ token: 'support.type.property-name', foreground: 'BC5215' },
|
||||
|
||||
{ token: 'entity.name.tag', foreground: '205EA6' },
|
||||
{ token: 'tag', foreground: '205EA6' },
|
||||
|
||||
{ token: 'support.class.component', foreground: 'A02F6F' },
|
||||
|
||||
{ token: 'entity.other.attribute-name', foreground: 'AD8301' },
|
||||
|
||||
{ token: 'entity.name.namespace', foreground: 'AD8301' },
|
||||
|
||||
{ token: 'entity.name.module', foreground: 'AF3029' },
|
||||
|
||||
{ token: 'meta.decorator', foreground: 'AD8301' },
|
||||
{ token: 'entity.name.function.decorator', foreground: 'AD8301' },
|
||||
|
||||
{ token: 'entity.name.label', foreground: 'A02F6F' },
|
||||
|
||||
{ token: 'meta.preprocessor', foreground: 'A02F6F' },
|
||||
{ token: 'entity.name.function.preprocessor', foreground: '205EA6' },
|
||||
|
||||
{ token: 'punctuation', foreground: '6F6E69' },
|
||||
{ token: 'delimiter', foreground: '6F6E69' },
|
||||
{ token: 'delimiter.bracket', foreground: '6F6E69' },
|
||||
|
||||
{ token: 'markup.heading', foreground: 'AD8301' },
|
||||
{ token: 'markup.bold', foreground: 'AD8301', fontStyle: 'bold' },
|
||||
{ token: 'markup.italic', foreground: '24837B', fontStyle: 'italic' },
|
||||
{ token: 'markup.underline.link', foreground: '205EA6' },
|
||||
{ token: 'markup.inline.raw', foreground: '24837B' },
|
||||
|
||||
{ token: 'invalid', foreground: 'AF3029' },
|
||||
{ token: 'invalid.illegal', foreground: 'AF3029' },
|
||||
|
||||
{ token: 'string.key.json', foreground: 'BC5215' },
|
||||
{ token: 'string.value.json', foreground: '24837B' },
|
||||
|
||||
{ token: 'support.type.property-name.css', foreground: '100F0F' },
|
||||
{ token: 'support.constant.property-value.css', foreground: '24837B' },
|
||||
|
||||
{ token: 'type', foreground: 'AD8301' },
|
||||
{ token: 'type.identifier', foreground: 'AD8301' },
|
||||
{ token: 'identifier', foreground: '100F0F' },
|
||||
],
|
||||
colors: {
|
||||
|
||||
'editor.background': '#FFFCF0',
|
||||
'editor.foreground': '#100F0F',
|
||||
'editor.lineHighlightBackground': '#F2F0E5',
|
||||
'editor.selectionBackground': '#100F0F44',
|
||||
'editor.selectionHighlightBackground': '#100F0F44',
|
||||
'editor.inactiveSelectionBackground': '#E6E4D9',
|
||||
'editor.findMatchBackground': '#D0A215',
|
||||
'editor.findMatchHighlightBackground': '#D0A215cc',
|
||||
'editor.hoverHighlightBackground': '#DAD8CE',
|
||||
'editor.rangeHighlightBackground': '#CECDC3',
|
||||
'editorCursor.foreground': '#100F0F',
|
||||
|
||||
'editorLineNumber.foreground': '#CECDC3',
|
||||
'editorLineNumber.activeForeground': '#100F0F',
|
||||
|
||||
'editorGutter.background': '#FFFCF0',
|
||||
'editorGutter.modifiedBackground': '#24837B',
|
||||
'editorGutter.addedBackground': '#66800B',
|
||||
'editorGutter.deletedBackground': '#AF3029',
|
||||
|
||||
'diffEditor.insertedTextBackground': '#66800B25',
|
||||
'diffEditor.removedTextBackground': '#AF302925',
|
||||
'diffEditor.insertedLineBackground': '#66800B15',
|
||||
'diffEditor.removedLineBackground': '#AF302915',
|
||||
'diffEditor.insertedTextBorder': '#00000000',
|
||||
'diffEditor.removedTextBorder': '#00000000',
|
||||
|
||||
'editorBracketMatch.background': '#E6E4D9',
|
||||
'editorBracketMatch.border': '#DAD8CE',
|
||||
|
||||
'editorWhitespace.foreground': '#CECDC3',
|
||||
'editorIndentGuide.background1': '#DAD8CE',
|
||||
'editorIndentGuide.activeBackground1': '#B7B5AC',
|
||||
|
||||
'editorWidget.background': '#F2F0E5',
|
||||
'editorWidget.border': '#DAD8CE',
|
||||
'editorSuggestWidget.background': '#FFFCF0',
|
||||
'editorSuggestWidget.border': '#DAD8CE',
|
||||
'editorSuggestWidget.foreground': '#100F0F',
|
||||
'editorSuggestWidget.selectedBackground': '#DAD8CE',
|
||||
'editorHoverWidget.background': '#E6E4D9',
|
||||
'editorHoverWidget.border': '#DAD8CE',
|
||||
|
||||
'editorInlayHint.foreground': '#6F6E69',
|
||||
'editorInlayHint.background': '#DAD8CE',
|
||||
|
||||
'editorError.foreground': '#AF3029',
|
||||
'editorWarning.foreground': '#BC5215',
|
||||
'editorInfo.foreground': '#205EA6',
|
||||
|
||||
'input.background': '#F2F0E5',
|
||||
'input.foreground': '#100F0F',
|
||||
'input.border': '#DAD8CE',
|
||||
'input.placeholderForeground': '#6F6E69',
|
||||
|
||||
'dropdown.background': '#F2F0E5',
|
||||
'dropdown.foreground': '#100F0F',
|
||||
'dropdown.border': '#DAD8CE',
|
||||
'dropdown.listBackground': '#FFFCF0',
|
||||
|
||||
'focusBorder': '#DAD8CE',
|
||||
|
||||
'scrollbarSlider.background': '#DAD8CE80',
|
||||
'scrollbarSlider.hoverBackground': '#CECDC3',
|
||||
'scrollbarSlider.activeBackground': '#B7B5AC',
|
||||
},
|
||||
};
|
||||
|
||||
export const getMonacoThemeIdForTheme = (theme: Theme): string => {
|
||||
return theme.metadata.variant === 'dark' ? MONACO_DARK_THEME_ID : MONACO_LIGHT_THEME_ID;
|
||||
};
|
||||
|
||||
export const ensureMonacoThemeRegistered = (theme: Theme, monacoOverride?: Monaco): void => {
|
||||
const monaco = monacoOverride ?? getMonacoFromGlobal();
|
||||
if (!monaco) return;
|
||||
|
||||
const themeId = getMonacoThemeIdForTheme(theme);
|
||||
if (lastRegisteredThemeId === themeId) return;
|
||||
|
||||
const themeData = theme.metadata.variant === 'dark' ? flexokiDarkTheme : flexokiLightTheme;
|
||||
monaco.editor.defineTheme(themeId, themeData);
|
||||
|
||||
lastRegisteredThemeId = themeId;
|
||||
};
|
||||
@@ -0,0 +1,208 @@
|
||||
import type { Theme } from '@/types/theme';
|
||||
|
||||
export function generateSyntaxTheme(theme: Theme) {
|
||||
const syntax = theme.colors.syntax;
|
||||
const surface = theme.colors.surface;
|
||||
|
||||
return {
|
||||
'code[class*="language-"]': {
|
||||
color: syntax.base.foreground,
|
||||
background: 'transparent',
|
||||
fontFamily: 'Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace',
|
||||
fontSize: '1em',
|
||||
textAlign: 'left' as const,
|
||||
whiteSpace: 'pre',
|
||||
wordSpacing: 'normal',
|
||||
wordBreak: 'normal' as const,
|
||||
wordWrap: 'normal' as const,
|
||||
lineHeight: '1.5',
|
||||
MozTabSize: '4',
|
||||
OTabSize: '4',
|
||||
tabSize: '4',
|
||||
WebkitHyphens: 'none' as const,
|
||||
MozHyphens: 'none' as const,
|
||||
msHyphens: 'none' as const,
|
||||
hyphens: 'none' as const,
|
||||
},
|
||||
'pre[class*="language-"]': {
|
||||
color: syntax.base.foreground,
|
||||
background: 'transparent',
|
||||
fontFamily: 'Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace',
|
||||
fontSize: '1em',
|
||||
textAlign: 'left' as const,
|
||||
whiteSpace: 'pre',
|
||||
wordSpacing: 'normal',
|
||||
wordBreak: 'normal' as const,
|
||||
wordWrap: 'normal' as const,
|
||||
lineHeight: '1.5',
|
||||
MozTabSize: '4',
|
||||
OTabSize: '4',
|
||||
tabSize: '4',
|
||||
WebkitHyphens: 'none' as const,
|
||||
MozHyphens: 'none' as const,
|
||||
msHyphens: 'none' as const,
|
||||
hyphens: 'none' as const,
|
||||
padding: '0',
|
||||
margin: '0',
|
||||
overflow: 'auto',
|
||||
},
|
||||
|
||||
comment: {
|
||||
color: syntax.base.comment,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
prolog: {
|
||||
color: syntax.base.comment,
|
||||
},
|
||||
doctype: {
|
||||
color: syntax.base.comment,
|
||||
},
|
||||
cdata: {
|
||||
color: syntax.base.comment,
|
||||
},
|
||||
|
||||
punctuation: {
|
||||
color: syntax.tokens?.punctuation || surface.mutedForeground,
|
||||
},
|
||||
|
||||
property: {
|
||||
color: syntax.tokens?.variableProperty || syntax.base.variable,
|
||||
},
|
||||
tag: {
|
||||
color: syntax.tokens?.tag || syntax.base.keyword,
|
||||
},
|
||||
'attr-name': {
|
||||
color: syntax.tokens?.tagAttribute || syntax.base.variable,
|
||||
},
|
||||
'attr-value': {
|
||||
color: syntax.tokens?.tagAttributeValue || syntax.base.string,
|
||||
},
|
||||
|
||||
boolean: {
|
||||
color: syntax.tokens?.boolean || syntax.base.number,
|
||||
},
|
||||
number: {
|
||||
color: syntax.base.number,
|
||||
},
|
||||
constant: {
|
||||
color: syntax.tokens?.constant || syntax.base.number,
|
||||
},
|
||||
symbol: {
|
||||
color: syntax.tokens?.constant || syntax.base.number,
|
||||
},
|
||||
|
||||
string: {
|
||||
color: syntax.base.string,
|
||||
},
|
||||
char: {
|
||||
color: syntax.base.string,
|
||||
},
|
||||
|
||||
function: {
|
||||
color: syntax.base.function,
|
||||
},
|
||||
builtin: {
|
||||
color: syntax.tokens?.functionBuiltin || syntax.base.function,
|
||||
},
|
||||
|
||||
'class-name': {
|
||||
color: syntax.tokens?.className || syntax.base.type,
|
||||
},
|
||||
namespace: {
|
||||
color: syntax.tokens?.namespace || syntax.base.type,
|
||||
opacity: 0.8,
|
||||
},
|
||||
|
||||
keyword: {
|
||||
color: syntax.base.keyword,
|
||||
},
|
||||
atrule: {
|
||||
color: syntax.base.keyword,
|
||||
},
|
||||
selector: {
|
||||
color: syntax.base.function,
|
||||
},
|
||||
|
||||
operator: {
|
||||
color: syntax.base.operator,
|
||||
},
|
||||
|
||||
variable: {
|
||||
color: syntax.base.variable,
|
||||
},
|
||||
|
||||
regex: {
|
||||
color: syntax.tokens?.regex || syntax.base.string,
|
||||
},
|
||||
|
||||
url: {
|
||||
color: syntax.base.function,
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
entity: {
|
||||
color: syntax.base.function,
|
||||
cursor: 'help',
|
||||
},
|
||||
|
||||
'.language-css .token.string': {
|
||||
color: syntax.base.string,
|
||||
},
|
||||
'.style .token.string': {
|
||||
color: syntax.base.string,
|
||||
},
|
||||
|
||||
deleted: {
|
||||
color: theme.colors.status.error,
|
||||
backgroundColor: theme.colors.status.errorBackground,
|
||||
},
|
||||
inserted: {
|
||||
color: theme.colors.status.success,
|
||||
backgroundColor: theme.colors.status.successBackground,
|
||||
},
|
||||
|
||||
title: {
|
||||
color: theme.colors.primary.base,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'code-block': {
|
||||
color: syntax.base.string,
|
||||
},
|
||||
'code-snippet': {
|
||||
color: syntax.base.string,
|
||||
},
|
||||
list: {
|
||||
color: syntax.base.variable,
|
||||
},
|
||||
hr: {
|
||||
color: surface.mutedForeground,
|
||||
},
|
||||
table: {
|
||||
color: syntax.base.function,
|
||||
},
|
||||
blockquote: {
|
||||
color: surface.mutedForeground,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
|
||||
important: {
|
||||
color: syntax.base.keyword,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
bold: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
italic: {
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
strike: {
|
||||
textDecoration: 'line-through',
|
||||
},
|
||||
|
||||
decorator: {
|
||||
color: syntax.tokens?.decorator || syntax.base.function,
|
||||
},
|
||||
annotation: {
|
||||
color: syntax.tokens?.decorator || syntax.base.function,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
import type { Theme } from '@/types/theme';
|
||||
|
||||
export const flexokiDarkTheme: Theme = {
|
||||
metadata: {
|
||||
id: 'flexoki-dark',
|
||||
name: 'Flexoki Dark',
|
||||
description: 'An inky color scheme for prose and code - dark variant',
|
||||
author: 'Steph Ango',
|
||||
version: '1.0.0',
|
||||
variant: 'dark',
|
||||
tags: ['dark', 'warm', 'natural', 'ink']
|
||||
},
|
||||
|
||||
colors: {
|
||||
|
||||
primary: {
|
||||
base: '#EC8B49',
|
||||
hover: '#DA702C',
|
||||
active: '#F9AE77',
|
||||
foreground: '#100F0F',
|
||||
muted: '#EC8B4980',
|
||||
emphasis: '#F9AE77'
|
||||
},
|
||||
|
||||
surface: {
|
||||
background: '#100F0F',
|
||||
foreground: '#CECDC3',
|
||||
muted: '#1C1B1A',
|
||||
mutedForeground: '#878580',
|
||||
elevated: '#282726',
|
||||
elevatedForeground: '#CECDC3',
|
||||
overlay: '#00000080',
|
||||
subtle: '#343331'
|
||||
},
|
||||
|
||||
interactive: {
|
||||
border: '#343331',
|
||||
borderHover: '#403E3C',
|
||||
borderFocus: '#EC8B49',
|
||||
selection: '#CECDC330',
|
||||
selectionForeground: '#CECDC3',
|
||||
focus: '#EC8B49',
|
||||
focusRing: '#EC8B4950',
|
||||
cursor: '#CECDC3',
|
||||
hover: '#343331',
|
||||
active: '#403E3C'
|
||||
},
|
||||
|
||||
status: {
|
||||
error: '#D14D41',
|
||||
errorForeground: '#100F0F',
|
||||
errorBackground: '#AF302920',
|
||||
errorBorder: '#AF302950',
|
||||
|
||||
warning: '#DA702C',
|
||||
warningForeground: '#100F0F',
|
||||
warningBackground: '#BC521520',
|
||||
warningBorder: '#BC521550',
|
||||
|
||||
success: '#A0AF54',
|
||||
successForeground: '#100F0F',
|
||||
successBackground: '#66800B20',
|
||||
successBorder: '#66800B50',
|
||||
|
||||
info: '#4385BE',
|
||||
infoForeground: '#100F0F',
|
||||
infoBackground: '#205EA620',
|
||||
infoBorder: '#205EA650'
|
||||
},
|
||||
|
||||
syntax: {
|
||||
base: {
|
||||
background: '#1C1B1A',
|
||||
foreground: '#CECDC3',
|
||||
comment: '#878580',
|
||||
keyword: '#4385BE',
|
||||
string: '#3AA99F',
|
||||
number: '#8B7EC8',
|
||||
function: '#DA702C',
|
||||
variable: '#CECDC3',
|
||||
type: '#D0A215',
|
||||
operator: '#D14D41'
|
||||
},
|
||||
|
||||
tokens: {
|
||||
commentDoc: '#575653',
|
||||
stringEscape: '#CECDC3',
|
||||
keywordImport: '#D14D41',
|
||||
storageModifier: '#4385BE',
|
||||
functionCall: '#DA702C',
|
||||
method: '#879A39',
|
||||
variableProperty: '#4385BE',
|
||||
variableOther: '#879A39',
|
||||
variableGlobal: '#CE5D97',
|
||||
variableLocal: '#282726',
|
||||
parameter: '#CECDC3',
|
||||
constant: '#CECDC3',
|
||||
class: '#DA702C',
|
||||
className: '#DA702C',
|
||||
interface: '#D0A215',
|
||||
struct: '#DA702C',
|
||||
enum: '#DA702C',
|
||||
typeParameter: '#DA702C',
|
||||
namespace: '#D0A215',
|
||||
module: '#D14D41',
|
||||
tag: '#4385BE',
|
||||
jsxTag: '#CE5D97',
|
||||
tagAttribute: '#D0A215',
|
||||
tagAttributeValue: '#3AA99F',
|
||||
boolean: '#D0A215',
|
||||
decorator: '#D0A215',
|
||||
label: '#CE5D97',
|
||||
punctuation: '#878580',
|
||||
macro: '#4385BE',
|
||||
preprocessor: '#CE5D97',
|
||||
regex: '#3AA99F',
|
||||
url: '#4385BE',
|
||||
key: '#DA702C',
|
||||
exception: '#CE5D97'
|
||||
},
|
||||
|
||||
highlights: {
|
||||
diffAdded: '#879A39',
|
||||
diffAddedBackground: '#66800B20',
|
||||
diffRemoved: '#D14D41',
|
||||
diffRemovedBackground: '#AF302920',
|
||||
diffModified: '#4385BE',
|
||||
diffModifiedBackground: '#205EA620',
|
||||
lineNumber: '#403E3C',
|
||||
lineNumberActive: '#CECDC3'
|
||||
}
|
||||
},
|
||||
|
||||
markdown: {
|
||||
heading1: '#D0A215',
|
||||
heading2: '#DA702C',
|
||||
heading3: '#4385BE',
|
||||
heading4: '#CECDC3',
|
||||
link: '#4385BE',
|
||||
linkHover: '#205EA6',
|
||||
inlineCode: '#A0AF54',
|
||||
inlineCodeBackground: '#1C1B1A',
|
||||
blockquote: '#878580',
|
||||
blockquoteBorder: '#343331',
|
||||
listMarker: '#D0A21599'
|
||||
},
|
||||
|
||||
chat: {
|
||||
userMessage: '#CECDC3',
|
||||
userMessageBackground: '#282726',
|
||||
assistantMessage: '#CECDC3',
|
||||
assistantMessageBackground: '#100F0F',
|
||||
timestamp: '#878580',
|
||||
divider: '#343331'
|
||||
},
|
||||
|
||||
tools: {
|
||||
background: '#1C1B1A50',
|
||||
border: '#34333180',
|
||||
headerHover: '#34333150',
|
||||
icon: '#878580',
|
||||
title: '#CECDC3',
|
||||
description: '#878580',
|
||||
|
||||
edit: {
|
||||
added: '#879A39',
|
||||
addedBackground: '#66800B25',
|
||||
removed: '#D14D41',
|
||||
removedBackground: '#AF302925',
|
||||
lineNumber: '#403E3C'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
config: {
|
||||
fonts: {
|
||||
sans: '"IBM Plex Mono", monospace',
|
||||
mono: '"IBM Plex Mono", monospace',
|
||||
heading: '"IBM Plex Mono", monospace'
|
||||
},
|
||||
|
||||
radius: {
|
||||
none: '0',
|
||||
sm: '0.125rem',
|
||||
md: '0.375rem',
|
||||
lg: '0.5rem',
|
||||
xl: '0.75rem',
|
||||
full: '9999px'
|
||||
},
|
||||
|
||||
transitions: {
|
||||
fast: '150ms ease',
|
||||
normal: '250ms ease',
|
||||
slow: '350ms ease'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,197 @@
|
||||
import type { Theme } from '@/types/theme';
|
||||
|
||||
export const flexokiLightTheme: Theme = {
|
||||
metadata: {
|
||||
id: 'flexoki-light',
|
||||
name: 'Flexoki Light',
|
||||
description: 'An inky color scheme for prose and code - light variant',
|
||||
author: 'Steph Ango',
|
||||
version: '1.0.0',
|
||||
variant: 'light',
|
||||
tags: ['light', 'warm', 'natural', 'paper']
|
||||
},
|
||||
|
||||
colors: {
|
||||
|
||||
primary: {
|
||||
base: '#EC8B49',
|
||||
hover: '#F9AE77',
|
||||
active: '#DA702C',
|
||||
foreground: '#FFFCF0',
|
||||
muted: '#EC8B4980',
|
||||
emphasis: '#F9AE77'
|
||||
},
|
||||
|
||||
surface: {
|
||||
background: '#FFFCF0',
|
||||
foreground: '#100F0F',
|
||||
muted: '#F2F0E5',
|
||||
mutedForeground: '#6F6E69',
|
||||
elevated: '#E6E4D9',
|
||||
elevatedForeground: '#100F0F',
|
||||
overlay: '#100F0F20',
|
||||
subtle: '#DAD8CE'
|
||||
},
|
||||
|
||||
interactive: {
|
||||
border: '#DAD8CE',
|
||||
borderHover: '#CECDC3',
|
||||
borderFocus: '#EC8B49',
|
||||
selection: '#100F0F44',
|
||||
selectionForeground: '#100F0F',
|
||||
focus: '#EC8B49',
|
||||
focusRing: '#EC8B4940',
|
||||
cursor: '#100F0F',
|
||||
hover: '#DAD8CE',
|
||||
active: '#CECDC3'
|
||||
},
|
||||
|
||||
status: {
|
||||
error: '#AF3029',
|
||||
errorForeground: '#FFFCF0',
|
||||
errorBackground: '#D14D4120',
|
||||
errorBorder: '#D14D4150',
|
||||
|
||||
warning: '#BC5215',
|
||||
warningForeground: '#FFFCF0',
|
||||
warningBackground: '#DA702C20',
|
||||
warningBorder: '#DA702C50',
|
||||
|
||||
success: '#66800B',
|
||||
successForeground: '#FFFCF0',
|
||||
successBackground: '#879A3920',
|
||||
successBorder: '#879A3950',
|
||||
|
||||
info: '#205EA6',
|
||||
infoForeground: '#FFFCF0',
|
||||
infoBackground: '#4385BE20',
|
||||
infoBorder: '#4385BE50'
|
||||
},
|
||||
|
||||
syntax: {
|
||||
base: {
|
||||
background: '#F2F0E5',
|
||||
foreground: '#100F0F',
|
||||
comment: '#6F6E69',
|
||||
keyword: '#205EA6',
|
||||
string: '#24837B',
|
||||
number: '#5E409D',
|
||||
function: '#BC5215',
|
||||
variable: '#100F0F',
|
||||
type: '#AD8301',
|
||||
operator: '#AF3029'
|
||||
},
|
||||
|
||||
tokens: {
|
||||
commentDoc: '#B7B5AC',
|
||||
stringEscape: '#100F0F',
|
||||
keywordImport: '#AF3029',
|
||||
storageModifier: '#205EA6',
|
||||
functionCall: '#BC5215',
|
||||
method: '#66800B',
|
||||
variableProperty: '#205EA6',
|
||||
variableOther: '#66800B',
|
||||
variableGlobal: '#A02F6F',
|
||||
variableLocal: '#E6E4D9',
|
||||
parameter: '#100F0F',
|
||||
constant: '#100F0F',
|
||||
class: '#BC5215',
|
||||
className: '#BC5215',
|
||||
interface: '#AD8301',
|
||||
struct: '#BC5215',
|
||||
enum: '#BC5215',
|
||||
typeParameter: '#BC5215',
|
||||
namespace: '#AD8301',
|
||||
module: '#AF3029',
|
||||
tag: '#205EA6',
|
||||
jsxTag: '#A02F6F',
|
||||
tagAttribute: '#AD8301',
|
||||
tagAttributeValue: '#24837B',
|
||||
boolean: '#AD8301',
|
||||
decorator: '#AD8301',
|
||||
label: '#A02F6F',
|
||||
punctuation: '#6F6E69',
|
||||
macro: '#205EA6',
|
||||
preprocessor: '#A02F6F',
|
||||
regex: '#24837B',
|
||||
url: '#205EA6',
|
||||
key: '#BC5215',
|
||||
exception: '#A02F6F'
|
||||
},
|
||||
|
||||
highlights: {
|
||||
diffAdded: '#66800B',
|
||||
diffAddedBackground: '#879A3920',
|
||||
diffRemoved: '#AF3029',
|
||||
diffRemovedBackground: '#D14D4120',
|
||||
diffModified: '#205EA6',
|
||||
diffModifiedBackground: '#4385BE20',
|
||||
lineNumber: '#CECDC3',
|
||||
lineNumberActive: '#100F0F'
|
||||
}
|
||||
},
|
||||
|
||||
markdown: {
|
||||
heading1: '#AD8301',
|
||||
heading2: '#BC5215',
|
||||
heading3: '#205EA6',
|
||||
heading4: '#100F0F',
|
||||
link: '#205EA6',
|
||||
linkHover: '#4385BE',
|
||||
inlineCode: '#24837B',
|
||||
inlineCodeBackground: '#F2F0E5',
|
||||
blockquote: '#6F6E69',
|
||||
blockquoteBorder: '#DAD8CE',
|
||||
listMarker: '#AD830199'
|
||||
},
|
||||
|
||||
chat: {
|
||||
userMessage: '#100F0F',
|
||||
userMessageBackground: '#F2F0E5',
|
||||
assistantMessage: '#100F0F',
|
||||
assistantMessageBackground: '#FFFCF0',
|
||||
timestamp: '#6F6E69',
|
||||
divider: '#DAD8CE'
|
||||
},
|
||||
|
||||
tools: {
|
||||
background: '#F2F0E550',
|
||||
border: '#DAD8CE80',
|
||||
headerHover: '#DAD8CE',
|
||||
icon: '#6F6E69',
|
||||
title: '#100F0F',
|
||||
description: '#6F6E69',
|
||||
|
||||
edit: {
|
||||
added: '#66800B',
|
||||
addedBackground: '#66800B25',
|
||||
removed: '#AF3029',
|
||||
removedBackground: '#AF302925',
|
||||
lineNumber: '#CECDC3'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
config: {
|
||||
fonts: {
|
||||
sans: '"IBM Plex Mono", monospace',
|
||||
mono: '"IBM Plex Mono", monospace',
|
||||
heading: '"IBM Plex Mono", monospace'
|
||||
},
|
||||
|
||||
radius: {
|
||||
none: '0',
|
||||
sm: '0.125rem',
|
||||
md: '0.375rem',
|
||||
lg: '0.5rem',
|
||||
xl: '0.75rem',
|
||||
full: '9999px'
|
||||
},
|
||||
|
||||
transitions: {
|
||||
fast: '150ms ease',
|
||||
normal: '250ms ease',
|
||||
slow: '350ms ease'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { Theme } from '@/types/theme';
|
||||
import { flexokiLightTheme } from './flexoki-light';
|
||||
import { flexokiDarkTheme } from './flexoki-dark';
|
||||
|
||||
export const themes: Theme[] = [
|
||||
flexokiLightTheme,
|
||||
flexokiDarkTheme,
|
||||
];
|
||||
|
||||
export {
|
||||
flexokiLightTheme,
|
||||
flexokiDarkTheme,
|
||||
};
|
||||
|
||||
export function getThemeById(id: string): Theme | undefined {
|
||||
return themes.find(theme => theme.metadata.id === id);
|
||||
}
|
||||
|
||||
export function getDefaultTheme(prefersDark: boolean): Theme {
|
||||
return prefersDark ? flexokiDarkTheme : flexokiLightTheme;
|
||||
}
|
||||
Reference in New Issue
Block a user