theme awareness

This commit is contained in:
2025-11-14 13:42:18 +01:00
parent 8941ee13bc
commit 5a388e7f14
37 changed files with 444 additions and 109 deletions

View File

@ -603,7 +603,7 @@
margin-top: var(--space-lg);
padding: var(--space-md) var(--space-2xl);
background-color: var(--accent-color);
color: white;
color: var(--accent-text);
border: none;
font-size: var(--font-lg);
font-weight: 600;

View File

@ -46,10 +46,15 @@
node.getByteTimeDomainData(dataArray);
canvasContext.fillStyle = '#0a0a0a';
const computedStyle = getComputedStyle(document.documentElement);
const bgColor = computedStyle.getPropertyValue('--editor-background').trim();
const borderColor = computedStyle.getPropertyValue('--border-color').trim();
const accentColor = computedStyle.getPropertyValue('--accent-color').trim();
canvasContext.fillStyle = bgColor;
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
canvasContext.strokeStyle = '#333';
canvasContext.strokeStyle = borderColor;
canvasContext.lineWidth = 1;
canvasContext.beginPath();
canvasContext.moveTo(0, canvas.height / 2);
@ -57,7 +62,7 @@
canvasContext.stroke();
canvasContext.lineWidth = 2;
canvasContext.strokeStyle = '#646cff';
canvasContext.strokeStyle = accentColor;
canvasContext.beginPath();
const sliceWidth = canvas.width / dataArray.length;
@ -94,7 +99,9 @@
if (canvas) {
canvasContext = canvas.getContext('2d');
if (canvasContext) {
canvasContext.fillStyle = '#0a0a0a';
const computedStyle = getComputedStyle(document.documentElement);
const bgColor = computedStyle.getPropertyValue('--editor-background').trim();
canvasContext.fillStyle = bgColor;
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
}
}
@ -132,7 +139,7 @@
display: flex;
align-items: center;
justify-content: center;
background-color: #0a0a0a;
background-color: var(--editor-background);
overflow: hidden;
}
@ -140,6 +147,6 @@
display: block;
width: 100%;
height: 100%;
background-color: #0a0a0a;
background-color: var(--editor-background);
}
</style>

View File

@ -46,6 +46,10 @@
node.getByteFrequencyData(dataArray);
const computedStyle = getComputedStyle(document.documentElement);
const bgColor = computedStyle.getPropertyValue('--editor-background').trim();
const accentColor = computedStyle.getPropertyValue('--accent-color').trim();
const imageData = canvasContext.getImageData(1, 0, canvas.width - 1, canvas.height);
canvasContext.putImageData(imageData, 0, 0);
@ -58,11 +62,7 @@
const y = canvas.height - (i / dataArray.length) * canvas.height;
const height = (canvas.height / dataArray.length);
const hue = (1 - percent) * 240;
const saturation = 100;
const lightness = percent * 50;
canvasContext.fillStyle = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
canvasContext.fillStyle = interpolateColor(bgColor, accentColor, percent);
canvasContext.fillRect(x, y - height, barWidth, height);
}
};
@ -70,6 +70,39 @@
draw();
}
function interpolateColor(color1: string, color2: string, percent: number): string {
const c1 = parseColor(color1);
const c2 = parseColor(color2);
const r = Math.round(c1.r + (c2.r - c1.r) * percent);
const g = Math.round(c1.g + (c2.g - c1.g) * percent);
const b = Math.round(c1.b + (c2.b - c1.b) * percent);
return `rgb(${r}, ${g}, ${b})`;
}
function parseColor(color: string): { r: number; g: number; b: number } {
if (color.startsWith('#')) {
const hex = color.slice(1);
return {
r: parseInt(hex.slice(0, 2), 16),
g: parseInt(hex.slice(2, 4), 16),
b: parseInt(hex.slice(4, 6), 16)
};
}
const match = color.match(/\d+/g);
if (match && match.length >= 3) {
return {
r: parseInt(match[0]),
g: parseInt(match[1]),
b: parseInt(match[2])
};
}
return { r: 0, g: 0, b: 0 };
}
function updateSize() {
if (container && canvas) {
const rect = container.getBoundingClientRect();
@ -82,7 +115,9 @@
if (canvas) {
canvasContext = canvas.getContext('2d');
if (canvasContext) {
canvasContext.fillStyle = '#000';
const computedStyle = getComputedStyle(document.documentElement);
const bgColor = computedStyle.getPropertyValue('--editor-background').trim();
canvasContext.fillStyle = bgColor;
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
}
}
@ -120,7 +155,7 @@
display: flex;
align-items: center;
justify-content: center;
background-color: #0a0a0a;
background-color: var(--editor-background);
overflow: hidden;
}
@ -128,6 +163,6 @@
display: block;
width: 100%;
height: 100%;
background-color: #0a0a0a;
background-color: var(--editor-background);
}
</style>

View File

@ -20,6 +20,7 @@
} from '../../editor/block-eval';
import { csoundTooltip, csoundTooltipTheme } from '../../csound-reference/csoundTooltips';
import { createCodeMirrorTheme } from '../../editor/codemirror-theme';
import { themes } from '../../themes';
interface Props {
value: string;
@ -148,13 +149,14 @@
];
const initSettings = $editorSettings;
const currentTheme = themes[initSettings.theme];
editorView = new EditorView({
doc: value,
extensions: [
...baseExtensions,
languageCompartment.of(csoundMode({ fileType })),
themeCompartment.of(createCodeMirrorTheme()),
themeCompartment.of(createCodeMirrorTheme(currentTheme)),
evaluateBlockKeymap,
evaluateSelectionKeymap,
evaluateFileKeymap,
@ -197,16 +199,12 @@
});
$effect(() => {
const theme = $editorSettings.theme;
if (!editorView) return;
const themeName = $editorSettings.theme;
const theme = themes[themeName];
if (!editorView || !theme) return;
// Wait for CSS variables to be recomputed after theme change
requestAnimationFrame(() => {
if (editorView) {
editorView.dispatch({
effects: themeCompartment.reconfigure(createCodeMirrorTheme())
});
}
editorView.dispatch({
effects: themeCompartment.reconfigure(createCodeMirrorTheme(theme))
});
});

View File

@ -276,23 +276,25 @@
}
.action-button.pause-active {
color: rgba(255, 200, 100, 0.9);
background-color: rgba(255, 200, 100, 0.15);
color: var(--warning-text);
background-color: var(--warning-color);
opacity: 0.9;
}
.action-button.pause-active:hover {
color: rgba(255, 200, 100, 1);
background-color: rgba(255, 200, 100, 0.25);
background-color: var(--warning-hover);
opacity: 1;
}
.action-button.search-active {
color: rgba(100, 200, 255, 0.9);
background-color: rgba(100, 200, 255, 0.15);
color: var(--info-text);
background-color: var(--info-color);
opacity: 0.9;
}
.action-button.search-active:hover {
color: rgba(100, 200, 255, 1);
background-color: rgba(100, 200, 255, 0.25);
background-color: var(--info-hover);
opacity: 1;
}
.log-content {
@ -322,12 +324,14 @@
}
.log-entry.error {
background-color: rgba(255, 0, 0, 0.1);
border-left: 3px solid rgba(255, 0, 0, 0.6);
background-color: var(--danger-color);
opacity: 0.2;
border-left: 3px solid var(--danger-color);
}
.log-entry.error .log-message {
color: rgba(255, 100, 100, 0.95);
color: var(--danger-color);
opacity: 1;
}
.log-timestamp {

View File

@ -241,7 +241,7 @@
gap: var(--space-sm);
width: 100%;
padding: var(--space-md) var(--space-lg);
background-color: var(--accordion-header-bg);
background-color: var(--surface-color);
border: none;
color: var(--text-color);
cursor: pointer;
@ -250,7 +250,7 @@
}
.category-header:hover {
background-color: var(--accordion-header-hover);
background-color: var(--surface-hover);
}
.category-header :global(svg) {
@ -267,7 +267,7 @@
.category-count {
font-size: var(--font-xs);
color: var(--text-color);
background-color: var(--accent-color-subtle);
background-color: var(--surface-hover);
padding: 2px var(--space-sm);
border-radius: var(--radius-sm);
}

View File

@ -71,7 +71,7 @@
.version-toggle-button.active {
color: var(--accent-color);
background-color: rgba(100, 200, 255, 0.15);
background-color: var(--surface-hover);
border-color: var(--accent-color);
}
</style>

View File

@ -69,11 +69,11 @@
.button-primary {
background-color: var(--accent-color);
color: white;
color: var(--accent-text);
}
.button-primary:hover {
background-color: var(--accent-color-active);
background-color: var(--accent-hover);
}
.button-secondary {

View File

@ -206,7 +206,7 @@
.new-file-button {
padding: var(--space-sm);
background-color: var(--accent-color);
color: white;
color: var(--accent-text);
border: none;
cursor: pointer;
display: flex;
@ -336,7 +336,7 @@
.icon-btn.save {
background-color: var(--accent-color);
color: white;
color: var(--accent-text);
}
.icon-btn.save:hover {

View File

@ -101,11 +101,11 @@
.button-primary {
background-color: var(--accent-color);
color: white;
color: var(--accent-text);
}
.button-primary:hover {
background-color: var(--accent-color-active);
background-color: var(--accent-hover);
}
.button-secondary {

View File

@ -44,7 +44,7 @@
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;

View File

@ -150,7 +150,7 @@
z-index: 9999;
background-color: var(--bg-color);
border: 1px solid var(--border-color);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
}

View File

@ -1,110 +1,84 @@
import { EditorView } from '@codemirror/view';
import type { Extension } from '@codemirror/state';
import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
import { tags as t } from '@lezer/highlight';
import { syntaxHighlighting } from '@codemirror/language';
import type { Theme } from '../themes/types';
import { createHighlightStyle } from '../themes/utils';
function getCSSVariable(name: string): string {
if (typeof window === 'undefined') return '';
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
}
export function createCodeMirrorTheme(): Extension {
export function createCodeMirrorTheme(theme: Theme): Extension {
const editorTheme = EditorView.theme({
'&': {
backgroundColor: getCSSVariable('--editor-background'),
color: getCSSVariable('--editor-foreground'),
backgroundColor: theme.editor.background,
color: theme.editor.foreground,
},
'.cm-content': {
caretColor: getCSSVariable('--editor-caret'),
caretColor: theme.editor.caret,
},
'.cm-cursor, .cm-dropCursor': {
borderLeftColor: getCSSVariable('--editor-caret'),
borderLeftColor: theme.editor.caret,
},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {
backgroundColor: getCSSVariable('--editor-selection'),
backgroundColor: theme.editor.selection,
},
'.cm-panels': {
backgroundColor: getCSSVariable('--surface-color'),
color: getCSSVariable('--text-color'),
backgroundColor: theme.colors.surface,
color: theme.colors.text,
},
'.cm-panels.cm-panels-top': {
borderBottom: `1px solid ${getCSSVariable('--border-color')}`,
borderBottom: `1px solid ${theme.colors.border}`,
},
'.cm-panels.cm-panels-bottom': {
borderTop: `1px solid ${getCSSVariable('--border-color')}`,
borderTop: `1px solid ${theme.colors.border}`,
},
'.cm-searchMatch': {
backgroundColor: getCSSVariable('--syntax-number'),
outline: `1px solid ${getCSSVariable('--accent-color')}`,
backgroundColor: theme.syntax.number,
outline: `1px solid ${theme.colors.accent}`,
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: getCSSVariable('--accent-color'),
backgroundColor: theme.colors.accent,
},
'.cm-activeLine': {
backgroundColor: getCSSVariable('--editor-active-line'),
backgroundColor: theme.editor.activeLine,
},
'.cm-selectionMatch': {
backgroundColor: getCSSVariable('--editor-selection'),
backgroundColor: theme.editor.selection,
},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: getCSSVariable('--editor-selection'),
backgroundColor: theme.editor.selection,
},
'.cm-gutters': {
backgroundColor: getCSSVariable('--editor-gutter'),
color: getCSSVariable('--editor-gutter-text'),
backgroundColor: theme.editor.gutter,
color: theme.editor.gutterText,
border: 'none',
borderRight: `1px solid ${getCSSVariable('--border-color')}`,
borderRight: `1px solid ${theme.colors.border}`,
},
'.cm-activeLineGutter': {
backgroundColor: getCSSVariable('--editor-active-line-gutter'),
color: getCSSVariable('--editor-line-number'),
backgroundColor: theme.editor.activeLineGutter,
color: theme.editor.lineNumber,
},
'.cm-foldPlaceholder': {
backgroundColor: getCSSVariable('--surface-color'),
border: `1px solid ${getCSSVariable('--border-color')}`,
color: getCSSVariable('--text-secondary'),
backgroundColor: theme.colors.surface,
border: `1px solid ${theme.colors.border}`,
color: theme.colors.textSecondary,
},
'.cm-tooltip': {
border: `1px solid ${getCSSVariable('--border-color')}`,
backgroundColor: getCSSVariable('--surface-color'),
border: `1px solid ${theme.colors.border}`,
backgroundColor: theme.colors.surface,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: getCSSVariable('--border-color'),
borderTopColor: theme.colors.border,
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: getCSSVariable('--surface-color'),
borderTopColor: theme.colors.surface,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
backgroundColor: getCSSVariable('--editor-selection'),
color: getCSSVariable('--text-color'),
backgroundColor: theme.editor.selection,
color: theme.colors.text,
},
},
}, { dark: getCSSVariable('--editor-background').startsWith('#1') || getCSSVariable('--editor-background').startsWith('#2') || getCSSVariable('--editor-background').startsWith('#0') });
}, { dark: theme.name !== 'Light' });
const highlightStyle = HighlightStyle.define([
{ tag: t.keyword, color: getCSSVariable('--syntax-keyword') },
{ tag: [t.name, t.deleted, t.character, t.macroName], color: getCSSVariable('--syntax-variable') },
{ tag: [t.function(t.variableName), t.labelName], color: getCSSVariable('--syntax-function') },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: getCSSVariable('--syntax-constant') },
{ tag: [t.definition(t.name), t.separator], color: getCSSVariable('--syntax-variable') },
{ tag: [t.typeName, t.className, t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: getCSSVariable('--syntax-class') },
{ tag: [t.operator, t.operatorKeyword, t.url, t.escape, t.regexp, t.link, t.special(t.string)], color: getCSSVariable('--syntax-operator') },
{ tag: [t.meta, t.comment], color: getCSSVariable('--syntax-comment'), fontStyle: 'italic' },
{ tag: t.strong, fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
{ tag: t.link, color: getCSSVariable('--accent-color'), textDecoration: 'underline' },
{ tag: t.heading, fontWeight: 'bold', color: getCSSVariable('--syntax-keyword') },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: getCSSVariable('--syntax-boolean') },
{ tag: [t.processingInstruction, t.string, t.inserted], color: getCSSVariable('--syntax-string') },
{ tag: t.invalid, color: getCSSVariable('--danger-color') },
{ tag: t.number, color: getCSSVariable('--syntax-number') },
{ tag: [t.propertyName], color: getCSSVariable('--syntax-property') },
{ tag: [t.typeName], color: getCSSVariable('--syntax-type') },
{ tag: [t.tagName], color: getCSSVariable('--syntax-tag') },
{ tag: [t.attributeName], color: getCSSVariable('--syntax-attribute') },
]);
const highlightStyle = createHighlightStyle(theme);
return [editorTheme, syntaxHighlighting(highlightStyle)];
}

View File

@ -7,17 +7,30 @@ export function applyTheme(theme: Theme): void {
root.setProperty('--bg-color', theme.colors.background);
root.setProperty('--surface-color', theme.colors.surface);
root.setProperty('--surface-hover', theme.colors.surfaceHover);
root.setProperty('--border-color', theme.colors.border);
root.setProperty('--text-color', theme.colors.text);
root.setProperty('--text-secondary', theme.colors.textSecondary);
root.setProperty('--accent-color', theme.colors.accent);
root.setProperty('--accent-hover', theme.colors.accentHover);
root.setProperty('--accent-text', theme.colors.accentText);
root.setProperty('--input-bg', theme.colors.input);
root.setProperty('--input-border', theme.colors.inputBorder);
root.setProperty('--input-border-focus', theme.colors.inputBorderFocus);
root.setProperty('--button-bg', theme.colors.button);
root.setProperty('--button-hover', theme.colors.buttonHover);
root.setProperty('--danger-color', theme.colors.danger);
root.setProperty('--danger-hover', theme.colors.dangerHover);
root.setProperty('--danger-text', theme.colors.dangerText);
root.setProperty('--warning-color', theme.colors.warning);
root.setProperty('--warning-hover', theme.colors.warningHover);
root.setProperty('--warning-text', theme.colors.warningText);
root.setProperty('--info-color', theme.colors.info);
root.setProperty('--info-hover', theme.colors.infoHover);
root.setProperty('--info-text', theme.colors.infoText);
root.setProperty('--success-color', theme.colors.success);
root.setProperty('--success-hover', theme.colors.successHover);
root.setProperty('--success-text', theme.colors.successText);
root.setProperty('--editor-background', theme.editor.background);
root.setProperty('--editor-foreground', theme.editor.foreground);

View File

@ -5,17 +5,30 @@ export const ayumirage: Theme = {
colors: {
background: '#1f2430',
surface: '#232834',
surfaceHover: '#2d3540',
border: '#33415e',
text: '#cccac2',
textSecondary: '#707a8c',
accent: '#ffcc66',
accentHover: '#ffd580',
accentText: '#1f2430',
input: '#242936',
inputBorder: '#33415e',
inputBorderFocus: '#ffcc66',
button: '#33415e',
buttonHover: '#3e4b66',
danger: '#f28779',
dangerHover: '#f5a697',
dangerText: '#1f2430',
warning: '#ffa759',
warningHover: '#f29e74',
warningText: '#1f2430',
info: '#5ccfe6',
infoHover: '#73d0ff',
infoText: '#1f2430',
success: '#d5ff80',
successHover: '#bae67e',
successText: '#1f2430',
},
editor: {
background: '#1f2430',

View File

@ -5,17 +5,30 @@ export const blue: Theme = {
colors: {
background: '#0e1525',
surface: '#162032',
surfaceHover: '#1d2840',
border: '#1f2d47',
text: '#c5d4eb',
textSecondary: '#7a8bb0',
accent: '#4d9fff',
accentHover: '#6eb0ff',
accentText: '#0e1525',
input: '#1a2840',
inputBorder: '#2a3d5f',
inputBorderFocus: '#4d9fff',
button: '#1a2840',
buttonHover: '#243554',
danger: '#ff6b6b',
dangerHover: '#ff5252',
dangerText: '#0e1525',
warning: '#ffb547',
warningHover: '#ff9f28',
warningText: '#0e1525',
info: '#5ccfe6',
infoHover: '#3ebfd8',
infoText: '#0e1525',
success: '#7dd3a0',
successHover: '#5ec481',
successText: '#0e1525',
},
editor: {
background: '#0e1525',

View File

@ -5,17 +5,30 @@ export const bluescreen: Theme = {
colors: {
background: '#0000aa',
surface: '#0000cc',
surfaceHover: '#0000ee',
border: '#5555ff',
text: '#ffffff',
textSecondary: '#aaaaff',
accent: '#ffffff',
accentHover: '#ddddff',
accentText: '#0000aa',
input: '#0000cc',
inputBorder: '#5555ff',
inputBorderFocus: '#ffffff',
button: '#0000cc',
buttonHover: '#0000ee',
danger: '#ffffff',
dangerHover: '#dddddd',
dangerText: '#0000aa',
warning: '#ffff00',
warningHover: '#ffff33',
warningText: '#0000aa',
info: '#00ffff',
infoHover: '#66ffff',
infoText: '#0000aa',
success: '#00ff00',
successHover: '#33ff33',
successText: '#0000aa',
},
editor: {
background: '#0000aa',

View File

@ -5,17 +5,30 @@ export const catppuccin: Theme = {
colors: {
background: '#1e1e2e',
surface: '#181825',
surfaceHover: '#313244',
border: '#45475a',
text: '#cdd6f4',
textSecondary: '#6c7086',
accent: '#89b4fa',
accentHover: '#b4befe',
accentText: '#1e1e2e',
input: '#181825',
inputBorder: '#45475a',
inputBorderFocus: '#89b4fa',
button: '#313244',
buttonHover: '#45475a',
danger: '#f38ba8',
dangerHover: '#eba0ac',
dangerText: '#1e1e2e',
warning: '#f9e2af',
warningHover: '#fab387',
warningText: '#1e1e2e',
info: '#89dceb',
infoHover: '#74c7ec',
infoText: '#1e1e2e',
success: '#a6e3a1',
successHover: '#94e2d5',
successText: '#1e1e2e',
},
editor: {
background: '#1e1e2e',

View File

@ -5,17 +5,30 @@ export const darcula: Theme = {
colors: {
background: '#2b2b2b',
surface: '#313335',
surfaceHover: '#3c3f41',
border: '#3c3f41',
text: '#a9b7c6',
textSecondary: '#808080',
accent: '#4b6eaf',
accentHover: '#5b7ec5',
accentText: '#ffffff',
input: '#45494a',
inputBorder: '#555555',
inputBorderFocus: '#4b6eaf',
button: '#3c3f41',
buttonHover: '#4c5052',
danger: '#c75450',
dangerHover: '#d96461',
dangerText: '#ffffff',
warning: '#e08a38',
warningHover: '#f0a648',
warningText: '#2b2b2b',
info: '#6897bb',
infoHover: '#78a7cb',
infoText: '#2b2b2b',
success: '#629755',
successHover: '#72a765',
successText: '#ffffff',
},
editor: {
background: '#2b2b2b',

View File

@ -5,17 +5,30 @@ export const dracula: Theme = {
colors: {
background: '#282a36',
surface: '#21222c',
surfaceHover: '#2e303e',
border: '#44475a',
text: '#f8f8f2',
textSecondary: '#6272a4',
accent: '#bd93f9',
accentHover: '#d4b5ff',
accentText: '#282a36',
input: '#44475a',
inputBorder: '#6272a4',
inputBorderFocus: '#bd93f9',
button: '#44475a',
buttonHover: '#565869',
danger: '#ff5555',
dangerHover: '#ff6e6e',
dangerText: '#282a36',
warning: '#ffb86c',
warningHover: '#ff9a4d',
warningText: '#282a36',
info: '#8be9fd',
infoHover: '#6ad7f5',
infoText: '#282a36',
success: '#50fa7b',
successHover: '#2ee85c',
successText: '#282a36',
},
editor: {
background: '#282a36',

View File

@ -5,17 +5,30 @@ export const georges: Theme = {
colors: {
background: '#000000',
surface: '#0a0a0a',
surfaceHover: '#1a1a1a',
border: '#1a1a1a',
text: '#e0e0e0',
textSecondary: '#808080',
accent: '#00d9ff',
accentHover: '#33e1ff',
accentText: '#000000',
input: '#0a0a0a',
inputBorder: '#1a1a1a',
inputBorderFocus: '#00d9ff',
button: '#1a1a1a',
buttonHover: '#2a2a2a',
danger: '#ff3366',
dangerHover: '#ff5580',
dangerText: '#000000',
warning: '#ff9d00',
warningHover: '#ffb86c',
warningText: '#000000',
info: '#57c7ff',
infoHover: '#b4f1ff',
infoText: '#000000',
success: '#a5ff90',
successHover: '#c1ffae',
successText: '#000000',
},
editor: {
background: '#000000',

View File

@ -5,17 +5,30 @@ export const gruvbox: Theme = {
colors: {
background: '#282828',
surface: '#3c3836',
surfaceHover: '#504945',
border: '#504945',
text: '#ebdbb2',
textSecondary: '#a89984',
accent: '#fe8019',
accentHover: '#fe9720',
accentText: '#282828',
input: '#3c3836',
inputBorder: '#504945',
inputBorderFocus: '#fe8019',
button: '#3c3836',
buttonHover: '#504945',
danger: '#fb4934',
dangerHover: '#cc241d',
dangerText: '#282828',
warning: '#fabd2f',
warningHover: '#d79921',
warningText: '#282828',
info: '#83a598',
infoHover: '#458588',
infoText: '#282828',
success: '#b8bb26',
successHover: '#98971a',
successText: '#282828',
},
editor: {
background: '#282828',

View File

@ -5,17 +5,30 @@ export const hacker: Theme = {
colors: {
background: '#0d0d0d',
surface: '#1a1a1a',
surfaceHover: '#252525',
border: '#00ff00',
text: '#00ff00',
textSecondary: '#008800',
accent: '#00ff00',
accentHover: '#33ff33',
accentText: '#000000',
input: '#1a1a1a',
inputBorder: '#008800',
inputBorderFocus: '#00ff00',
button: '#1a1a1a',
buttonHover: '#0f2f0f',
danger: '#ff0000',
dangerHover: '#ff3333',
dangerText: '#000000',
warning: '#ffff00',
warningHover: '#ffff33',
warningText: '#000000',
info: '#00ffff',
infoHover: '#33ffff',
infoText: '#000000',
success: '#00ff88',
successHover: '#33ffaa',
successText: '#000000',
},
editor: {
background: '#0d0d0d',

View File

@ -5,17 +5,30 @@ export const light: Theme = {
colors: {
background: '#ffffff',
surface: '#f5f5f5',
surfaceHover: '#e8e8e8',
border: '#e0e0e0',
text: '#333333',
textSecondary: '#6e7681',
accent: '#0066cc',
accentHover: '#0052a3',
accentText: '#ffffff',
input: '#ffffff',
inputBorder: '#d0d0d0',
inputBorderFocus: '#0066cc',
button: '#e8e8e8',
buttonHover: '#d0d0d0',
danger: '#d32f2f',
dangerHover: '#b71c1c',
dangerText: '#ffffff',
warning: '#f57c00',
warningHover: '#e65100',
warningText: '#ffffff',
info: '#0288d1',
infoHover: '#01579b',
infoText: '#ffffff',
success: '#388e3c',
successHover: '#2e7d32',
successText: '#ffffff',
},
editor: {
background: '#ffffff',

View File

@ -5,17 +5,30 @@ export const materialdarker: Theme = {
colors: {
background: '#212121',
surface: '#292929',
surfaceHover: '#3a3a3a',
border: '#3a3a3a',
text: '#eeffff',
textSecondary: '#616161',
accent: '#80cbc4',
accentHover: '#a1dbd5',
accentText: '#212121',
input: '#292929',
inputBorder: '#3a3a3a',
inputBorderFocus: '#80cbc4',
button: '#3a3a3a',
buttonHover: '#4a4a4a',
danger: '#f07178',
dangerHover: '#f49499',
dangerText: '#212121',
warning: '#ffcb6b',
warningHover: '#f78c6c',
warningText: '#212121',
info: '#89ddff',
infoHover: '#82aaff',
infoText: '#212121',
success: '#c3e88d',
successHover: '#a5d374',
successText: '#212121',
},
editor: {
background: '#212121',

View File

@ -5,17 +5,30 @@ export const monodark: Theme = {
colors: {
background: '#000000',
surface: '#0a0a0a',
surfaceHover: '#1a1a1a',
border: '#333333',
text: '#ffffff',
textSecondary: '#999999',
accent: '#ffffff',
accentHover: '#cccccc',
accentText: '#000000',
input: '#1a1a1a',
inputBorder: '#444444',
inputBorderFocus: '#666666',
button: '#1a1a1a',
buttonHover: '#2a2a2a',
danger: '#ffffff',
dangerHover: '#cccccc',
dangerText: '#000000',
warning: '#ffaa00',
warningHover: '#ff8800',
warningText: '#000000',
info: '#3399ff',
infoHover: '#1177dd',
infoText: '#000000',
success: '#00cc66',
successHover: '#00aa55',
successText: '#000000',
},
editor: {
background: '#000000',

View File

@ -5,17 +5,30 @@ export const monokai: Theme = {
colors: {
background: '#272822',
surface: '#2e2f2a',
surfaceHover: '#3a3b35',
border: '#3e3d32',
text: '#f8f8f2',
textSecondary: '#75715e',
accent: '#66d9ef',
accentHover: '#a1efe4',
accentText: '#272822',
input: '#3e3d32',
inputBorder: '#5a5a47',
inputBorderFocus: '#66d9ef',
button: '#3e3d32',
buttonHover: '#49483e',
danger: '#f92672',
dangerHover: '#ff669d',
dangerText: '#272822',
warning: '#fd971f',
warningHover: '#e67e00',
warningText: '#272822',
info: '#66d9ef',
infoHover: '#a1efe4',
infoText: '#272822',
success: '#a6e22e',
successHover: '#8dc919',
successText: '#272822',
},
editor: {
background: '#272822',

View File

@ -5,17 +5,30 @@ export const monolight: Theme = {
colors: {
background: '#ffffff',
surface: '#f8f8f8',
surfaceHover: '#eeeeee',
border: '#e0e0e0',
text: '#000000',
textSecondary: '#666666',
accent: '#000000',
accentHover: '#333333',
accentText: '#ffffff',
input: '#ffffff',
inputBorder: '#cccccc',
inputBorderFocus: '#666666',
button: '#f0f0f0',
buttonHover: '#e0e0e0',
danger: '#000000',
dangerHover: '#333333',
dangerText: '#ffffff',
warning: '#666666',
warningHover: '#555555',
warningText: '#ffffff',
info: '#555555',
infoHover: '#444444',
infoText: '#ffffff',
success: '#444444',
successHover: '#333333',
successText: '#ffffff',
},
editor: {
background: '#ffffff',

View File

@ -5,17 +5,30 @@ export const nightowl: Theme = {
colors: {
background: '#011627',
surface: '#0b2942',
surfaceHover: '#1d3b53',
border: '#1d3b53',
text: '#d6deeb',
textSecondary: '#637777',
accent: '#80a4c2',
accentHover: '#9fb9d0',
accentText: '#011627',
input: '#0b2942',
inputBorder: '#1d3b53',
inputBorderFocus: '#80a4c2',
button: '#1d3b53',
buttonHover: '#2d4f6b',
danger: '#ef5350',
dangerHover: '#f27572',
dangerText: '#011627',
warning: '#ecc48d',
warningHover: '#f78c6c',
warningText: '#011627',
info: '#82aaff',
infoHover: '#7fdbca',
infoText: '#011627',
success: '#addb67',
successHover: '#7fdbca',
successText: '#011627',
},
editor: {
background: '#011627',

View File

@ -5,17 +5,30 @@ export const nord: Theme = {
colors: {
background: '#2e3440',
surface: '#3b4252',
surfaceHover: '#434c5e',
border: '#4c566a',
text: '#d8dee9',
textSecondary: '#81a1c1',
accent: '#88c0d0',
accentHover: '#8fbcbb',
accentText: '#2e3440',
input: '#3b4252',
inputBorder: '#4c566a',
inputBorderFocus: '#88c0d0',
button: '#434c5e',
buttonHover: '#4c566a',
danger: '#bf616a',
dangerHover: '#d08770',
dangerText: '#2e3440',
warning: '#ebcb8b',
warningHover: '#d08770',
warningText: '#2e3440',
info: '#81a1c1',
infoHover: '#5e81ac',
infoText: '#2e3440',
success: '#a3be8c',
successHover: '#8fa876',
successText: '#2e3440',
},
editor: {
background: '#2e3440',

View File

@ -5,17 +5,30 @@ export const onedarkpro: Theme = {
colors: {
background: '#1e2127',
surface: '#282c34',
surfaceHover: '#3e4451',
border: '#3e4451',
text: '#abb2bf',
textSecondary: '#5c6370',
accent: '#61afef',
accentHover: '#84c0f4',
accentText: '#1e2127',
input: '#282c34',
inputBorder: '#3e4451',
inputBorderFocus: '#61afef',
button: '#3e4451',
buttonHover: '#4b5362',
danger: '#e06c75',
dangerHover: '#e88388',
dangerText: '#1e2127',
warning: '#e5c07b',
warningHover: '#d19a66',
warningText: '#1e2127',
info: '#56b6c2',
infoHover: '#61afef',
infoText: '#1e2127',
success: '#98c379',
successHover: '#7fb068',
successText: '#1e2127',
},
editor: {
background: '#1e2127',

View File

@ -5,17 +5,30 @@ export const solarizeddark: Theme = {
colors: {
background: '#002b36',
surface: '#073642',
surfaceHover: '#094551',
border: '#586e75',
text: '#839496',
textSecondary: '#657b83',
accent: '#268bd2',
accentHover: '#2aa198',
accentText: '#002b36',
input: '#073642',
inputBorder: '#586e75',
inputBorderFocus: '#268bd2',
button: '#073642',
buttonHover: '#094551',
danger: '#dc322f',
dangerHover: '#cb4b16',
dangerText: '#fdf6e3',
warning: '#b58900',
warningHover: '#cb4b16',
warningText: '#002b36',
info: '#2aa198',
infoHover: '#268bd2',
infoText: '#002b36',
success: '#859900',
successHover: '#719600',
successText: '#002b36',
},
editor: {
background: '#002b36',

View File

@ -5,17 +5,30 @@ export const solarizedlight: Theme = {
colors: {
background: '#fdf6e3',
surface: '#eee8d5',
surfaceHover: '#e4ddc4',
border: '#93a1a1',
text: '#657b83',
textSecondary: '#839496',
accent: '#268bd2',
accentHover: '#2aa198',
accentText: '#fdf6e3',
input: '#eee8d5',
inputBorder: '#93a1a1',
inputBorderFocus: '#268bd2',
button: '#eee8d5',
buttonHover: '#e4ddc4',
danger: '#dc322f',
dangerHover: '#cb4b16',
dangerText: '#fdf6e3',
warning: '#b58900',
warningHover: '#cb4b16',
warningText: '#fdf6e3',
info: '#2aa198',
infoHover: '#268bd2',
infoText: '#fdf6e3',
success: '#859900',
successHover: '#719600',
successText: '#fdf6e3',
},
editor: {
background: '#fdf6e3',

View File

@ -5,17 +5,30 @@ export const tokyonight: Theme = {
colors: {
background: '#1a1b26',
surface: '#16161e',
surfaceHover: '#1f2335',
border: '#414868',
text: '#c0caf5',
textSecondary: '#565f89',
accent: '#7aa2f7',
accentHover: '#89b4fa',
accentText: '#1a1b26',
input: '#1f2335',
inputBorder: '#414868',
inputBorderFocus: '#7aa2f7',
button: '#1f2335',
buttonHover: '#24283b',
danger: '#f7768e',
dangerHover: '#ff9e64',
dangerText: '#1a1b26',
warning: '#e0af68',
warningHover: '#ff9e64',
warningText: '#1a1b26',
info: '#2ac3de',
infoHover: '#7dcfff',
infoText: '#1a1b26',
success: '#9ece6a',
successHover: '#b9f27c',
successText: '#1a1b26',
},
editor: {
background: '#1a1b26',

View File

@ -1,5 +1,6 @@
export type { Theme } from './types';
export { applyTheme } from './apply-theme';
export { createHighlightStyle } from './utils';
import type { Theme } from './types';
import { light } from './definitions/light';
import { blue } from './definitions/blue';

View File

@ -3,17 +3,30 @@ export interface Theme {
colors: {
background: string;
surface: string;
surfaceHover: string;
border: string;
text: string;
textSecondary: string;
accent: string;
accentHover: string;
accentText: string;
input: string;
inputBorder: string;
inputBorderFocus: string;
button: string;
buttonHover: string;
danger: string;
dangerHover: string;
dangerText: string;
warning: string;
warningHover: string;
warningText: string;
info: string;
infoHover: string;
infoText: string;
success: string;
successHover: string;
successText: string;
};
editor: {
background: string;

30
src/lib/themes/utils.ts Normal file
View File

@ -0,0 +1,30 @@
import { HighlightStyle } from '@codemirror/language';
import { tags as t } from '@lezer/highlight';
import type { Theme } from './types';
export function createHighlightStyle(theme: Theme): HighlightStyle {
return HighlightStyle.define([
{ tag: t.keyword, color: theme.syntax.keyword },
{ tag: [t.function(t.variableName), t.labelName], color: theme.syntax.function },
{ tag: [t.variableName], color: theme.syntax.function },
{ tag: [t.name, t.deleted, t.character, t.macroName], color: theme.syntax.variable },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: theme.syntax.constant },
{ tag: [t.definition(t.name), t.separator], color: theme.syntax.variable },
{ tag: [t.typeName, t.className, t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: theme.syntax.class },
{ tag: [t.operator, t.operatorKeyword, t.url, t.escape, t.regexp, t.link, t.special(t.string)], color: theme.syntax.operator },
{ tag: [t.meta, t.comment], color: theme.syntax.comment },
{ tag: t.strong, fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
{ tag: t.link, color: theme.syntax.string, textDecoration: 'underline' },
{ tag: t.heading, fontWeight: 'bold', color: theme.syntax.keyword },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: theme.syntax.boolean },
{ tag: [t.processingInstruction, t.string, t.inserted], color: theme.syntax.string },
{ tag: t.invalid, color: theme.editor.foreground },
{ tag: t.number, color: theme.syntax.number },
{ tag: [t.propertyName], color: theme.syntax.property },
{ tag: [t.typeName], color: theme.syntax.type },
{ tag: [t.tagName], color: theme.syntax.tag },
{ tag: [t.attributeName], color: theme.syntax.attribute },
]);
}