diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/css/style.css | 8 | ||||
| -rw-r--r-- | src/index.html | 2 | ||||
| -rw-r--r-- | src/ts/editor-standalone.ts | 74 | ||||
| -rw-r--r-- | src/ts/editor.ts | 108 | ||||
| -rw-r--r-- | src/ts/script.ts | 113 |
5 files changed, 141 insertions, 164 deletions
diff --git a/src/css/style.css b/src/css/style.css index 48d964e..4c83cb0 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -635,8 +635,8 @@ nav a:active { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; - box-shadow: inset 1px 1px 0 var(--border-light), inset -1px -1px 0 var(--border-dark), 2px 2px 0 - rgba(0, 0, 0, 0.12); + box-shadow: inset 1px 1px 0 var(--border-light), inset -1px -1px 0 var(--border-dark), 2px + 2px 0 rgba(0, 0, 0, 0.12); } th, @@ -646,8 +646,8 @@ nav a:active { pre { padding: var(--space-sm); - box-shadow: inset 1px 1px 0 var(--border-light), inset -1px -1px 0 var(--border-dark), 2px 2px 0 - rgba(0, 0, 0, 0.12); + box-shadow: inset 1px 1px 0 var(--border-light), inset -1px -1px 0 var(--border-dark), 2px + 2px 0 rgba(0, 0, 0, 0.12); } } diff --git a/src/index.html b/src/index.html index 511e113..36590ff 100644 --- a/src/index.html +++ b/src/index.html @@ -537,7 +537,7 @@ retro(); // "That's totally rad!"</code></pre> </main> <footer> - <p>© 2025 Liz CSS Framework. Made with coffee and retro vibes.</p> + <p>hai</p> </footer> <script type="module" src="/script.js"></script> diff --git a/src/ts/editor-standalone.ts b/src/ts/editor-standalone.ts new file mode 100644 index 0000000..2c8ec81 --- /dev/null +++ b/src/ts/editor-standalone.ts @@ -0,0 +1,74 @@ +import { createEditor, setEditorTheme } from './editor'; + +// Global API +const adelieEditor = { + /** + * Initialize an editor in the given element + * @param element - The container element or selector + * @param options - Editor configuration + */ + init( + element: HTMLElement | string, + options?: { + language?: 'javascript' | 'css' | 'html'; + initialCode?: string; + theme?: 'light' | 'dark'; + } + ) { + const container = + typeof element === 'string' ? document.querySelector<HTMLElement>(element) : element; + + if (!container) { + throw new Error('Editor container not found'); + } + + // Auto-detect theme if not specified + const theme = + options?.theme || + (document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'); + + const view = createEditor({ + parent: container, + language: options?.language || 'javascript', + initialCode: options?.initialCode || '', + theme, + }); + + // Listen for theme changes + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.attributeName === 'data-theme') { + const newTheme = + document.documentElement.getAttribute('data-theme') === 'dark' + ? 'dark' + : 'light'; + setEditorTheme(view, newTheme); + } + }); + }); + + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['data-theme'], + }); + + return view; + }, + + /** + * Create an editor with full control + */ + create: createEditor, + + /** + * Change editor theme + */ + setTheme: setEditorTheme, +}; + +// Export to window +if (typeof window !== 'undefined') { + (window as any).adelieEditor = adelieEditor; +} + +export default adelieEditor; diff --git a/src/ts/editor.ts b/src/ts/editor.ts index 2d2a3da..ebc6b9b 100644 --- a/src/ts/editor.ts +++ b/src/ts/editor.ts @@ -61,7 +61,10 @@ function highlightWhitespace() { // Relative line numbers that update on cursor movement class RelativeLineNumberMarker extends GutterMarker { - constructor(private lineNo: number, private currentLine: number) { + constructor( + private lineNo: number, + private currentLine: number + ) { super(); } @@ -184,50 +187,53 @@ const lightTheme = EditorView.theme({ }, }); -const darkTheme = EditorView.theme({ - '&': { - backgroundColor: 'var(--surface)', - color: 'var(--text)', - }, - '.cm-content': { - caretColor: 'var(--primary)', - fontFamily: 'var(--font-mono)', - fontSize: '0.875rem', - paddingLeft: '0', - }, - '.cm-gutters': { - backgroundColor: 'var(--bg)', - color: 'var(--muted)', - border: 'none', - borderRight: '1px solid var(--border)', - }, - '.cm-activeLineGutter': { - backgroundColor: 'rgba(229, 106, 166, 0.2)', - color: 'var(--text)', - }, - '.cm-activeLine': { - backgroundColor: 'rgba(240, 106, 166, 0.08)', - }, - '.cm-selectionBackground': { - backgroundColor: 'rgba(240, 106, 166, 0.45) !important', - }, - '&.cm-focused .cm-selectionBackground': { - backgroundColor: 'rgba(240, 106, 166, 0.45) !important', - }, - '&.cm-focused .cm-selectionMatch': { - backgroundColor: 'rgba(182, 156, 255, 0.35) !important', - }, - '.cm-cursor': { - borderLeftColor: 'var(--primary)', - }, - '.cm-whitespace::before': { - content: '"·"', - position: 'absolute', - opacity: '0.25', - color: 'var(--muted)', - pointerEvents: 'none', +const darkTheme = EditorView.theme( + { + '&': { + backgroundColor: 'var(--surface)', + color: 'var(--text)', + }, + '.cm-content': { + caretColor: 'var(--primary)', + fontFamily: 'var(--font-mono)', + fontSize: '0.875rem', + paddingLeft: '0', + }, + '.cm-gutters': { + backgroundColor: 'var(--bg)', + color: 'var(--muted)', + border: 'none', + borderRight: '1px solid var(--border)', + }, + '.cm-activeLineGutter': { + backgroundColor: 'rgba(229, 106, 166, 0.2)', + color: 'var(--text)', + }, + '.cm-activeLine': { + backgroundColor: 'rgba(240, 106, 166, 0.08)', + }, + '.cm-selectionBackground': { + backgroundColor: 'rgba(240, 106, 166, 0.45) !important', + }, + '&.cm-focused .cm-selectionBackground': { + backgroundColor: 'rgba(240, 106, 166, 0.45) !important', + }, + '&.cm-focused .cm-selectionMatch': { + backgroundColor: 'rgba(182, 156, 255, 0.35) !important', + }, + '.cm-cursor': { + borderLeftColor: 'var(--primary)', + }, + '.cm-whitespace::before': { + content: '"·"', + position: 'absolute', + opacity: '0.25', + color: 'var(--muted)', + pointerEvents: 'none', + }, }, -}, { dark: true }); + { dark: true } +); interface EditorOptions { parent: HTMLElement; @@ -254,9 +260,10 @@ export function createEditor(options: EditorOptions): EditorView { highlightWhitespace(), vim(), languageExtension(), - themeConfig.of(theme === 'dark' - ? [darkTheme, syntaxHighlighting(darkHighlighting)] - : [lightTheme, syntaxHighlighting(lightHighlighting)] + themeConfig.of( + theme === 'dark' + ? [darkTheme, syntaxHighlighting(darkHighlighting)] + : [lightTheme, syntaxHighlighting(lightHighlighting)] ), ], }); @@ -271,9 +278,10 @@ export function createEditor(options: EditorOptions): EditorView { export function setEditorTheme(view: EditorView, theme: 'light' | 'dark'): void { view.dispatch({ - effects: themeConfig.reconfigure(theme === 'dark' - ? [darkTheme, syntaxHighlighting(darkHighlighting)] - : [lightTheme, syntaxHighlighting(lightHighlighting)] + effects: themeConfig.reconfigure( + theme === 'dark' + ? [darkTheme, syntaxHighlighting(darkHighlighting)] + : [lightTheme, syntaxHighlighting(lightHighlighting)] ), }); } diff --git a/src/ts/script.ts b/src/ts/script.ts index e8502c8..8aff107 100644 --- a/src/ts/script.ts +++ b/src/ts/script.ts @@ -3,15 +3,15 @@ import 'prismjs/components/prism-css'; import 'prismjs/components/prism-javascript'; import 'prismjs/components/prism-markup'; import { initOneko } from './oneko'; +import { createEditor, setEditorTheme } from './editor'; +import type { EditorView } from 'codemirror'; 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; @@ -63,8 +63,8 @@ function initThemeToggle(): void { applyTheme(nextTheme); sessionStorage.setItem(THEME_STORAGE_KEY, nextTheme); - if (editorInstance && editorModule) { - editorModule.setEditorTheme(editorInstance, nextTheme); + if (editorInstance) { + setEditorTheme(editorInstance, nextTheme); } }); } @@ -150,116 +150,11 @@ 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: `<!-- Try editing this HTML! --> -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <title>Retro Page</title> -</head> -<body> - <h1>Hello, World!</h1> - <p>Welcome to the retro web.</p> -</body> -</html>`, - }; - - 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(); } |
