Skip to content

Commit 9848906

Browse files
committed
fix AssemblyScript editor
1 parent a5e3f27 commit 9848906

2 files changed

Lines changed: 152 additions & 3 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<script setup lang="ts">
2+
import { computed, onMounted, onUnmounted, ref } from 'vue'
3+
4+
const props = defineProps<{
5+
code: string
6+
}>()
7+
8+
const editor = ref<HTMLElement | null>(null)
9+
const isMaximized = ref(false)
10+
const iframeSrc = ref('data:text/html;base64,')
11+
12+
const editorSrc = computed(() => `/editor.html#${props.code}`)
13+
14+
let readyStateListener: (() => void) | null = null
15+
16+
function updateBodyOverflow(): void {
17+
document.body.style.overflow = isMaximized.value ? 'hidden' : 'auto'
18+
}
19+
20+
function toggleEditor(): void {
21+
isMaximized.value = !isMaximized.value
22+
updateBodyOverflow()
23+
24+
if (!isMaximized.value) {
25+
editor.value?.scrollIntoView({ block: 'nearest', behavior: 'smooth' })
26+
}
27+
}
28+
29+
onMounted(() => {
30+
const setIframeSrc = (): void => {
31+
iframeSrc.value = editorSrc.value
32+
}
33+
34+
if (document.readyState === 'complete') {
35+
setIframeSrc()
36+
return
37+
}
38+
39+
readyStateListener = () => {
40+
if (document.readyState === 'complete') {
41+
setIframeSrc()
42+
if (readyStateListener) {
43+
document.removeEventListener('readystatechange', readyStateListener)
44+
readyStateListener = null
45+
}
46+
}
47+
}
48+
49+
document.addEventListener('readystatechange', readyStateListener, { once: true })
50+
})
51+
52+
onUnmounted(() => {
53+
if (readyStateListener) {
54+
document.removeEventListener('readystatechange', readyStateListener)
55+
}
56+
57+
if (isMaximized.value) {
58+
document.body.style.overflow = 'auto'
59+
}
60+
})
61+
</script>
62+
63+
<template>
64+
<div ref="editor" class="editor-wrap" :class="{ maximized: isMaximized }">
65+
<button
66+
type="button"
67+
class="maximize"
68+
:aria-label="isMaximized ? 'Minimize editor' : 'Maximize editor'"
69+
@click="toggleEditor"
70+
>
71+
{{ isMaximized ? '◲' : '◰' }}
72+
</button>
73+
<iframe :src="iframeSrc" title="Editor" loading="lazy" />
74+
</div>
75+
</template>
76+
77+
<style scoped>
78+
.editor-wrap {
79+
position: relative;
80+
margin-block: 1em;
81+
}
82+
83+
.maximize {
84+
position: absolute;
85+
top: 8px;
86+
right: 12px;
87+
z-index: 1000;
88+
border: 0;
89+
padding: 0;
90+
background: transparent;
91+
color: #c7c4c7;
92+
cursor: pointer;
93+
font: inherit;
94+
font-size: 1.2rem;
95+
line-height: 1;
96+
}
97+
98+
.maximize:hover {
99+
color: #fff;
100+
}
101+
102+
iframe {
103+
width: 100%;
104+
height: 540px;
105+
min-height: 540px;
106+
border: 0;
107+
background: #1e1e1e;
108+
resize: vertical;
109+
}
110+
111+
.maximized {
112+
position: fixed;
113+
z-index: 9000;
114+
inset: 0;
115+
margin: 0;
116+
}
117+
118+
.maximized iframe {
119+
height: 100% !important;
120+
resize: none;
121+
}
122+
</style>

src/.vuepress/config.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
import { readFileSync } from 'node:fs'
22
import { resolve } from 'node:path'
33
import { fileURLToPath } from 'node:url'
4+
import { Buffer } from 'node:buffer'
45
import { viteBundler } from '@vuepress/bundler-vite'
56
import { docsearchPlugin } from '@vuepress/plugin-docsearch'
67
import { redirectPlugin } from '@vuepress/plugin-redirect'
78
import { shikiPlugin } from '@vuepress/plugin-shiki'
89
import { registerComponentsPlugin } from '@vuepress/plugin-register-components'
910
import { defaultTheme } from '@vuepress/theme-default'
1011
import { defineUserConfig } from 'vuepress'
12+
13+
import type { Plugin } from '@vuepress/core'
14+
import type { Markdown } from '@vuepress/markdown'
15+
1116
import navbar from './nav'
1217
import sidebar from './sidebar'
1318

1419
const __dirname = fileURLToPath(new URL('.', import.meta.url))
1520
const redirectsFile = new URL('./redirects', import.meta.url)
21+
1622
export default defineUserConfig({
1723
base: '/',
1824
dest: './dist',
@@ -66,15 +72,13 @@ export default defineUserConfig({
6672
plugins: [
6773
shikiPlugin({
6874
langs: ['ts', 'js', 'json', 'md', 'bash'],
69-
langAlias: {
70-
editor: 'ts',
71-
},
7275
themes: {
7376
light: 'light-plus',
7477
dark: 'ayu-mirage',
7578
},
7679
lineNumbers: false,
7780
}),
81+
assemblyScriptEditorPlugin(),
7882
redirectPlugin({
7983
config: loadRedirects(),
8084
}),
@@ -90,6 +94,29 @@ export default defineUserConfig({
9094
]
9195
})
9296

97+
function assemblyScriptEditorPlugin(): Plugin {
98+
return {
99+
name: 'as-editor',
100+
extendsMarkdown(md: Markdown) {
101+
const defaultFence = md.renderer.rules.fence
102+
103+
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
104+
const token = tokens[idx]
105+
const [lang = ''] = token.info.trim().split(/\s+/u)
106+
107+
if (lang !== 'editor') {
108+
return defaultFence
109+
? defaultFence(tokens, idx, options, env, self)
110+
: self.renderToken(tokens, idx, options)
111+
}
112+
113+
const encoded = Buffer.from(token.content, 'utf8').toString('base64')
114+
return `<EditorFrame code="${encoded}" />`
115+
}
116+
},
117+
}
118+
}
119+
93120
function loadRedirects(): Record<string, string> {
94121
return Object.fromEntries(
95122
readFileSync(redirectsFile, 'utf8')

0 commit comments

Comments
 (0)