diff --git a/icons.config.ts b/icons.config.ts
index 8283e7be..bf5f777e 100644
--- a/icons.config.ts
+++ b/icons.config.ts
@@ -57,6 +57,8 @@ const config: IconsConfig = {
"light_mode",
"palette",
"translate",
+ "play_arrow",
+ "extension",
],
codePoints: {
speed: "e9e4",
diff --git a/package-lock.json b/package-lock.json
index 85b3b2b3..cf0a8fd5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,8 @@
"hasInstallScript": true,
"license": "AGPL-3.0-or-later",
"devDependencies": {
+ "@codemirror/lang-javascript": "^6.1.9",
+ "@codemirror/state": "^6.2.1",
"@fontsource-variable/material-symbols-rounded": "^5.0.4",
"@fontsource-variable/noto-sans-mono": "^5.0.4",
"@material/material-color-utilities": "^0.2.7",
@@ -23,6 +25,7 @@
"@types/w3c-web-serial": "^1.0.3",
"@vite-pwa/sveltekit": "^0.2.5",
"autoprefixer": "^10.4.14",
+ "codemirror": "^6.0.1",
"cypress": "^12.17.1",
"flexsearch": "^0.7.31",
"fontkit": "^2.0.2",
@@ -1763,6 +1766,104 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@codemirror/autocomplete": {
+ "version": "6.9.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.9.0.tgz",
+ "integrity": "sha512-Fbwm0V/Wn3BkEJZRhr0hi5BhCo5a7eBL6LYaliPjOSwCyfOpnjXY59HruSxOUNV+1OYer0Tgx1zRNQttjXyDog==",
+ "dev": true,
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.6.0",
+ "@lezer/common": "^1.0.0"
+ },
+ "peerDependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/commands": {
+ "version": "6.2.4",
+ "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.2.4.tgz",
+ "integrity": "sha512-42lmDqVH0ttfilLShReLXsDfASKLXzfyC36bzwcqzox9PlHulMcsUOfHXNo2X2aFMVNUoQ7j+d4q5bnfseYoOA==",
+ "dev": true,
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.2.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/lang-javascript": {
+ "version": "6.1.9",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.1.9.tgz",
+ "integrity": "sha512-z3jdkcqOEBT2txn2a87A0jSy6Te3679wg/U8QzMeftFt+4KA6QooMwfdFzJiuC3L6fXKfTXZcDocoaxMYfGz0w==",
+ "dev": true,
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/language": "^6.6.0",
+ "@codemirror/lint": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/javascript": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/language": {
+ "version": "6.8.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.8.0.tgz",
+ "integrity": "sha512-r1paAyWOZkfY0RaYEZj3Kul+MiQTEbDvYqf8gPGaRvNneHXCmfSaAVFjwRUPlgxS8yflMxw2CTu6uCMp8R8A2g==",
+ "dev": true,
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0",
+ "style-mod": "^4.0.0"
+ }
+ },
+ "node_modules/@codemirror/lint": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.4.0.tgz",
+ "integrity": "sha512-6VZ44Ysh/Zn07xrGkdtNfmHCbGSHZzFBdzWi0pbd7chAQ/iUcpLGX99NYRZTa7Ugqg4kEHCqiHhcZnH0gLIgSg==",
+ "dev": true,
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/search": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.0.tgz",
+ "integrity": "sha512-64/M40YeJPToKvGO6p3fijo2vwUEj4nACEAXElCaYQ50HrXSvRaK+NHEhSh73WFBGdvIdhrV+lL9PdJy2RfCYA==",
+ "dev": true,
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/state": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.1.tgz",
+ "integrity": "sha512-RupHSZ8+OjNT38zU9fKH2sv+Dnlr8Eb8sl4NOnnqz95mCFTZUaiRP8Xv5MeeaG0px2b8Bnfe7YGwCV3nsBhbuw==",
+ "dev": true
+ },
+ "node_modules/@codemirror/view": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.16.0.tgz",
+ "integrity": "sha512-1Z2HkvkC3KR/oEZVuW9Ivmp8TWLzGEd8T8TA04TTwPvqogfkHBdYSlflytDOqmkUxM2d1ywTg7X2dU5mC+SXvg==",
+ "dev": true,
+ "dependencies": {
+ "@codemirror/state": "^6.1.4",
+ "style-mod": "^4.0.0",
+ "w3c-keyname": "^2.2.4"
+ }
+ },
"node_modules/@colors/colors": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
@@ -2466,6 +2567,40 @@
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
"dev": true
},
+ "node_modules/@lezer/common": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.3.tgz",
+ "integrity": "sha512-JH4wAXCgUOcCGNekQPLhVeUtIqjH0yPBs7vvUdSjyQama9618IOKFJwkv2kcqdhF0my8hQEgCTEJU0GIgnahvA==",
+ "dev": true
+ },
+ "node_modules/@lezer/highlight": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.6.tgz",
+ "integrity": "sha512-cmSJYa2us+r3SePpRCjN5ymCqCPv+zyXmDl0ciWtVaNiORT/MxM7ZgOMQZADD0o51qOaOg24qc/zBViOIwAjJg==",
+ "dev": true,
+ "dependencies": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/javascript": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.5.tgz",
+ "integrity": "sha512-FmBUHz8K1V22DgjTd6SrIG9owbzOYZ1t3rY6vGEmw+e2RVBd7sqjM8uXEVRFmfxKFn1Mx2ABJehHjrN3G2ZpmA==",
+ "dev": true,
+ "dependencies": {
+ "@lezer/highlight": "^1.1.3",
+ "@lezer/lr": "^1.3.0"
+ }
+ },
+ "node_modules/@lezer/lr": {
+ "version": "1.3.9",
+ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.9.tgz",
+ "integrity": "sha512-XPz6dzuTHlnsbA5M2DZgjflNQ+9Hi5Swhic0RULdp3oOs3rh6bqGZolosVqN/fQIT8uNiepzINJDnS39oweTHQ==",
+ "dev": true,
+ "dependencies": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
"node_modules/@material/material-color-utilities": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/@material/material-color-utilities/-/material-color-utilities-0.2.7.tgz",
@@ -3999,6 +4134,21 @@
"periscopic": "^3.1.0"
}
},
+ "node_modules/codemirror": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
+ "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
+ "dev": true,
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/commands": "^6.0.0",
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/lint": "^6.0.0",
+ "@codemirror/search": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0"
+ }
+ },
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -4117,6 +4267,12 @@
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
+ "node_modules/crelt": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
+ "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
+ "dev": true
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -9348,6 +9504,12 @@
"url": "https://github.com/sponsors/antfu"
}
},
+ "node_modules/style-mod": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.3.tgz",
+ "integrity": "sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw==",
+ "dev": true
+ },
"node_modules/style-search": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
@@ -10582,6 +10744,12 @@
}
}
},
+ "node_modules/w3c-keyname": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
+ "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
+ "dev": true
+ },
"node_modules/w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
diff --git a/package.json b/package.json
index 2b76b8af..da8c01eb 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,12 @@
"@vite-pwa/sveltekit": "^0.2.5",
"@fontsource-variable/noto-sans-mono": "^5.0.4",
"@fontsource-variable/material-symbols-rounded": "^5.0.4",
+ "@codemirror/state": "^6.2.1",
+ "@codemirror/commands": "^6.2.4",
+ "@codemirror/autocomplete": "^6.9.0",
+ "@codemirror/lang-javascript": "^6.1.9",
+ "@codemirror/language": "^6.8.0",
+ "codemirror": "^6.0.1",
"stylelint": "^15.9.0",
"stylelint-config-standard-scss": "^10.0.0",
"stylelint-config-prettier-scss": "^1.0.0",
diff --git a/src/i18n/de/index.ts b/src/i18n/de/index.ts
index e2563cd9..d1aca2a2 100644
--- a/src/i18n/de/index.ts
+++ b/src/i18n/de/index.ts
@@ -58,6 +58,11 @@ const de = {
TITLE: "Einstellungen",
},
},
+ plugin: {
+ editor: {
+ RUN: "Ausführen",
+ },
+ },
} satisfies Translation
export default de
diff --git a/src/i18n/en/index.ts b/src/i18n/en/index.ts
index e4f7918c..4d32a03e 100644
--- a/src/i18n/en/index.ts
+++ b/src/i18n/en/index.ts
@@ -56,6 +56,11 @@ const en = {
TITLE: "Settings",
},
},
+ plugin: {
+ editor: {
+ RUN: "Run",
+ },
+ },
} satisfies BaseTranslation
export default en
diff --git a/src/routes/plugin/+page.svelte b/src/routes/plugin/+page.svelte
new file mode 100644
index 00000000..94e119a7
--- /dev/null
+++ b/src/routes/plugin/+page.svelte
@@ -0,0 +1,186 @@
+
+
+