diff --git a/packages/monaco/index.html b/packages/monaco/index.html
new file mode 100644
index 0000000..82b74ac
--- /dev/null
+++ b/packages/monaco/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+ Document
+
+
+
+
+
diff --git a/packages/monaco/package.json b/packages/monaco/package.json
new file mode 100644
index 0000000..5e6b7b1
--- /dev/null
+++ b/packages/monaco/package.json
@@ -0,0 +1,41 @@
+{
+ "name": "inpageedit-plugin-monaco",
+ "description": "Monaco Editor for InPageEdit",
+ "version": "1.0.0",
+ "private": true,
+ "type": "module",
+ "module": "./dist/index.mjs",
+ "files": [
+ "dist"
+ ],
+ "exports": {
+ ".": {
+ "import": "./dist/index.mjs"
+ }
+ },
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build"
+ },
+ "$ipe": {
+ "name": "Monaco Editor",
+ "categories": [],
+ "loader": {
+ "kind": "module",
+ "entry": "dist/index.mjs",
+ "styles": [],
+ "main_export": "default"
+ },
+ "dev_loader": {
+ "entry": "src/index.ts",
+ "styles": []
+ }
+ },
+ "dependencies": {
+ "modern-monaco": "^0.2.2"
+ },
+ "devDependencies": {
+ "rolldown": "1.0.0-beta.47",
+ "vite": "npm:rolldown-vite@latest"
+ }
+}
\ No newline at end of file
diff --git a/packages/monaco/src/index.ts b/packages/monaco/src/index.ts
new file mode 100644
index 0000000..8236a42
--- /dev/null
+++ b/packages/monaco/src/index.ts
@@ -0,0 +1,112 @@
+import { BasePlugin } from '~~/defineIPEPlugin.js'
+import type { Events, InPageEdit } from '@inpageedit/core'
+import type {} from '@inpageedit/core/services/WikiTitleService'
+import type {} from '@inpageedit/core/plugins/toolbox/index'
+import type {} from '@inpageedit/core/plugins/quick-edit/index'
+import { IWikiPage } from '@inpageedit/core/dist/models/WikiPage/index.js'
+
+export class PluginMonaco extends BasePlugin {
+ constructor(ctx: InPageEdit) {
+ super(ctx, {}, 'monaco-editor')
+ ctx.set('plugin:monaco-editor', true)
+ }
+
+ protected async start() {
+ this.ctx.on('quick-edit/wiki-page', this.onQuickEditWikiPage.bind(this))
+ }
+
+ async onQuickEditWikiPage(
+ payload: Parameters[0]
+ ) {
+ const { init } = await import('modern-monaco')
+
+ const { modal, wikiPage } = payload
+ const textarea = modal
+ .get$content()
+ .querySelector('textarea[name="text"]')
+ const wrapper = modal
+ .get$content()
+ .querySelector('.ipe-quickEdit__content')
+ if (!textarea || !wrapper) return
+
+ const language =
+ wikiPage.contentmodel ||
+ this.guessLangByTitle(wikiPage.title) ||
+ 'wikitext'
+ const monaco = await init({})
+ const container = document.createElement('div')
+ container.style.width = wrapper.clientWidth + 'px'
+ container.style.height = '65lvh'
+ wrapper.appendChild(container)
+ const editor = monaco.editor.create(container, {
+ theme: 'vs-dark',
+ automaticLayout: true,
+ language,
+ tabSize: 2,
+ glyphMargin: true,
+ wordWrap: language === 'wikitext' ? 'on' : 'off',
+ wordBreak: language === 'wikitext' ? 'keepAll' : 'normal',
+ unicodeHighlight:
+ language === 'wikitext'
+ ? {
+ ambiguousCharacters: false,
+ }
+ : undefined,
+ })
+ const model = this.createModel(monaco, wikiPage)
+ editor.setModel(model)
+ model.onDidChangeAttached(() => {
+ textarea.value = model.getValue()
+ textarea.dispatchEvent(new Event('input'))
+ textarea.dispatchEvent(new Event('change'))
+ })
+ }
+
+ guessLangByTitle(input = '') {
+ const title = this.ctx.wikiTitle.newTitle(input)
+ const nsNumber = title.getNamespaceId()
+ const pageName = title.getMainText()
+ const ext = pageName.split('.').pop()
+ if (ext === 'js') {
+ return 'javascript'
+ } else if (ext === 'css') {
+ return 'css'
+ }
+ // NS_MODULE
+ else if (nsNumber === 828 && !pageName.endsWith('/doc')) {
+ return 'lua'
+ }
+ // NS_WIDGET
+ else if (nsNumber === 274) {
+ return 'html'
+ } else if (ext === 'json') {
+ return 'json'
+ }
+ return 'wikitext'
+ }
+
+ async createWorkspace(wikiPage: IWikiPage) {
+ const { Workspace } = await import('modern-monaco')
+ const workspace = new Workspace({
+ name: wikiPage.title,
+ initialFiles: {
+ [wikiPage.title]: wikiPage.revisions?.[0]?.content || '',
+ },
+ entryFile: wikiPage.title,
+ })
+ workspace.openTextDocument(wikiPage.title)
+ return workspace
+ }
+
+ createModel(
+ monaco: Awaited>,
+ wikiPage: IWikiPage
+ ) {
+ return monaco.editor.createModel(
+ wikiPage.revisions?.[0]?.content || '',
+ wikiPage.contentmodel ||
+ this.guessLangByTitle(wikiPage.title) ||
+ 'wikitext'
+ )
+ }
+}
diff --git a/packages/monaco/vite.config.ts b/packages/monaco/vite.config.ts
new file mode 100644
index 0000000..8703ec8
--- /dev/null
+++ b/packages/monaco/vite.config.ts
@@ -0,0 +1,24 @@
+import { resolve } from 'node:path'
+import { defineConfig } from 'vite'
+
+export default defineConfig({
+ build: {
+ lib: {
+ entry: 'src/index.ts',
+ formats: ['es'],
+ fileName: () => 'index.mjs',
+ cssFileName: 'style.css',
+ },
+ sourcemap: true,
+ rollupOptions: {
+ output: {
+ inlineDynamicImports: false,
+ },
+ },
+ },
+ resolve: {
+ alias: {
+ '~~': resolve(import.meta.dirname, '../../common'),
+ },
+ },
+})