Skip to content

Commit d78dcb1

Browse files
committed
feat: monaco
1 parent ae7ed11 commit d78dcb1

9 files changed

Lines changed: 192 additions & 7 deletions

File tree

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
"eslint": "^7.24.0",
2828
"fs-extra": "^9.1.0",
2929
"markdown-it-prism": "^2.1.6",
30+
"monaco-editor": "^0.23.0",
3031
"pnpm": "^6.0.1",
32+
"theme-vitesse": "^0.1.8",
3133
"typescript": "^4.2.4",
3234
"vite": "^2.1.5",
3335
"vite-plugin-components": "^0.8.3",

plugins/monaco.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Plugin, resolvePackageData } from 'vite'
2+
3+
export function createMonacoLoader(): Plugin {
4+
return {
5+
name: 'monaco-types-loader',
6+
7+
resolveId(id) {
8+
if (id.startsWith('/@monaco-types/'))
9+
return id
10+
return null
11+
},
12+
13+
load(id) {
14+
const match = id.match(/^\/\@monaco-types\/(.*)$/)
15+
if (match) {
16+
const pkg = match[1]
17+
const info = resolvePackageData(pkg, process.cwd())
18+
if (!info)
19+
return
20+
21+
if (!info.data.types)
22+
return ''
23+
24+
return [
25+
'import * as monaco from \'monaco-editor\'',
26+
`import Type from "${info.dir}/${info.data.types}?raw"`,
27+
...Object.keys(info.data.dependencies || {}).map(i => `import "/@monaco-types/${i}"`),
28+
`monaco.languages.typescript.typescriptDefaults.addExtraLib(\`declare module "${pkg}" { \$\{Type\} }\`)`,
29+
].join('\n')
30+
}
31+
},
32+
}
33+
}
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,24 @@ export function createSlidesLoader(): Plugin {
4545
items = parse(raw)
4646
},
4747

48+
configureServer(server) {
49+
server.watcher.add(filepath)
50+
},
51+
4852
async handleHotUpdate(ctx) {
4953
if (ctx.file === filepath) {
50-
raw = await ctx.read()
54+
raw = await read()
5155
items = parse(raw)
5256

53-
return [
57+
const modules = [
5458
'/@vite-slides/routes',
5559
...items.map((i, idx) => `/@vite-slides/slides/${idx}.md`),
5660
]
5761
.map(id => ctx.server.moduleGraph.getModuleById(id))
5862
.filter(isNotNull)
63+
64+
modules.map(m => ctx.server.moduleGraph.invalidateModule(m))
65+
return modules
5966
}
6067
},
6168

pnpm-lock.yaml

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

slides.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ import { useFullscreen } from '@vueuse/core'
4343

4444
<Tweet url="https://twitter.com/antfu7/status/1362676666221268995" />
4545

46+
---
47+
---
48+
49+
# Monaco Example
50+
51+
<Monaco />
52+
4653
---
4754
layout: end
4855
---

src/components/Monaco.vue

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<template>
2+
<div ref="el" class="monaco-editor text-base" :style="{ height, width }"></div>
3+
</template>
4+
5+
<script setup lang="ts">
6+
import { ref, onMounted, onUnmounted, defineProps, watch } from 'vue'
7+
import { monaco } from './MonacoEnv'
8+
import { isDark, useNavigateControls } from '~/logic'
9+
10+
const props = defineProps({
11+
code: {
12+
default:
13+
`
14+
import { ref, computed } from 'vue'
15+
16+
const counter = ref(0)
17+
const doubled = computed(() => counter.value * 2)
18+
`.trim(),
19+
},
20+
fontSize: {
21+
default: 20,
22+
},
23+
lang: {
24+
default: 'typescript',
25+
},
26+
lineNumbers: {
27+
default: 'off',
28+
},
29+
width: {
30+
default: '800px',
31+
},
32+
height: {
33+
default: '600px',
34+
},
35+
})
36+
37+
const el = ref<HTMLElement>()
38+
const controls = useNavigateControls()
39+
let editor: monaco.editor.IStandaloneCodeEditor
40+
41+
onMounted(() => {
42+
editor = monaco.editor.create(el.value!, {
43+
language: props.lang,
44+
value: props.code,
45+
tabSize: 2,
46+
insertSpaces: true,
47+
detectIndentation: false,
48+
folding: false,
49+
lineDecorationsWidth: 4,
50+
lineNumbersMinChars: 0,
51+
theme: isDark.value ? 'vitesse-dark' : 'vitesse-light',
52+
lineNumbers: props.lineNumbers as any,
53+
fontSize: props.fontSize,
54+
glyphMargin: false,
55+
scrollbar: {
56+
useShadows: false,
57+
vertical: 'hidden',
58+
horizontal: 'hidden',
59+
},
60+
overviewRulerLanes: 0,
61+
hideCursorInOverviewRuler: true,
62+
minimap: { enabled: false },
63+
})
64+
editor.onDidFocusEditorText(() => controls.paused.value = true)
65+
editor.onDidBlurEditorText(() => controls.paused.value = false)
66+
67+
// @ts-expect-error
68+
editor._themeService._theme.getTokenStyleMetadata = (type, modifiers) => {
69+
console.log(type, modifiers)
70+
if (type === 'keyword') {
71+
return {
72+
foreground: 5, // color id 5
73+
bold: true,
74+
underline: true,
75+
italic: true,
76+
}
77+
}
78+
}
79+
})
80+
81+
watch(isDark, () => monaco.editor.setTheme(isDark.value ? 'vitesse-dark' : 'vitesse-light'))
82+
83+
onUnmounted(() => {
84+
editor.dispose()
85+
})
86+
</script>

src/components/MonacoEnv.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as monaco from 'monaco-editor'
2+
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
3+
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
4+
import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
5+
import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
6+
import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
7+
8+
import '/@monaco-types/vue'
9+
import '/@monaco-types/@vueuse/core'
10+
11+
import dark from 'theme-vitesse/themes/vitesse-dark.json'
12+
import light from 'theme-vitesse/themes/vitesse-light.json'
13+
14+
monaco.editor.defineTheme('vitesse-light', light as any)
15+
monaco.editor.defineTheme('vitesse-dark', dark as any)
16+
17+
// @ts-expect-error
18+
self.MonacoEnvironment = {
19+
getWorker(_: any, label: string) {
20+
if (label === 'json')
21+
return new JsonWorker()
22+
if (label === 'css' || label === 'scss' || label === 'less')
23+
return new CssWorker()
24+
if (label === 'html' || label === 'handlebars' || label === 'razor')
25+
return new HtmlWorker()
26+
if (label === 'typescript' || label === 'javascript')
27+
return new TsWorker()
28+
return new EditorWorker()
29+
},
30+
}
31+
32+
export { monaco }

src/logic/controls.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { computed, App, InjectionKey, inject, ref, ComputedRef } from 'vue'
1+
import { computed, App, InjectionKey, inject, ref, ComputedRef, Ref } from 'vue'
22
import { Fn, useMagicKeys, whenever } from '@vueuse/core'
33
import { Router } from 'vue-router'
44

55
export interface NavigateControls {
66
next: Fn
77
prev: Fn
8+
paused: Ref<boolean>
89
hasNext: ComputedRef<boolean>
910
hasPrev: ComputedRef<boolean>
1011
install(app: App): void
@@ -18,6 +19,7 @@ export function createNavigateControls(router: Router) {
1819
const path = computed(() => route.value.path)
1920

2021
const counter = ref(parseInt(path.value.split(/\//g)[1]) || 0)
22+
const paused = ref(false)
2123

2224
router.afterEach(() => {
2325
counter.value = parseInt(path.value.split(/\//g)[1]) || 0
@@ -38,13 +40,14 @@ export function createNavigateControls(router: Router) {
3840

3941
const { space, right, left } = useMagicKeys()
4042

41-
whenever(space, next)
42-
whenever(right, next)
43-
whenever(left, prev)
43+
whenever(() => space.value && !paused.value, next)
44+
whenever(() => right.value && !paused.value, next)
45+
whenever(() => left.value && !paused.value, prev)
4446

4547
const navigateControls: NavigateControls = {
4648
next,
4749
prev,
50+
paused,
4851
hasNext,
4952
hasPrev,
5053
install(app: App) {

vite.config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import ViteComponents from 'vite-plugin-components'
66
import Markdown from 'vite-plugin-md'
77
import WindiCSS from 'vite-plugin-windicss'
88
import Prism from 'markdown-it-prism'
9-
import { createSlidesLoader } from './plugins/loader'
9+
import { createSlidesLoader } from './plugins/slides'
10+
import { createMonacoLoader } from './plugins/monaco'
1011

1112
export default defineConfig({
1213
resolve: {
@@ -45,6 +46,7 @@ export default defineConfig({
4546
}),
4647

4748
createSlidesLoader(),
49+
createMonacoLoader(),
4850

4951
ViteIcons(),
5052

0 commit comments

Comments
 (0)