This commit is contained in:
2025-10-15 16:52:39 +02:00
parent 1015e9e18f
commit 1b35c4ccc1
26 changed files with 1078 additions and 433 deletions

View File

@ -6,10 +6,9 @@
import { defaultKeymap, history, historyKeymap } from '@codemirror/commands';
import { searchKeymap, highlightSelectionMatches } from '@codemirror/search';
import { autocompletion, completionKeymap, closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
import { foldGutter, indentOnInput, syntaxHighlighting, defaultHighlightStyle, bracketMatching, foldKeymap } from '@codemirror/language';
import { foldGutter, indentOnInput, bracketMatching, foldKeymap } from '@codemirror/language';
import { lintKeymap } from '@codemirror/lint';
import { csoundMode } from '@hlolli/codemirror-lang-csound';
import { oneDark } from '@codemirror/theme-one-dark';
import { vim } from '@replit/codemirror-vim';
import type { EditorSettingsStore } from '../../stores/editorSettings';
import {
@ -20,6 +19,7 @@
getDocument
} from '../../editor/block-eval';
import { csoundTooltip, csoundTooltipTheme } from '../../csound-reference/csoundTooltips';
import { createCodeMirrorTheme } from '../../editor/codemirror-theme';
interface Props {
value: string;
@ -44,6 +44,8 @@
const lineWrappingCompartment = new Compartment();
const vimCompartment = new Compartment();
const languageCompartment = new Compartment();
const hoverTooltipCompartment = new Compartment();
const themeCompartment = new Compartment();
function handleExecute() {
if (!editorView) return;
@ -93,14 +95,12 @@
drawSelection(),
dropCursor(),
indentOnInput(),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
bracketMatching(),
closeBrackets(),
autocompletion(),
rectangularSelection(),
crosshairCursor(),
highlightSelectionMatches(),
csoundTooltip,
csoundTooltipTheme,
keymap.of([
...closeBracketsKeymap,
@ -122,12 +122,13 @@
extensions: [
...baseExtensions,
languageCompartment.of(csoundMode({ fileType })),
oneDark,
themeCompartment.of(createCodeMirrorTheme()),
evaluateKeymap,
flashField(),
lineNumbersCompartment.of(initSettings.showLineNumbers ? lineNumbers() : []),
lineWrappingCompartment.of(initSettings.enableLineWrapping ? EditorView.lineWrapping : []),
vimCompartment.of(initSettings.vimMode ? vim() : []),
hoverTooltipCompartment.of(initSettings.enableHoverTooltips ? csoundTooltip : []),
EditorView.updateListener.of((update) => {
if (update.docChanged && onChange) {
onChange(update.state.doc.toString());
@ -152,7 +153,8 @@
effects: [
lineNumbersCompartment.reconfigure(settings.showLineNumbers ? lineNumbers() : []),
lineWrappingCompartment.reconfigure(settings.enableLineWrapping ? EditorView.lineWrapping : []),
vimCompartment.reconfigure(settings.vimMode ? vim() : [])
vimCompartment.reconfigure(settings.vimMode ? vim() : []),
hoverTooltipCompartment.reconfigure(settings.enableHoverTooltips ? csoundTooltip : [])
]
});
@ -160,6 +162,20 @@
editorView.dom.style.fontFamily = settings.fontFamily;
});
$effect(() => {
const theme = $editorSettings.theme;
if (!editorView) return;
// Wait for CSS variables to be recomputed after theme change
requestAnimationFrame(() => {
if (editorView) {
editorView.dispatch({
effects: themeCompartment.reconfigure(createCodeMirrorTheme())
});
}
});
});
$effect(() => {
if (!editorView) return;

View File

@ -15,6 +15,26 @@
</script>
<div class="editor-settings">
<div class="setting">
<span class="label-text">Theme</span>
<div class="theme-toggle">
<button
class="theme-option"
class:active={settings.theme === 'dark'}
onclick={() => updateSetting('theme', 'dark')}
>
Dark
</button>
<button
class="theme-option"
class:active={settings.theme === 'light'}
onclick={() => updateSetting('theme', 'light')}
>
Light
</button>
</div>
</div>
<div class="setting">
<label>
<span class="label-text">Font Size: {settings.fontSize}px</span>
@ -87,17 +107,26 @@
/>
<span>Enable line wrapping</span>
</label>
<label class="checkbox-label">
<input
type="checkbox"
checked={settings.enableHoverTooltips}
onchange={(e) => updateSetting('enableHoverTooltips', e.currentTarget.checked)}
/>
<span>Enable hover tooltips</span>
</label>
</div>
</div>
<style>
.editor-settings {
padding: 0.5rem;
color: rgba(255, 255, 255, 0.87);
padding: var(--space-sm);
color: var(--color-text-primary);
}
.setting {
margin-bottom: 1rem;
margin-bottom: var(--space-lg);
}
label {
@ -106,10 +135,44 @@
.label-text {
display: block;
font-size: 0.75rem;
font-size: var(--font-sm);
font-weight: 500;
color: rgba(255, 255, 255, 0.6);
margin-bottom: 0.25rem;
color: var(--color-text-secondary);
margin-bottom: var(--space-xs);
}
.theme-toggle {
display: flex;
gap: 0;
border: 1px solid var(--color-border-default);
overflow: hidden;
}
.theme-option {
flex: 1;
padding: var(--space-sm) var(--space-lg);
background-color: transparent;
color: var(--color-text-secondary);
border: none;
cursor: pointer;
font-size: var(--font-sm);
font-weight: 500;
transition: all var(--transition-base);
border-right: 1px solid var(--color-border-default);
}
.theme-option:last-child {
border-right: none;
}
.theme-option:hover:not(.active) {
background-color: var(--color-hover-overlay);
color: var(--color-text-primary);
}
.theme-option.active {
background-color: var(--color-accent-primary);
color: white;
}
input[type="range"] {
@ -124,14 +187,14 @@
appearance: none;
width: 12px;
height: 12px;
background: #646cff;
background: var(--color-accent-primary);
cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
width: 12px;
height: 12px;
background: #646cff;
background: var(--color-accent-primary);
cursor: pointer;
border: none;
}
@ -141,45 +204,45 @@
}
input[type="range"]::-webkit-slider-thumb:hover {
background: #818cf8;
background: var(--color-accent-primary-hover);
}
input[type="range"]::-moz-range-thumb:hover {
background: #818cf8;
background: var(--color-accent-primary-hover);
}
select {
width: 100%;
background-color: #1a1a1a;
color: rgba(255, 255, 255, 0.87);
background-color: var(--color-bg-base);
color: var(--color-text-primary);
border: 1px solid #555;
padding: 0.4rem;
font-size: 0.75rem;
font-size: var(--font-sm);
cursor: pointer;
}
select:hover {
border-color: #646cff;
border-color: var(--color-accent-primary);
}
select:focus {
outline: none;
border-color: #646cff;
border-color: var(--color-accent-primary);
}
.checkboxes {
display: flex;
flex-direction: column;
gap: 0.5rem;
gap: var(--space-sm);
}
.checkbox-label {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.75rem;
gap: var(--space-sm);
font-size: var(--font-sm);
font-weight: 500;
color: rgba(255, 255, 255, 0.6);
color: var(--color-text-secondary);
cursor: pointer;
}
@ -190,7 +253,7 @@
background-color: #4b5563;
border: 1px solid #6b7280;
cursor: pointer;
transition: all 0.2s;
transition: all var(--transition-base);
}
input[type="checkbox"]:hover {
@ -199,13 +262,13 @@
}
input[type="checkbox"]:checked {
background-color: #646cff;
border-color: #646cff;
background-color: var(--color-accent-primary);
border-color: var(--color-accent-primary);
}
input[type="checkbox"]:checked:hover {
background-color: #818cf8;
border-color: #818cf8;
background-color: var(--color-accent-primary-hover);
border-color: var(--color-accent-primary-hover);
}
input[type="checkbox"]:checked::before {

View File

@ -113,15 +113,15 @@
.resize-divider {
height: 4px;
background-color: #2a2a2a;
background-color: var(--color-surface-3);
cursor: ns-resize;
transition: background-color 0.2s;
transition: background-color var(--transition-base);
z-index: 10;
}
.resize-divider:hover,
.resize-divider:active {
background-color: #646cff;
background-color: var(--color-accent-primary);
}
.logs-section {

View File

@ -188,86 +188,86 @@
display: flex;
flex-direction: column;
height: 100%;
background-color: #1a1a1a;
background-color: var(--color-bg-base);
}
.log-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem 0.75rem;
background-color: #2a2a2a;
border-bottom: 1px solid #3a3a3a;
padding: var(--space-sm) var(--space-md);
background-color: var(--color-surface-3);
border-bottom: 1px solid var(--color-border-default);
cursor: pointer;
transition: background-color 0.2s;
transition: background-color var(--transition-base);
}
.log-header:hover {
background-color: #323232;
background-color: var(--color-hover-overlay);
}
.search-bar {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
background-color: #252525;
border-bottom: 1px solid #3a3a3a;
gap: var(--space-sm);
padding: var(--space-sm) var(--space-md);
background-color: var(--color-surface-2);
border-bottom: 1px solid var(--color-border-default);
}
.search-bar :global(.search-icon) {
color: rgba(255, 255, 255, 0.4);
color: var(--color-text-tertiary);
flex-shrink: 0;
}
.search-input {
flex: 1;
background-color: #1a1a1a;
color: rgba(255, 255, 255, 0.87);
border: 1px solid #3a3a3a;
padding: 0.375rem 0.5rem;
font-size: 0.875rem;
font-family: 'Courier New', monospace;
background-color: var(--color-bg-base);
color: var(--color-text-primary);
border: 1px solid var(--color-border-default);
padding: 0.375rem var(--space-sm);
font-size: var(--font-base);
font-family: var(--font-mono);
outline: none;
transition: border-color 0.2s;
transition: border-color var(--transition-base);
}
.search-input:focus {
border-color: rgba(255, 255, 255, 0.4);
border-color: var(--color-text-tertiary);
}
.search-input::placeholder {
color: rgba(255, 255, 255, 0.3);
color: var(--color-text-disabled);
}
.log-title {
font-size: 0.75rem;
font-size: var(--font-sm);
font-weight: 600;
color: rgba(255, 255, 255, 0.6);
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.log-actions {
display: flex;
gap: 0.25rem;
gap: var(--space-xs);
}
.action-button {
padding: 0.25rem;
padding: var(--space-xs);
background-color: transparent;
color: rgba(255, 255, 255, 0.6);
color: var(--color-text-secondary);
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
transition: all var(--transition-base);
}
.action-button:hover:not(:disabled) {
color: rgba(255, 255, 255, 0.9);
background-color: rgba(255, 255, 255, 0.1);
color: var(--color-text-primary);
background-color: var(--color-active-overlay);
}
.action-button:disabled {
@ -298,27 +298,27 @@
.log-content {
flex: 1;
overflow-y: auto;
padding: 0.5rem;
font-family: 'Courier New', monospace;
font-size: 0.875rem;
padding: var(--space-sm);
font-family: var(--font-mono);
font-size: var(--font-base);
}
.empty-state {
color: rgba(255, 255, 255, 0.4);
color: var(--color-text-tertiary);
text-align: center;
padding: 2rem;
padding: var(--space-2xl);
}
.log-entry {
display: flex;
gap: 0.75rem;
padding: 0.25rem 0.5rem;
color: rgba(255, 255, 255, 0.87);
border-bottom: 1px solid #2a2a2a;
gap: var(--space-md);
padding: var(--space-xs) var(--space-sm);
color: var(--color-text-primary);
border-bottom: 1px solid var(--color-surface-3);
}
.log-entry:hover {
background-color: #252525;
background-color: var(--color-surface-2);
}
.log-entry.error {
@ -331,9 +331,9 @@
}
.log-timestamp {
color: rgba(255, 255, 255, 0.4);
color: var(--color-text-tertiary);
min-width: 6rem;
font-size: 0.75rem;
font-size: var(--font-sm);
}
.log-message {