diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 4a3a5f6..cc16f23 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -8,16 +8,12 @@ function codeBlockRunPlugin(md) { const info = token.info.trim() const content = token.content - // Check if the code block has a 'run' attribute if (info.includes('run')) { - // Remove 'run' from info for standard rendering const cleanInfo = info.replace(/\s*run\s*/, '').trim() token.info = cleanInfo - // Render the standard code block const codeHtml = defaultFence(tokens, idx, options, env, self) - // Wrap with run button - no language badge since we hide it anyway return `
diff --git a/docs/.vitepress/theme/components/BasaltDemo.vue b/docs/.vitepress/theme/components/BasaltDemo.vue index ee81845..5c8919c 100644 --- a/docs/.vitepress/theme/components/BasaltDemo.vue +++ b/docs/.vitepress/theme/components/BasaltDemo.vue @@ -10,13 +10,18 @@ let isDragging = false const slots = useSlots() let luaCode = '' + onMounted(() => { + if (typeof window === 'undefined') return + luaCode = (slots.default?.() || []) .map(vnode => typeof vnode.children === 'string' ? vnode.children : '') .join('\n') }) async function startDemo() { + if (typeof window === 'undefined' || typeof document === 'undefined') return + showDemo.value = true const basalt = await fetch( @@ -47,6 +52,8 @@ function closeDemo() { } function startDrag(e) { + if (typeof document === 'undefined') return + isDragging = true offset.x = e.clientX - position.x offset.y = e.clientY - position.y @@ -55,32 +62,30 @@ function startDrag(e) { } function onDrag(e) { - if (isDragging) { - // Containergröße ermitteln - const containerEl = container.value?.parentElement - const contW = containerEl?.offsetWidth || 0 - const contH = containerEl?.offsetHeight || 0 + if (!isDragging || typeof window === 'undefined') return + + const containerEl = container.value?.parentElement + const contW = containerEl?.offsetWidth || 0 + const contH = containerEl?.offsetHeight || 0 - // Maximal erlaubte Positionen - const maxX = window.innerWidth - contW - const maxY = window.innerHeight - contH + const maxX = window.innerWidth - contW + const maxY = window.innerHeight - contH - // Neue Position berechnen - let newX = e.clientX - offset.x - let newY = e.clientY - offset.y + let newX = e.clientX - offset.x + let newY = e.clientY - offset.y - // Begrenzen (clampen) - if (newX < 0) newX = 0 - if (newY < 0) newY = 0 - if (newX > maxX) newX = maxX - if (newY > maxY) newY = maxY + if (newX < 0) newX = 0 + if (newY < 0) newY = 0 + if (newX > maxX) newX = maxX + if (newY > maxY) newY = maxY - position.x = newX - position.y = newY - } + position.x = newX + position.y = newY } function stopDrag() { + if (typeof document === 'undefined') return + isDragging = false document.removeEventListener('mousemove', onDrag) document.removeEventListener('mouseup', stopDrag) @@ -175,4 +180,4 @@ function stopDrag() { top: 0; left: 0; } - + \ No newline at end of file diff --git a/docs/.vitepress/theme/components/BasaltDemoWithCode.vue b/docs/.vitepress/theme/components/BasaltDemoWithCode.vue index 8647610..9e92c96 100644 --- a/docs/.vitepress/theme/components/BasaltDemoWithCode.vue +++ b/docs/.vitepress/theme/components/BasaltDemoWithCode.vue @@ -40,7 +40,6 @@ function extractText(nodes) { const luaCode = computed(() => extractText(slots.default?.() ?? [])) - const highlightedCode = computed(() => { let code = luaCode.value @@ -61,6 +60,7 @@ const highlightedCode = computed(() => { }) async function startDemo() { + if (typeof window === 'undefined') return if (isLoading.value || showDemo.value) return isLoading.value = true @@ -133,6 +133,8 @@ function closeDemo() { } function centerWindow() { + if (typeof window === 'undefined') return + const windowWidth = window.innerWidth const windowHeight = window.innerHeight position.x = Math.max(0, (windowWidth - 650) / 2) @@ -140,6 +142,8 @@ function centerWindow() { } function startDrag(e) { + if (typeof document === 'undefined') return + if (e.target.closest('button')) return isDragging = true offset.x = e.clientX - position.x @@ -150,7 +154,8 @@ function startDrag(e) { } function onDrag(e) { - if (!isDragging) return + if (!isDragging || typeof window === 'undefined') return + const maxX = window.innerWidth - 650 const maxY = window.innerHeight - 480 @@ -159,6 +164,8 @@ function onDrag(e) { } function stopDrag() { + if (typeof document === 'undefined') return + isDragging = false document.removeEventListener('mousemove', onDrag) document.removeEventListener('mouseup', stopDrag) @@ -171,11 +178,17 @@ function handleKeydown(e) { } onMounted(() => { - document.addEventListener('keydown', handleKeydown) + // SSR Guard - nur im Browser Event Listener hinzufügen + if (typeof document !== 'undefined') { + document.addEventListener('keydown', handleKeydown) + } }) onUnmounted(() => { - document.removeEventListener('keydown', handleKeydown) + // SSR Guard + if (typeof document !== 'undefined') { + document.removeEventListener('keydown', handleKeydown) + } closeDemo() }) @@ -197,13 +210,12 @@ onUnmounted(() => {
-
- +
res.text()) + let globalComputerInstance = null + let isGlobalLoading = false - if (!window.require) { - await new Promise((resolve, reject) => { - const script = document.createElement('script') - script.src = 'https://copy-cat.squiddev.cc/require.js' - script.onload = resolve - script.onerror = reject - document.body.appendChild(script) - }) - } + async function loadDependencies() { + const basalt = await fetch( + 'https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/release/basalt.lua' + ).then(res => res.text()) - return basalt -} - -async function runCodeInEmulator(code, title = 'Code Demo') { - console.log('runCodeInEmulator called with:', { code, title }) - - if (isGlobalLoading || globalComputerInstance) { - console.warn('Emulator already running') - return - } - - isGlobalLoading = true - console.log('Starting emulator loading...') - - try { - console.log('Loading dependencies...') - const basalt = await loadDependencies() - console.log('Dependencies loaded, basalt length:', basalt.length) - - const tempContainer = document.createElement('div') - tempContainer.style.position = 'fixed' - tempContainer.style.top = '-9999px' - tempContainer.style.left = '-9999px' - tempContainer.style.width = '650px' - tempContainer.style.height = '480px' - tempContainer.style.padding = '0' - tempContainer.style.margin = '0' - tempContainer.style.border = 'none' - document.body.appendChild(tempContainer) - console.log('Temporary container created') - - console.log('Setting up CopyCat...') - window.require.config({ paths: { copycat: 'https://copy-cat.squiddev.cc/' } }) - - window.require(['copycat/embed'], (setup) => { - console.log('CopyCat setup function received:', setup) - - const setupPromise = setup(tempContainer, { - hdFont: 'https://copy-cat.squiddev.cc/term_font_hd-0506b6efe5f7feae.png', - files: { - 'startup.lua': code, - 'basalt.lua': basalt - }, - label: title + if (!window.require) { + await new Promise((resolve, reject) => { + const script = document.createElement('script') + script.src = 'https://copy-cat.squiddev.cc/require.js' + script.onload = resolve + script.onerror = reject + document.body.appendChild(script) }) + } - console.log('Setup promise created:', setupPromise) + return basalt + } - if (setupPromise && typeof setupPromise.then === 'function') { - setupPromise.then((computer) => { - console.log('Computer instance resolved from promise:', computer) - globalComputerInstance = computer + async function runCodeInEmulator(code, title = 'Code Demo') { + console.log('runCodeInEmulator called with:', { code, title }) - if (computer && typeof computer.run === 'function') { - computer.run() - console.log('Computer started running') - } else if (computer && typeof computer.start === 'function') { - computer.start() - console.log('Computer started with start()') + if (isGlobalLoading || globalComputerInstance) { + console.warn('Emulator already running') + return + } + + isGlobalLoading = true + console.log('Starting emulator loading...') + + try { + console.log('Loading dependencies...') + const basalt = await loadDependencies() + console.log('Dependencies loaded, basalt length:', basalt.length) + + const tempContainer = document.createElement('div') + tempContainer.style.position = 'fixed' + tempContainer.style.top = '-9999px' + tempContainer.style.left = '-9999px' + tempContainer.style.width = '650px' + tempContainer.style.height = '480px' + tempContainer.style.padding = '0' + tempContainer.style.margin = '0' + tempContainer.style.border = 'none' + document.body.appendChild(tempContainer) + window.require.config({ paths: { copycat: 'https://copy-cat.squiddev.cc/' } }) + + window.require(['copycat/embed'], (setup) => { + + const setupPromise = setup(tempContainer, { + hdFont: 'https://copy-cat.squiddev.cc/term_font_hd-0506b6efe5f7feae.png', + files: { + 'startup.lua': code, + 'basalt.lua': basalt + }, + label: title + }) + + console.log('Setup promise created:', setupPromise) + + if (setupPromise && typeof setupPromise.then === 'function') { + setupPromise.then((computer) => { + console.log('Computer instance resolved from promise:', computer) + globalComputerInstance = computer + + if (computer && typeof computer.run === 'function') { + computer.run() + console.log('Computer started running') + } else if (computer && typeof computer.start === 'function') { + computer.start() + console.log('Computer started with start()') + } else { + console.error('Computer does not have run or start method:', computer) + console.log('Available methods:', Object.getOwnPropertyNames(computer || {})) + } + + console.log('Showing terminal window...') + showTerminalWindow(tempContainer, title) + + isGlobalLoading = false + console.log('Emulator setup complete') + }).catch((error) => { + console.error('Error in setup promise:', error) + isGlobalLoading = false + }) + } else { + console.log('Setup returned directly:', setupPromise) + globalComputerInstance = setupPromise + + if (setupPromise && typeof setupPromise.run === 'function') { + setupPromise.run() + console.log('Computer started running (direct)') } else { - console.error('Computer does not have run or start method:', computer) - console.log('Available methods:', Object.getOwnPropertyNames(computer || {})) + console.error('Direct setup does not have run method:', setupPromise) } - console.log('Showing terminal window...') showTerminalWindow(tempContainer, title) - isGlobalLoading = false - console.log('Emulator setup complete') - }).catch((error) => { - console.error('Error in setup promise:', error) - isGlobalLoading = false - }) - } else { - console.log('Setup returned directly:', setupPromise) - globalComputerInstance = setupPromise - - if (setupPromise && typeof setupPromise.run === 'function') { - setupPromise.run() - console.log('Computer started running (direct)') - } else { - console.error('Direct setup does not have run method:', setupPromise) } + }) - showTerminalWindow(tempContainer, title) - isGlobalLoading = false - } + } catch (error) { + console.error('Error starting emulator:', error) + isGlobalLoading = false + } + } + + function showTerminalWindow(container, title) { + console.log('showTerminalWindow called with:', { container, title }) + + const windowDiv = document.createElement('div') + windowDiv.className = 'global-terminal-window' + console.log('Terminal window div created') + + windowDiv.style.cssText = ` + position: fixed; + width: 625px; + height: 425px; + background: #1a1a1a; + border-radius: 8px; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); + display: flex; + flex-direction: column; + z-index: 9999; + border: 1px solid #333; + top: 100px; + left: 100px; + ` + + const header = document.createElement('div') + header.className = 'terminal-header' + header.style.cssText = ` + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.2rem 1rem; + background: linear-gradient(180deg, #2a2a2a 0%, #222 100%); + border-bottom: 1px solid #111; + cursor: move; + user-select: none; + border-radius: 8px 8px 0 0; + ` + + const titleDiv = document.createElement('div') + titleDiv.innerHTML = `💻 ${title}` + + const controls = document.createElement('div') + controls.innerHTML = ` + + ` + + header.appendChild(titleDiv) + header.appendChild(controls) + + const body = document.createElement('div') + body.style.cssText = ` + flex: 1; + background: #000; + border-radius: 0 0 8px 8px; + overflow: hidden; + padding: 0; + margin: 0; + ` + body.appendChild(container) + container.style.position = 'static' + container.style.top = 'auto' + container.style.left = 'auto' + container.style.width = '100%' + container.style.height = '100%' + container.style.padding = '0' + container.style.margin = '0' + + windowDiv.appendChild(header) + windowDiv.appendChild(body) + + document.body.appendChild(windowDiv) + console.log('Terminal window added to body') + + let isDragging = false + let offset = { x: 0, y: 0 } + + header.addEventListener('mousedown', (e) => { + isDragging = true + offset.x = e.clientX - windowDiv.offsetLeft + offset.y = e.clientY - windowDiv.offsetTop }) - } catch (error) { - console.error('Error starting emulator:', error) - isGlobalLoading = false + document.addEventListener('mousemove', (e) => { + if (!isDragging) return + + const terminalWidth = windowDiv.offsetWidth + const terminalHeight = windowDiv.offsetHeight + + let newX = e.clientX - offset.x + let newY = e.clientY - offset.y + + const maxX = window.innerWidth - terminalWidth + const maxY = window.innerHeight - terminalHeight + + newX = Math.max(0, Math.min(newX, maxX)) + newY = Math.max(0, Math.min(newY, maxY)) + + windowDiv.style.left = newX + 'px' + windowDiv.style.top = newY + 'px' + }) + + document.addEventListener('mouseup', () => { + isDragging = false + }) } -} -function showTerminalWindow(container, title) { - console.log('showTerminalWindow called with:', { container, title }) - - const windowDiv = document.createElement('div') - windowDiv.className = 'global-terminal-window' - console.log('Terminal window div created') - - windowDiv.style.cssText = ` - position: fixed; - width: 625px; - height: 425px; - background: #1a1a1a; - border-radius: 8px; - box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); - display: flex; - flex-direction: column; - z-index: 9999; - border: 1px solid #333; - top: 100px; - left: 100px; - ` - - const header = document.createElement('div') - header.className = 'terminal-header' - header.style.cssText = ` - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.2rem 1rem; - background: linear-gradient(180deg, #2a2a2a 0%, #222 100%); - border-bottom: 1px solid #111; - cursor: move; - user-select: none; - border-radius: 8px 8px 0 0; - ` - - const titleDiv = document.createElement('div') - titleDiv.innerHTML = `💻 ${title}` - - const controls = document.createElement('div') - controls.innerHTML = ` - - ` - - header.appendChild(titleDiv) - header.appendChild(controls) - - const body = document.createElement('div') - body.style.cssText = ` - flex: 1; - background: #000; - border-radius: 0 0 8px 8px; - overflow: hidden; - padding: 0; /* <-- REDUCED FROM DEFAULT */ - margin: 0; /* <-- NO MARGIN */ - ` - body.appendChild(container) - container.style.position = 'static' - container.style.top = 'auto' - container.style.left = 'auto' - container.style.width = '100%' - container.style.height = '100%' - container.style.padding = '0' - container.style.margin = '0' - - windowDiv.appendChild(header) - windowDiv.appendChild(body) - - document.body.appendChild(windowDiv) - console.log('Terminal window added to body') - - let isDragging = false - let offset = { x: 0, y: 0 } - - header.addEventListener('mousedown', (e) => { - isDragging = true - offset.x = e.clientX - windowDiv.offsetLeft - offset.y = e.clientY - windowDiv.offsetTop - }) - - document.addEventListener('mousemove', (e) => { - if (!isDragging) return - - const terminalWidth = windowDiv.offsetWidth - const terminalHeight = windowDiv.offsetHeight - - let newX = e.clientX - offset.x - let newY = e.clientY - offset.y - - const maxX = window.innerWidth - terminalWidth - const maxY = window.innerHeight - terminalHeight - - newX = Math.max(0, Math.min(newX, maxX)) - newY = Math.max(0, Math.min(newY, maxY)) - - windowDiv.style.left = newX + 'px' - windowDiv.style.top = newY + 'px' - }) - - document.addEventListener('mouseup', () => { - isDragging = false - }) -} - -function closeGlobalEmulator() { - if (globalComputerInstance) { - try { - globalComputerInstance.shutdown() - } catch (e) { - console.warn('Error shutting down:', e) + function closeGlobalEmulator() { + if (globalComputerInstance) { + try { + globalComputerInstance.shutdown() + } catch (e) { + console.warn('Error shutting down:', e) + } + globalComputerInstance = null + } + + const windowDiv = document.querySelector('.global-terminal-window') + if (windowDiv) { + document.body.removeChild(windowDiv) } - globalComputerInstance = null } - const windowDiv = document.querySelector('.global-terminal-window') - if (windowDiv) { - document.body.removeChild(windowDiv) + window.runCodeBlock = function(button) { + const container = button.closest('.code-block-with-run') + const codeContent = container.querySelector('.code-content') + const dataCode = codeContent.getAttribute('data-code') + const code = atob(dataCode) + const languageBadge = container.querySelector('.language-badge') + const language = languageBadge && languageBadge.textContent ? languageBadge.textContent : 'lua' + runCodeInEmulator(code, `Code Demo (${language})`) } -} -window.runCodeBlock = function(button) { - console.log('Run button clicked!', button) - - const container = button.closest('.code-block-with-run') - console.log('Container found:', container) - - const codeContent = container.querySelector('.code-content') - console.log('Code content found:', codeContent) - - const dataCode = codeContent.getAttribute('data-code') - console.log('Data code:', dataCode) - - const code = atob(dataCode) - console.log('Decoded code:', code) - - const languageBadge = container.querySelector('.language-badge') - const language = languageBadge && languageBadge.textContent ? languageBadge.textContent : 'lua' - console.log('Language:', language) - - console.log('Calling runCodeInEmulator...') - runCodeInEmulator(code, `Code Demo (${language})`) -} - -window.closeGlobalEmulator = closeGlobalEmulator + window.closeGlobalEmulator = closeGlobalEmulator +} \ No newline at end of file diff --git a/docs/.vitepress/theme/index.js b/docs/.vitepress/theme/index.js index a72e5d3..e3e9ec0 100644 --- a/docs/.vitepress/theme/index.js +++ b/docs/.vitepress/theme/index.js @@ -1,17 +1,50 @@ import CopyButton from 'vitepress-copy-helper'; import 'vitepress-copy-helper/style.css' import DefaultTheme from 'vitepress/theme' -import BasaltDemo from './components/BasaltDemo.vue' -import BasaltDemoWithCode from './components/BasaltDemoWithCode.vue' -import './emulator.js' import './styles.css' /** @type {import('vitepress').Theme} */ export default { extends: DefaultTheme, - enhanceApp({ app }) { + enhanceApp({ app, router, siteData }) { app.component('C', CopyButton) - app.component('BasaltDemo', BasaltDemo) - app.component('BasaltDemoWithCode', BasaltDemoWithCode) + + if (typeof window !== 'undefined') { + import('./components/BasaltDemo.vue').then((module) => { + app.component('BasaltDemo', module.default) + }) + import('./components/BasaltDemoWithCode.vue').then((module) => { + app.component('BasaltDemoWithCode', module.default) + }) + } + }, + setup() { + if (typeof window !== 'undefined') { + window.runCodeBlock = function(button) { + const container = button.closest('.code-block-with-run') + const codeContent = container.querySelector('.code-content') + const dataCode = codeContent.getAttribute('data-code') + const code = atob(dataCode) + const languageBadge = container.querySelector('.language-badge') + const language = languageBadge && languageBadge.textContent ? languageBadge.textContent : 'lua' + + if (!window.runCodeInEmulator) { + import('./emulator.js').then(({ initEmulator }) => { + initEmulator() + setTimeout(() => window.runCodeBlock(button), 100) + }) + } else { + window.runCodeInEmulator(code, `Code Demo (${language})`) + } + } + + import('vue').then(({ onMounted }) => { + onMounted(() => { + import('./emulator.js').then(({ initEmulator }) => { + initEmulator() + }) + }) + }) + } } } \ No newline at end of file