SSR fixes
This commit is contained in:
@@ -8,16 +8,12 @@ function codeBlockRunPlugin(md) {
|
|||||||
const info = token.info.trim()
|
const info = token.info.trim()
|
||||||
const content = token.content
|
const content = token.content
|
||||||
|
|
||||||
// Check if the code block has a 'run' attribute
|
|
||||||
if (info.includes('run')) {
|
if (info.includes('run')) {
|
||||||
// Remove 'run' from info for standard rendering
|
|
||||||
const cleanInfo = info.replace(/\s*run\s*/, '').trim()
|
const cleanInfo = info.replace(/\s*run\s*/, '').trim()
|
||||||
token.info = cleanInfo
|
token.info = cleanInfo
|
||||||
|
|
||||||
// Render the standard code block
|
|
||||||
const codeHtml = defaultFence(tokens, idx, options, env, self)
|
const codeHtml = defaultFence(tokens, idx, options, env, self)
|
||||||
|
|
||||||
// Wrap with run button - no language badge since we hide it anyway
|
|
||||||
return `
|
return `
|
||||||
<div class="code-block-with-run">
|
<div class="code-block-with-run">
|
||||||
<div class="code-header">
|
<div class="code-header">
|
||||||
|
|||||||
@@ -10,13 +10,18 @@ let isDragging = false
|
|||||||
|
|
||||||
const slots = useSlots()
|
const slots = useSlots()
|
||||||
let luaCode = ''
|
let luaCode = ''
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if (typeof window === 'undefined') return
|
||||||
|
|
||||||
luaCode = (slots.default?.() || [])
|
luaCode = (slots.default?.() || [])
|
||||||
.map(vnode => typeof vnode.children === 'string' ? vnode.children : '')
|
.map(vnode => typeof vnode.children === 'string' ? vnode.children : '')
|
||||||
.join('\n')
|
.join('\n')
|
||||||
})
|
})
|
||||||
|
|
||||||
async function startDemo() {
|
async function startDemo() {
|
||||||
|
if (typeof window === 'undefined' || typeof document === 'undefined') return
|
||||||
|
|
||||||
showDemo.value = true
|
showDemo.value = true
|
||||||
|
|
||||||
const basalt = await fetch(
|
const basalt = await fetch(
|
||||||
@@ -47,6 +52,8 @@ function closeDemo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function startDrag(e) {
|
function startDrag(e) {
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
|
||||||
isDragging = true
|
isDragging = true
|
||||||
offset.x = e.clientX - position.x
|
offset.x = e.clientX - position.x
|
||||||
offset.y = e.clientY - position.y
|
offset.y = e.clientY - position.y
|
||||||
@@ -55,32 +62,30 @@ function startDrag(e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onDrag(e) {
|
function onDrag(e) {
|
||||||
if (isDragging) {
|
if (!isDragging || typeof window === 'undefined') return
|
||||||
// Containergröße ermitteln
|
|
||||||
const containerEl = container.value?.parentElement
|
|
||||||
const contW = containerEl?.offsetWidth || 0
|
|
||||||
const contH = containerEl?.offsetHeight || 0
|
|
||||||
|
|
||||||
// Maximal erlaubte Positionen
|
const containerEl = container.value?.parentElement
|
||||||
const maxX = window.innerWidth - contW
|
const contW = containerEl?.offsetWidth || 0
|
||||||
const maxY = window.innerHeight - contH
|
const contH = containerEl?.offsetHeight || 0
|
||||||
|
|
||||||
// Neue Position berechnen
|
const maxX = window.innerWidth - contW
|
||||||
let newX = e.clientX - offset.x
|
const maxY = window.innerHeight - contH
|
||||||
let newY = e.clientY - offset.y
|
|
||||||
|
|
||||||
// Begrenzen (clampen)
|
let newX = e.clientX - offset.x
|
||||||
if (newX < 0) newX = 0
|
let newY = e.clientY - offset.y
|
||||||
if (newY < 0) newY = 0
|
|
||||||
if (newX > maxX) newX = maxX
|
|
||||||
if (newY > maxY) newY = maxY
|
|
||||||
|
|
||||||
position.x = newX
|
if (newX < 0) newX = 0
|
||||||
position.y = newY
|
if (newY < 0) newY = 0
|
||||||
}
|
if (newX > maxX) newX = maxX
|
||||||
|
if (newY > maxY) newY = maxY
|
||||||
|
|
||||||
|
position.x = newX
|
||||||
|
position.y = newY
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopDrag() {
|
function stopDrag() {
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
|
||||||
isDragging = false
|
isDragging = false
|
||||||
document.removeEventListener('mousemove', onDrag)
|
document.removeEventListener('mousemove', onDrag)
|
||||||
document.removeEventListener('mouseup', stopDrag)
|
document.removeEventListener('mouseup', stopDrag)
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ function extractText(nodes) {
|
|||||||
|
|
||||||
const luaCode = computed(() => extractText(slots.default?.() ?? []))
|
const luaCode = computed(() => extractText(slots.default?.() ?? []))
|
||||||
|
|
||||||
|
|
||||||
const highlightedCode = computed(() => {
|
const highlightedCode = computed(() => {
|
||||||
let code = luaCode.value
|
let code = luaCode.value
|
||||||
|
|
||||||
@@ -61,6 +60,7 @@ const highlightedCode = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
async function startDemo() {
|
async function startDemo() {
|
||||||
|
if (typeof window === 'undefined') return
|
||||||
if (isLoading.value || showDemo.value) return
|
if (isLoading.value || showDemo.value) return
|
||||||
|
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
@@ -133,6 +133,8 @@ function closeDemo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function centerWindow() {
|
function centerWindow() {
|
||||||
|
if (typeof window === 'undefined') return
|
||||||
|
|
||||||
const windowWidth = window.innerWidth
|
const windowWidth = window.innerWidth
|
||||||
const windowHeight = window.innerHeight
|
const windowHeight = window.innerHeight
|
||||||
position.x = Math.max(0, (windowWidth - 650) / 2)
|
position.x = Math.max(0, (windowWidth - 650) / 2)
|
||||||
@@ -140,6 +142,8 @@ function centerWindow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function startDrag(e) {
|
function startDrag(e) {
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
|
||||||
if (e.target.closest('button')) return
|
if (e.target.closest('button')) return
|
||||||
isDragging = true
|
isDragging = true
|
||||||
offset.x = e.clientX - position.x
|
offset.x = e.clientX - position.x
|
||||||
@@ -150,7 +154,8 @@ function startDrag(e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onDrag(e) {
|
function onDrag(e) {
|
||||||
if (!isDragging) return
|
if (!isDragging || typeof window === 'undefined') return
|
||||||
|
|
||||||
const maxX = window.innerWidth - 650
|
const maxX = window.innerWidth - 650
|
||||||
const maxY = window.innerHeight - 480
|
const maxY = window.innerHeight - 480
|
||||||
|
|
||||||
@@ -159,6 +164,8 @@ function onDrag(e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function stopDrag() {
|
function stopDrag() {
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
|
||||||
isDragging = false
|
isDragging = false
|
||||||
document.removeEventListener('mousemove', onDrag)
|
document.removeEventListener('mousemove', onDrag)
|
||||||
document.removeEventListener('mouseup', stopDrag)
|
document.removeEventListener('mouseup', stopDrag)
|
||||||
@@ -171,11 +178,17 @@ function handleKeydown(e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.addEventListener('keydown', handleKeydown)
|
// SSR Guard - nur im Browser Event Listener hinzufügen
|
||||||
|
if (typeof document !== 'undefined') {
|
||||||
|
document.addEventListener('keydown', handleKeydown)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
document.removeEventListener('keydown', handleKeydown)
|
// SSR Guard
|
||||||
|
if (typeof document !== 'undefined') {
|
||||||
|
document.removeEventListener('keydown', handleKeydown)
|
||||||
|
}
|
||||||
closeDemo()
|
closeDemo()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -197,13 +210,12 @@ onUnmounted(() => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Code Block with Syntax Highlighting -->
|
|
||||||
<div class="code-block">
|
<div class="code-block">
|
||||||
<pre><code v-html="highlightedCode"></code></pre>
|
<pre><code v-html="highlightedCode"></code></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Teleport to="body">
|
<Teleport v-if="typeof document !== 'undefined'" to="body">
|
||||||
<div
|
<div
|
||||||
v-if="showDemo"
|
v-if="showDemo"
|
||||||
ref="wrapperRef"
|
ref="wrapperRef"
|
||||||
|
|||||||
@@ -1,258 +1,245 @@
|
|||||||
// .vitepress/theme/emulator.js
|
// .vitepress/theme/emulator.js
|
||||||
let globalComputerInstance = null
|
export function initEmulator() {
|
||||||
let isGlobalLoading = false
|
if (typeof window === 'undefined') return
|
||||||
|
|
||||||
async function loadDependencies() {
|
let globalComputerInstance = null
|
||||||
const basalt = await fetch(
|
let isGlobalLoading = false
|
||||||
'https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/release/basalt.lua'
|
|
||||||
).then(res => res.text())
|
|
||||||
|
|
||||||
if (!window.require) {
|
async function loadDependencies() {
|
||||||
await new Promise((resolve, reject) => {
|
const basalt = await fetch(
|
||||||
const script = document.createElement('script')
|
'https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/release/basalt.lua'
|
||||||
script.src = 'https://copy-cat.squiddev.cc/require.js'
|
).then(res => res.text())
|
||||||
script.onload = resolve
|
|
||||||
script.onerror = reject
|
|
||||||
document.body.appendChild(script)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return basalt
|
if (!window.require) {
|
||||||
}
|
await new Promise((resolve, reject) => {
|
||||||
|
const script = document.createElement('script')
|
||||||
async function runCodeInEmulator(code, title = 'Code Demo') {
|
script.src = 'https://copy-cat.squiddev.cc/require.js'
|
||||||
console.log('runCodeInEmulator called with:', { code, title })
|
script.onload = resolve
|
||||||
|
script.onerror = reject
|
||||||
if (isGlobalLoading || globalComputerInstance) {
|
document.body.appendChild(script)
|
||||||
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
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Setup promise created:', setupPromise)
|
return basalt
|
||||||
|
}
|
||||||
|
|
||||||
if (setupPromise && typeof setupPromise.then === 'function') {
|
async function runCodeInEmulator(code, title = 'Code Demo') {
|
||||||
setupPromise.then((computer) => {
|
console.log('runCodeInEmulator called with:', { code, title })
|
||||||
console.log('Computer instance resolved from promise:', computer)
|
|
||||||
globalComputerInstance = computer
|
|
||||||
|
|
||||||
if (computer && typeof computer.run === 'function') {
|
if (isGlobalLoading || globalComputerInstance) {
|
||||||
computer.run()
|
console.warn('Emulator already running')
|
||||||
console.log('Computer started running')
|
return
|
||||||
} else if (computer && typeof computer.start === 'function') {
|
}
|
||||||
computer.start()
|
|
||||||
console.log('Computer started with start()')
|
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 {
|
} else {
|
||||||
console.error('Computer does not have run or start method:', computer)
|
console.error('Direct setup does not have run method:', setupPromise)
|
||||||
console.log('Available methods:', Object.getOwnPropertyNames(computer || {}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Showing terminal window...')
|
|
||||||
showTerminalWindow(tempContainer, title)
|
showTerminalWindow(tempContainer, title)
|
||||||
|
|
||||||
isGlobalLoading = false
|
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)
|
} catch (error) {
|
||||||
isGlobalLoading = false
|
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 = `<span style="color: #fff; font-size: 0.875rem; font-weight: 500;">💻 ${title}</span>`
|
||||||
|
|
||||||
|
const controls = document.createElement('div')
|
||||||
|
controls.innerHTML = `
|
||||||
|
<button class="control-button close" style="width: 24px; height: 24px; border-radius: 50%; border: none; cursor: pointer; background: #ef4444; color: white; font-size: 12px;" onclick="closeGlobalEmulator()">✕</button>
|
||||||
|
`
|
||||||
|
|
||||||
|
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) {
|
document.addEventListener('mousemove', (e) => {
|
||||||
console.error('Error starting emulator:', error)
|
if (!isDragging) return
|
||||||
isGlobalLoading = false
|
|
||||||
|
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) {
|
function closeGlobalEmulator() {
|
||||||
console.log('showTerminalWindow called with:', { container, title })
|
if (globalComputerInstance) {
|
||||||
|
try {
|
||||||
const windowDiv = document.createElement('div')
|
globalComputerInstance.shutdown()
|
||||||
windowDiv.className = 'global-terminal-window'
|
} catch (e) {
|
||||||
console.log('Terminal window div created')
|
console.warn('Error shutting down:', e)
|
||||||
|
}
|
||||||
windowDiv.style.cssText = `
|
globalComputerInstance = null
|
||||||
position: fixed;
|
}
|
||||||
width: 625px;
|
|
||||||
height: 425px;
|
const windowDiv = document.querySelector('.global-terminal-window')
|
||||||
background: #1a1a1a;
|
if (windowDiv) {
|
||||||
border-radius: 8px;
|
document.body.removeChild(windowDiv)
|
||||||
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 = `<span style="color: #fff; font-size: 0.875rem; font-weight: 500;">💻 ${title}</span>`
|
|
||||||
|
|
||||||
const controls = document.createElement('div')
|
|
||||||
controls.innerHTML = `
|
|
||||||
<button class="control-button close" style="width: 24px; height: 24px; border-radius: 50%; border: none; cursor: pointer; background: #ef4444; color: white; font-size: 12px;" onclick="closeGlobalEmulator()">✕</button>
|
|
||||||
`
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
globalComputerInstance = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const windowDiv = document.querySelector('.global-terminal-window')
|
window.runCodeBlock = function(button) {
|
||||||
if (windowDiv) {
|
const container = button.closest('.code-block-with-run')
|
||||||
document.body.removeChild(windowDiv)
|
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.closeGlobalEmulator = closeGlobalEmulator
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
|
|||||||
@@ -1,17 +1,50 @@
|
|||||||
import CopyButton from 'vitepress-copy-helper';
|
import CopyButton from 'vitepress-copy-helper';
|
||||||
import 'vitepress-copy-helper/style.css'
|
import 'vitepress-copy-helper/style.css'
|
||||||
import DefaultTheme from 'vitepress/theme'
|
import DefaultTheme from 'vitepress/theme'
|
||||||
import BasaltDemo from './components/BasaltDemo.vue'
|
|
||||||
import BasaltDemoWithCode from './components/BasaltDemoWithCode.vue'
|
|
||||||
import './emulator.js'
|
|
||||||
import './styles.css'
|
import './styles.css'
|
||||||
|
|
||||||
/** @type {import('vitepress').Theme} */
|
/** @type {import('vitepress').Theme} */
|
||||||
export default {
|
export default {
|
||||||
extends: DefaultTheme,
|
extends: DefaultTheme,
|
||||||
enhanceApp({ app }) {
|
enhanceApp({ app, router, siteData }) {
|
||||||
app.component('C', CopyButton)
|
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()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user