From acfea7c9e0129168205c374783e7036e5018c9a5 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Sun, 4 Jan 2026 20:58:28 -0800 Subject: Claude: first attempt at code editor --- src/ts/script.ts | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) (limited to 'src/ts/script.ts') diff --git a/src/ts/script.ts b/src/ts/script.ts index 79a9a75..e8502c8 100644 --- a/src/ts/script.ts +++ b/src/ts/script.ts @@ -5,10 +5,14 @@ import 'prismjs/components/prism-markup'; import { initOneko } from './oneko'; type Theme = 'light' | 'dark'; +type EditorView = any; const THEME_STORAGE_KEY = 'theme'; const DARK_THEME_ATTRIBUTE = 'data-theme'; +let editorInstance: EditorView | null = null; +let editorModule: typeof import('./editor') | null = null; + function detectAssetBase(): string { const currentScript = document.currentScript as HTMLScriptElement | null; const scriptSrc = @@ -58,6 +62,10 @@ function initThemeToggle(): void { const nextTheme: Theme = toggleButton.checked ? 'dark' : 'light'; applyTheme(nextTheme); sessionStorage.setItem(THEME_STORAGE_KEY, nextTheme); + + if (editorInstance && editorModule) { + editorModule.setEditorTheme(editorInstance, nextTheme); + } }); } @@ -142,11 +150,116 @@ function initFileInputs(): void { }); } +async function loadEditor() { + if (!editorModule) { + editorModule = await import('./editor'); + } + return editorModule; +} + +function initCodeEditor(): void { + const editorContainer = document.getElementById('code-editor'); + const languageSelect = document.getElementById('language-select'); + + if (!editorContainer || !(languageSelect instanceof HTMLSelectElement)) return; + + const initialCode = { + javascript: `// Welcome to the live code editor! +function greet(name) { + return \`Hello, \${name}! 👋\`; +} + +console.log(greet('World'));`, + css: `/* Try editing this CSS! */ +.retro-box { + background: var(--primary); + color: var(--text); + padding: var(--space-md); + border-radius: var(--border-radius); + box-shadow: var(--shadow-box); +}`, + html: ` + + + + + Retro Page + + +

Hello, World!

+

Welcome to the retro web.

+ +`, + }; + + let editorLoaded = false; + + const currentTheme = getStoredTheme() ?? getSystemTheme(); + + async function createEditorInstance() { + if (editorLoaded) return; + editorLoaded = true; + + const { createEditor } = await loadEditor(); + const language = languageSelect.value as 'javascript' | 'css' | 'html'; + + editorInstance = createEditor({ + parent: editorContainer, + language, + initialCode: initialCode[language], + theme: currentTheme, + }); + } + + // Lazy load on intersection (when editor scrolls into view) + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + createEditorInstance(); + observer.disconnect(); + } + }); + }, + { rootMargin: '100px' } + ); + + observer.observe(editorContainer); + + // Also load on language change + languageSelect.addEventListener('change', async () => { + const language = languageSelect.value as 'javascript' | 'css' | 'html'; + + if (!editorModule) { + await createEditorInstance(); + return; + } + + if (editorInstance && editorContainer) { + editorContainer.innerHTML = ''; + + const { createEditor } = editorModule; + editorInstance = createEditor({ + parent: editorContainer, + language, + initialCode: initialCode[language], + theme: currentTheme, + }); + } + }); +} + function init(): void { setAssetBase(); initThemeToggle(); initFairyDust(); initFileInputs(); + + // Only initialize code editor if the container exists + if (document.getElementById('code-editor')) { + initCodeEditor(); + } + Prism.highlightAll(); initOneko(); } -- cgit v1.2.3-70-g09d2