diff --git a/src/App.svelte b/src/App.svelte index ad2fff1..2cbea96 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -25,7 +25,7 @@ import { loadLastProjectId } from "./lib/project-system/persistence"; import { createAppContext, setAppContext } from "./lib/contexts/app-context"; import type { ProjectMode } from "./lib/project-system/types"; - import { themes } from "./lib/themes"; + import { themes, applyTheme } from "./lib/themes"; import { Save, Share2, @@ -239,52 +239,9 @@ } $effect(() => { - if (typeof document !== 'undefined') { - const themeName = $editorSettings.theme; - const theme = themes[themeName]; - - if (theme) { - const root = document.documentElement.style; - - root.setProperty('--bg-color', theme.colors.background); - root.setProperty('--surface-color', theme.colors.surface); - 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('--input-bg', theme.colors.input); - root.setProperty('--input-border', theme.colors.inputBorder); - 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('--editor-background', theme.editor.background); - root.setProperty('--editor-foreground', theme.editor.foreground); - root.setProperty('--editor-caret', theme.editor.caret); - root.setProperty('--editor-selection', theme.editor.selection); - root.setProperty('--editor-active-line', theme.editor.activeLine); - root.setProperty('--editor-gutter', theme.editor.gutter); - root.setProperty('--editor-gutter-text', theme.editor.gutterText); - root.setProperty('--editor-active-line-gutter', theme.editor.activeLineGutter); - root.setProperty('--editor-line-number', theme.editor.lineNumber); - - root.setProperty('--syntax-keyword', theme.syntax.keyword); - root.setProperty('--syntax-operator', theme.syntax.operator); - root.setProperty('--syntax-string', theme.syntax.string); - root.setProperty('--syntax-number', theme.syntax.number); - root.setProperty('--syntax-boolean', theme.syntax.boolean); - root.setProperty('--syntax-comment', theme.syntax.comment); - root.setProperty('--syntax-function', theme.syntax.function); - root.setProperty('--syntax-class', theme.syntax.class); - root.setProperty('--syntax-variable', theme.syntax.variable); - root.setProperty('--syntax-property', theme.syntax.property); - root.setProperty('--syntax-constant', theme.syntax.constant); - root.setProperty('--syntax-type', theme.syntax.type); - root.setProperty('--syntax-tag', theme.syntax.tag); - root.setProperty('--syntax-attribute', theme.syntax.attribute); - } + const theme = themes[$editorSettings.theme]; + if (theme) { + applyTheme(theme); } }); @@ -600,7 +557,7 @@ padding: var(--space-sm); background-color: var(--border-color); color: var(--text-color); - border: 1px solid #555; + border: 1px solid var(--border-color); cursor: pointer; display: flex; align-items: center; @@ -609,7 +566,7 @@ } .icon-button:hover:not(:disabled) { - background-color: #444; + background-color: var(--button-hover); border-color: var(--accent-color); } @@ -623,12 +580,12 @@ } .icon-button.stop-button:not(:disabled) { - color: #ff6b6b; + color: var(--danger-color); } .icon-button.stop-button:hover:not(:disabled) { - color: #ff5252; - border-color: #ff5252; + color: var(--danger-hover); + border-color: var(--danger-hover); } h3 { @@ -705,10 +662,10 @@ } .enable-audio-button:hover { - background-color: #535bdb; + background-color: var(--accent-hover); } .enable-audio-button:active { - background-color: var(--accent-hover); + background-color: var(--accent-color); } diff --git a/src/app.css b/src/app.css index f180277..48459a0 100644 --- a/src/app.css +++ b/src/app.css @@ -7,9 +7,8 @@ line-height: 1.5; font-weight: 400; - color-scheme: dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; + color: var(--text-color); + background-color: var(--bg-color); font-synthesis: none; text-rendering: optimizeLegibility; @@ -35,12 +34,12 @@ body { a { font-weight: 500; - color: #646cff; + color: var(--accent-color); text-decoration: inherit; } a:hover { - color: #535bf2; + color: var(--accent-hover); } button { @@ -49,17 +48,17 @@ button { font-size: 1em; font-weight: 500; font-family: inherit; - background-color: #1a1a1a; + background-color: var(--button-bg); cursor: pointer; transition: border-color 0.25s; } button:hover { - border-color: #646cff; + border-color: var(--accent-color); } button:focus, button:focus-visible { - outline: 2px solid #646cff; + outline: 2px solid var(--accent-color); outline-offset: 2px; } diff --git a/src/lib/components/editor/EditorSettings.svelte b/src/lib/components/editor/EditorSettings.svelte index 9955631..dd19949 100644 --- a/src/lib/components/editor/EditorSettings.svelte +++ b/src/lib/components/editor/EditorSettings.svelte @@ -141,7 +141,7 @@ input[type="range"] { width: 100%; height: 8px; - background: #4b5563; + background: var(--input-bg); appearance: none; cursor: pointer; } @@ -163,7 +163,7 @@ } input[type="range"]:hover { - background: #6b7280; + background: var(--button-hover); } input[type="range"]::-webkit-slider-thumb:hover { @@ -178,7 +178,7 @@ width: 100%; background-color: var(--bg-color); color: var(--text-color); - border: 1px solid #555; + border: 1px solid var(--border-color); padding: 0.4rem; font-size: var(--font-sm); cursor: pointer; @@ -213,15 +213,15 @@ appearance: none; width: 16px; height: 16px; - background-color: #4b5563; - border: 1px solid #6b7280; + background-color: var(--input-bg); + border: 1px solid var(--input-border); cursor: pointer; transition: all var(--transition-base); } input[type="checkbox"]:hover { - background-color: #6b7280; - border-color: #9ca3af; + background-color: var(--button-hover); + border-color: var(--border-color); } input[type="checkbox"]:checked { diff --git a/src/lib/stores/editorSettings.ts b/src/lib/stores/editorSettings.ts index 6b35147..d47226f 100644 --- a/src/lib/stores/editorSettings.ts +++ b/src/lib/stores/editorSettings.ts @@ -1,5 +1,5 @@ import { writable } from 'svelte/store'; -import type { ThemeName } from '$lib/themes'; +import type { ThemeName } from '../themes'; const STORAGE_KEY = 'editorSettings'; diff --git a/src/lib/themes/apply-theme.ts b/src/lib/themes/apply-theme.ts new file mode 100644 index 0000000..d278215 --- /dev/null +++ b/src/lib/themes/apply-theme.ts @@ -0,0 +1,46 @@ +import type { Theme } from './types'; + +export function applyTheme(theme: Theme): void { + if (typeof document === 'undefined') return; + + const root = document.documentElement.style; + + root.setProperty('--bg-color', theme.colors.background); + root.setProperty('--surface-color', theme.colors.surface); + 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('--input-bg', theme.colors.input); + root.setProperty('--input-border', theme.colors.inputBorder); + 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('--editor-background', theme.editor.background); + root.setProperty('--editor-foreground', theme.editor.foreground); + root.setProperty('--editor-caret', theme.editor.caret); + root.setProperty('--editor-selection', theme.editor.selection); + root.setProperty('--editor-active-line', theme.editor.activeLine); + root.setProperty('--editor-gutter', theme.editor.gutter); + root.setProperty('--editor-gutter-text', theme.editor.gutterText); + root.setProperty('--editor-active-line-gutter', theme.editor.activeLineGutter); + root.setProperty('--editor-line-number', theme.editor.lineNumber); + + root.setProperty('--syntax-keyword', theme.syntax.keyword); + root.setProperty('--syntax-operator', theme.syntax.operator); + root.setProperty('--syntax-string', theme.syntax.string); + root.setProperty('--syntax-number', theme.syntax.number); + root.setProperty('--syntax-boolean', theme.syntax.boolean); + root.setProperty('--syntax-comment', theme.syntax.comment); + root.setProperty('--syntax-function', theme.syntax.function); + root.setProperty('--syntax-class', theme.syntax.class); + root.setProperty('--syntax-variable', theme.syntax.variable); + root.setProperty('--syntax-property', theme.syntax.property); + root.setProperty('--syntax-constant', theme.syntax.constant); + root.setProperty('--syntax-type', theme.syntax.type); + root.setProperty('--syntax-tag', theme.syntax.tag); + root.setProperty('--syntax-attribute', theme.syntax.attribute); +} diff --git a/src/lib/themes/exportCss.ts b/src/lib/themes/exportCss.ts deleted file mode 100644 index 37b272c..0000000 --- a/src/lib/themes/exportCss.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { Theme } from './types'; - -export function generateThemeCss(theme: Theme): string { - return ` -/* ${theme.name} Theme */ - -/* UI Colors */ ---bg-color: ${theme.colors.background}; ---surface-color: ${theme.colors.surface}; ---border-color: ${theme.colors.border}; ---text-color: ${theme.colors.text}; ---text-secondary: ${theme.colors.textSecondary}; ---accent-color: ${theme.colors.accent}; ---accent-hover: ${theme.colors.accentHover}; ---input-bg: ${theme.colors.input}; ---input-border: ${theme.colors.inputBorder}; ---button-bg: ${theme.colors.button}; ---button-hover: ${theme.colors.buttonHover}; ---danger-color: ${theme.colors.danger}; ---danger-hover: ${theme.colors.dangerHover}; - -/* Editor Colors */ ---editor-background: ${theme.editor.background}; ---editor-foreground: ${theme.editor.foreground}; ---editor-caret: ${theme.editor.caret}; ---editor-selection: ${theme.editor.selection}; ---editor-active-line: ${theme.editor.activeLine}; ---editor-gutter: ${theme.editor.gutter}; ---editor-gutter-text: ${theme.editor.gutterText}; ---editor-active-line-gutter: ${theme.editor.activeLineGutter}; ---editor-line-number: ${theme.editor.lineNumber}; - -/* Syntax Highlighting */ ---syntax-keyword: ${theme.syntax.keyword}; ---syntax-operator: ${theme.syntax.operator}; ---syntax-string: ${theme.syntax.string}; ---syntax-number: ${theme.syntax.number}; ---syntax-boolean: ${theme.syntax.boolean}; ---syntax-comment: ${theme.syntax.comment}; ---syntax-function: ${theme.syntax.function}; ---syntax-class: ${theme.syntax.class}; ---syntax-variable: ${theme.syntax.variable}; ---syntax-property: ${theme.syntax.property}; ---syntax-constant: ${theme.syntax.constant}; ---syntax-type: ${theme.syntax.type}; ---syntax-tag: ${theme.syntax.tag}; ---syntax-attribute: ${theme.syntax.attribute}; -`.trim(); -} diff --git a/src/lib/themes/index.ts b/src/lib/themes/index.ts index 2a80dbf..739e7da 100644 --- a/src/lib/themes/index.ts +++ b/src/lib/themes/index.ts @@ -1,7 +1,5 @@ export type { Theme } from './types'; -export { createHighlightStyle } from './utils'; -export { generateThemeCss } from './exportCss'; - +export { applyTheme } from './apply-theme'; import type { Theme } from './types'; import { light } from './definitions/light'; import { blue } from './definitions/blue'; diff --git a/src/lib/themes/utils.ts b/src/lib/themes/utils.ts deleted file mode 100644 index 1cb24e7..0000000 --- a/src/lib/themes/utils.ts +++ /dev/null @@ -1,29 +0,0 @@ -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.name, t.deleted, t.character, t.macroName], color: theme.syntax.variable }, - { tag: [t.function(t.variableName), t.labelName], color: theme.syntax.function }, - { 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 }, - ]); -} diff --git a/src/main.ts b/src/main.ts index f10e710..d9d4239 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,7 +2,7 @@ import { mount } from 'svelte' import './base.css' import './app.css' import App from './App.svelte' -import { themes } from './lib/themes' +import { themes, applyTheme } from './lib/themes' // Apply saved theme before mounting app to prevent flash const STORAGE_KEY = 'editorSettings'; @@ -11,47 +11,7 @@ if (stored) { try { const settings = JSON.parse(stored); if (settings.theme && themes[settings.theme]) { - const theme = themes[settings.theme]; - const root = document.documentElement.style; - - root.setProperty('--bg-color', theme.colors.background); - root.setProperty('--surface-color', theme.colors.surface); - 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('--input-bg', theme.colors.input); - root.setProperty('--input-border', theme.colors.inputBorder); - 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('--editor-background', theme.editor.background); - root.setProperty('--editor-foreground', theme.editor.foreground); - root.setProperty('--editor-caret', theme.editor.caret); - root.setProperty('--editor-selection', theme.editor.selection); - root.setProperty('--editor-active-line', theme.editor.activeLine); - root.setProperty('--editor-gutter', theme.editor.gutter); - root.setProperty('--editor-gutter-text', theme.editor.gutterText); - root.setProperty('--editor-active-line-gutter', theme.editor.activeLineGutter); - root.setProperty('--editor-line-number', theme.editor.lineNumber); - - root.setProperty('--syntax-keyword', theme.syntax.keyword); - root.setProperty('--syntax-operator', theme.syntax.operator); - root.setProperty('--syntax-string', theme.syntax.string); - root.setProperty('--syntax-number', theme.syntax.number); - root.setProperty('--syntax-boolean', theme.syntax.boolean); - root.setProperty('--syntax-comment', theme.syntax.comment); - root.setProperty('--syntax-function', theme.syntax.function); - root.setProperty('--syntax-class', theme.syntax.class); - root.setProperty('--syntax-variable', theme.syntax.variable); - root.setProperty('--syntax-property', theme.syntax.property); - root.setProperty('--syntax-constant', theme.syntax.constant); - root.setProperty('--syntax-type', theme.syntax.type); - root.setProperty('--syntax-tag', theme.syntax.tag); - root.setProperty('--syntax-attribute', theme.syntax.attribute); + applyTheme(themes[settings.theme]); } } catch (e) { console.error('Failed to parse editor settings:', e);