From e492c03f153b2beb7861c3cff2d4874c313cc083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Forment?= Date: Wed, 15 Oct 2025 01:23:05 +0200 Subject: [PATCH] Cleaning --- src/App.svelte | 394 +++++++--------------- src/lib/Editor.svelte | 33 +- src/lib/EditorSettings.svelte | 4 +- src/lib/EditorWithLogs.svelte | 24 +- src/lib/FileBrowser.svelte | 5 +- src/lib/LogPanel.svelte | 6 +- src/lib/config/templates.ts | 33 ++ src/lib/contexts/app-context.ts | 38 +++ src/lib/csound/index.ts | 4 +- src/lib/csound/store.ts | 25 +- src/lib/project-system/index.ts | 2 +- src/lib/project-system/project-manager.ts | 3 - src/lib/stores/editorSettings.ts | 25 +- src/lib/stores/projectEditor.svelte.ts | 154 +++++++++ src/lib/stores/uiState.svelte.ts | 64 ++++ 15 files changed, 484 insertions(+), 330 deletions(-) create mode 100644 src/lib/config/templates.ts create mode 100644 src/lib/contexts/app-context.ts create mode 100644 src/lib/stores/projectEditor.svelte.ts create mode 100644 src/lib/stores/uiState.svelte.ts diff --git a/src/App.svelte b/src/App.svelte index 1c603b8..cfe6663 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -9,10 +9,13 @@ import ResizablePopup from './lib/ResizablePopup.svelte'; import AudioScope from './lib/AudioScope.svelte'; import Spectrogram from './lib/Spectrogram.svelte'; - import { csound, csoundLogs, type LogEntry } from './lib/csound'; - import { projectManager, type CsoundProject } from './lib/project-system'; import ConfirmDialog from './lib/ConfirmDialog.svelte'; import InputDialog from './lib/InputDialog.svelte'; + import { createCsoundDerivedStores, type LogEntry } from './lib/csound'; + import { type CsoundProject } from './lib/project-system'; + import { uiState } from './lib/stores/uiState.svelte'; + import { DEFAULT_CSOUND_TEMPLATE } from './lib/config/templates'; + import { createAppContext, setAppContext } from './lib/contexts/app-context'; import { PanelLeftClose, PanelLeftOpen, @@ -26,95 +29,15 @@ Activity } from 'lucide-svelte'; - let sidePanelVisible = $state(true); - let sidePanelPosition = $state<'left' | 'right' | 'bottom'>('right'); - let popupVisible = $state(false); - let sharePopupVisible = $state(false); - let shareUrl = $state(''); - let audioPermissionPopupVisible = $state(true); - let scopePopupVisible = $state(false); - let spectrogramPopupVisible = $state(false); + const appContext = createAppContext(); + setAppContext(appContext); + + const { csound, projectManager, editorSettings, projectEditor } = appContext; + const csoundDerived = createCsoundDerivedStores(csound); + let analyserNode = $state(null); - let editorValue = $state(` - --odac - - - -sr = 44100 -ksmps = 32 -nchnls = 2 -0dbfs = 1 - -instr 1 - iFreq = p4 - iAmp = p5 - - ; ADSR envelope - kEnv madsr 0.01, 0.1, 0.6, 0.2 - - ; Sine wave oscillator - aOsc oscili iAmp * kEnv, iFreq - - outs aOsc, aOsc -endin - - - -; Arpeggio: C4 E4 G4 C5 -i 1 0.0 0.5 261.63 0.3 -i 1 0.5 0.5 329.63 0.3 -i 1 1.0 0.5 392.00 0.3 -i 1 1.5 0.5 523.25 0.3 - - -`); let interpreterLogs = $state([]); - - let sidePanelRef: SidePanel; - let editorRef: EditorWithLogs; let fileBrowserRef: FileBrowser; - let currentProjectId = $state(null); - let hasUnsavedChanges = $state(false); - let isNewUnsavedBuffer = $state(false); - let pendingProject: CsoundProject | null = null; - let showUnsavedDialog = $state(false); - let showSaveAsDialog = $state(false); - - const TEMPLATE_CONTENT = ` - --odac - - - -sr = 44100 -ksmps = 32 -nchnls = 2 -0dbfs = 1 - -instr 1 - iFreq = p4 - iAmp = p5 - - ; ADSR envelope - kEnv madsr 0.01, 0.1, 0.6, 0.2 - - ; Sine wave oscillator - aOsc oscili iAmp * kEnv, iFreq - - outs aOsc, aOsc -endin - - - -; Arpeggio: C4 E4 G4 C5 -i 1 0.0 0.5 261.63 0.3 -i 1 0.5 0.5 329.63 0.3 -i 1 1.0 0.5 392.00 0.3 -i 1 1.5 0.5 523.25 0.3 - - -`; onMount(async () => { await projectManager.init(); @@ -124,12 +47,12 @@ i 1 1.5 0.5 523.25 0.3 await projectManager.createProject({ title: 'Template', author: 'System', - content: TEMPLATE_CONTENT, + content: DEFAULT_CSOUND_TEMPLATE, tags: [] }); } - const unsubscribe = csoundLogs.subscribe(logs => { + const unsubscribe = csoundDerived.logs.subscribe(logs => { interpreterLogs = logs; }); @@ -138,183 +61,115 @@ i 1 1.5 0.5 523.25 0.3 }; }); + onDestroy(async () => { + await csound.destroy(); + }); + async function handleEnableAudio() { try { await csound.init(); - audioPermissionPopupVisible = false; + uiState.closeAudioPermission(); } catch (error) { console.error('Failed to initialize audio:', error); } } - onDestroy(async () => { - await csound.destroy(); - }); - - function toggleSidePanel() { - sidePanelVisible = !sidePanelVisible; - } - - function showPopup() { - popupVisible = true; - } - function handleEditorChange(value: string) { - editorValue = value; - hasUnsavedChanges = true; + projectEditor.setContent(value); } function handleNewFile() { - if (hasUnsavedChanges) { - pendingProject = null; - showUnsavedDialog = true; + const needsConfirm = projectEditor.requestSwitch( + () => projectEditor.createNew(DEFAULT_CSOUND_TEMPLATE), + handleSwitchConfirm + ); + + if (needsConfirm) { + uiState.showUnsavedChangesDialog(); + } + } + + function handleFileSelect(project: CsoundProject | null) { + if (!project) return; + + const needsConfirm = projectEditor.requestSwitch( + () => projectEditor.loadProject(project), + handleSwitchConfirm + ); + + if (needsConfirm) { + uiState.showUnsavedChangesDialog(); + } + } + + async function handleExecute(code: string) { + try { + await csound.evaluate(code); + } catch (error) { + console.error('Execution error:', error); + } + } + + async function handleSave() { + if (projectEditor.isNewUnsavedBuffer) { + uiState.showSaveAsDialog(); return; } - createNewBuffer(); - } - - function createNewBuffer() { - currentProjectId = null; - editorValue = TEMPLATE_CONTENT; - hasUnsavedChanges = false; - isNewUnsavedBuffer = true; - if (editorRef) { - editorRef.setValue(TEMPLATE_CONTENT); - } - } - - async function handleFileSelect(project: CsoundProject | null) { - if (hasUnsavedChanges) { - pendingProject = project; - showUnsavedDialog = true; - return; - } - - if (project) { - loadProject(project); - } - } - - function loadProject(project: CsoundProject) { - currentProjectId = project.id; - editorValue = project.content; - hasUnsavedChanges = false; - isNewUnsavedBuffer = false; - if (editorRef) { - editorRef.setValue(project.content); - } - } - - async function saveCurrentProject() { - if (isNewUnsavedBuffer) { - showSaveAsDialog = true; - return; - } - - if (!currentProjectId) return; - - const result = await projectManager.updateProject({ - id: currentProjectId, - content: editorValue - }); - - if (result.success) { - hasUnsavedChanges = false; - if (fileBrowserRef) { - fileBrowserRef.refresh(); - } + const success = await projectEditor.save(); + if (success) { + fileBrowserRef?.refresh(); } } async function handleSaveAs(title: string) { - const finalTitle = title.trim() || 'Untitled'; - - const result = await projectManager.createProject({ - title: finalTitle, - author: 'Anonymous', - content: editorValue, - tags: [] - }); - - if (result.success) { - currentProjectId = result.data.id; - hasUnsavedChanges = false; - isNewUnsavedBuffer = false; - if (fileBrowserRef) { - fileBrowserRef.refresh(); - } + const success = await projectEditor.saveAs(title); + if (success) { + fileBrowserRef?.refresh(); + uiState.hideSaveAsDialog(); } } async function handleMetadataUpdate(projectId: string, updates: { title?: string; author?: string }) { - const result = await projectManager.updateProject({ - id: projectId, - ...updates - }); - - if (result.success && fileBrowserRef) { - fileBrowserRef.refresh(); + const success = await projectEditor.updateMetadata(updates); + if (success) { + fileBrowserRef?.refresh(); } } - function handleSaveAndSwitch() { - saveCurrentProject().then(() => { - if (pendingProject) { - loadProject(pendingProject); + function handleSwitchConfirm(action: 'save' | 'discard') { + if (action === 'save') { + if (projectEditor.isNewUnsavedBuffer) { + uiState.hideUnsavedChangesDialog(); + uiState.showSaveAsDialog(); } else { - createNewBuffer(); + projectEditor.handleSaveAndSwitch().then(() => { + fileBrowserRef?.refresh(); + uiState.hideUnsavedChangesDialog(); + }); } - pendingProject = null; - }); - } - - function handleDiscardAndSwitch() { - if (pendingProject) { - loadProject(pendingProject); } else { - createNewBuffer(); - } - pendingProject = null; - } - - function cyclePanelPosition() { - if (sidePanelPosition === 'right') { - sidePanelPosition = 'left'; - } else if (sidePanelPosition === 'left') { - sidePanelPosition = 'bottom'; - } else { - sidePanelPosition = 'right'; + projectEditor.handleDiscardAndSwitch(); + uiState.hideUnsavedChangesDialog(); } } async function handleShare() { - if (!currentProjectId) return; + if (!projectEditor.currentProjectId) return; - const result = await projectManager.exportProjectToUrl(currentProjectId); + const result = await projectManager.exportProjectToUrl(projectEditor.currentProjectId); if (result.success) { - shareUrl = result.data; - try { - await navigator.clipboard.writeText(shareUrl); + await navigator.clipboard.writeText(result.data); } catch (err) { console.error('Failed to copy to clipboard:', err); } - - sharePopupVisible = true; + uiState.showShare(result.data); } } - function handleOpenScope() { - scopePopupVisible = true; - } - - function handleOpenSpectrogram() { - spectrogramPopupVisible = true; - } - $effect(() => { - if (scopePopupVisible || spectrogramPopupVisible) { + if (uiState.scopePopupVisible || uiState.spectrogramPopupVisible) { const interval = setInterval(() => { analyserNode = csound.getAnalyserNode(); }, 100); @@ -344,10 +199,11 @@ i 1 1.5 0.5 523.25 0.3 {#snippet filesTabContent()} {/snippet} @@ -356,53 +212,53 @@ i 1 1.5 0.5 523.25 0.3 {#snippet leftActions()} {/snippet} - - -
- {#if sidePanelPosition === 'left'} +
+ {#if uiState.sidePanelPosition === 'left'} {/if}
- {#if sidePanelPosition === 'right'} + {#if uiState.sidePanelPosition === 'right'} {/if} - {#if sidePanelPosition === 'bottom'} + {#if uiState.sidePanelPosition === 'bottom'} - -

This is a popup!

-

You can drag it around by the header.

-

It stays on top of everything else.

-
- handleSwitchConfirm('save')} + onCancel={() => handleSwitchConfirm('discard')} /> + diff --git a/src/lib/Editor.svelte b/src/lib/Editor.svelte index ffa4ae5..69764bc 100644 --- a/src/lib/Editor.svelte +++ b/src/lib/Editor.svelte @@ -13,19 +13,22 @@ import { css } from '@codemirror/lang-css'; import { oneDark } from '@codemirror/theme-one-dark'; import { vim } from '@replit/codemirror-vim'; - import { editorSettings } from './stores/editorSettings'; - import { csound } from './csound'; + import type { EditorSettingsStore } from './stores/editorSettings'; interface Props { - initialValue?: string; + value: string; language?: 'javascript' | 'html' | 'css'; onChange?: (value: string) => void; + onExecute?: (code: string) => void; + editorSettings: EditorSettingsStore; } let { - initialValue = '', + value = '', language = 'javascript', - onChange + onChange, + onExecute, + editorSettings }: Props = $props(); let editorContainer: HTMLDivElement; @@ -45,10 +48,10 @@ { key: 'Mod-e', run: (view) => { - const code = view.state.doc.toString(); - csound.evaluate(code).catch(err => { - console.error('Evaluation error:', err); - }); + if (onExecute) { + const code = view.state.doc.toString(); + onExecute(code); + } return true; } } @@ -84,7 +87,7 @@ ]; editorView = new EditorView({ - doc: initialValue, + doc: value, extensions: [ ...baseExtensions, languageExtensions[language], @@ -134,17 +137,13 @@ } }); - export function getValue(): string { - return editorView?.state.doc.toString() || ''; - } - - export function setValue(value: string): void { - if (editorView) { + $effect(() => { + if (editorView && value !== editorView.state.doc.toString()) { editorView.dispatch({ changes: { from: 0, to: editorView.state.doc.length, insert: value } }); } - } + });
diff --git a/src/lib/EditorSettings.svelte b/src/lib/EditorSettings.svelte index ba04c59..01b7f66 100644 --- a/src/lib/EditorSettings.svelte +++ b/src/lib/EditorSettings.svelte @@ -1,5 +1,7 @@
diff --git a/src/lib/FileBrowser.svelte b/src/lib/FileBrowser.svelte index 05d124c..84ddee0 100644 --- a/src/lib/FileBrowser.svelte +++ b/src/lib/FileBrowser.svelte @@ -1,18 +1,19 @@