diff --git a/package.json b/package.json
index f5754d5d0..6f3db8a4d 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
"echarts": "^5.6.0",
"envfile": "^7.1.0",
"ignore": "^6.0.2",
+ "monaco-editor": "^0.52.2",
"nanoid": "^5.1.5",
"nanotar": "^0.1.1",
"plausible-tracker": "^0.3.9",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5b69bf151..75a5c5c80 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -62,6 +62,9 @@ importers:
ignore:
specifier: ^6.0.2
version: 6.0.2
+ monaco-editor:
+ specifier: ^0.52.2
+ version: 0.52.2
nanoid:
specifier: ^5.1.5
version: 5.1.5
@@ -2679,6 +2682,9 @@ packages:
module-details-from-path@1.0.3:
resolution: {integrity: sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==}
+ monaco-editor@0.52.2:
+ resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==}
+
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@@ -6490,6 +6496,8 @@ snapshots:
module-details-from-path@1.0.3: {}
+ monaco-editor@0.52.2: {}
+
mri@1.2.0: {}
mrmime@2.0.1: {}
diff --git a/src/lib/components/chat/chat.svelte b/src/lib/components/chat/chat.svelte
index 1fb3c87ce..4e5750b63 100644
--- a/src/lib/components/chat/chat.svelte
+++ b/src/lib/components/chat/chat.svelte
@@ -1,5 +1,5 @@
+
+{#each items as { title, icon, children, path }, i}
+ {@const hasChildren = !!children?.length}
+ {@const isRoot = level === 1}
+
+
+
+
+ {#if children}
+
+ {/if}
+
+{/each}
+
+
diff --git a/src/lib/components/editor/editor.svelte b/src/lib/components/editor/editor.svelte
new file mode 100644
index 000000000..f993ea358
--- /dev/null
+++ b/src/lib/components/editor/editor.svelte
@@ -0,0 +1,62 @@
+
+
+
+
+
diff --git a/src/lib/components/editor/filesystem.svelte b/src/lib/components/editor/filesystem.svelte
new file mode 100644
index 000000000..167abf65b
--- /dev/null
+++ b/src/lib/components/editor/filesystem.svelte
@@ -0,0 +1,42 @@
+
+
+
+
+
diff --git a/src/lib/components/editor/filesystem.ts b/src/lib/components/editor/filesystem.ts
new file mode 100644
index 000000000..e353ef02a
--- /dev/null
+++ b/src/lib/components/editor/filesystem.ts
@@ -0,0 +1,5 @@
+import { writable } from 'svelte/store';
+
+export type FileSystem = string[];
+
+export const createFileSystem = (initial: FileSystem = []) => writable(initial);
diff --git a/src/routes/(console)/project-[project]/studio/code/+page.svelte b/src/routes/(console)/project-[project]/studio/code/+page.svelte
new file mode 100644
index 000000000..94aef1084
--- /dev/null
+++ b/src/routes/(console)/project-[project]/studio/code/+page.svelte
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/routes/(console)/project-[project]/studio/code/app.css b/src/routes/(console)/project-[project]/studio/code/app.css
new file mode 100644
index 000000000..aa2b8324a
--- /dev/null
+++ b/src/routes/(console)/project-[project]/studio/code/app.css
@@ -0,0 +1,90 @@
+body {
+ margin: 0;
+ font-size: 100%;
+ width: 100%;
+}
+
+[data-loading='true'] .page-loader {
+ pointer-events: initial;
+ visibility: visible;
+ opacity: 1;
+}
+
+.theme-dark .page-loader {
+ --p-page-loader-background-color: #000;
+}
+.theme-light .page-loader {
+ --p-page-loader-background-color: #fff;
+}
+
+.theme-light .page-loader {
+ background-color: #fff;
+}
+
+.page-loader {
+ pointer-events: none;
+ visibility: hidden;
+ opacity: 0;
+ z-index: 100000;
+ position: fixed;
+ height: 100%;
+ width: 100%;
+ background-color: var(--p-page-loader-background-color);
+ top: 0;
+ transition: all 0.2s ease-in-out;
+}
+
+.page-loader img {
+ visibility: hidden;
+ position: absolute;
+ max-width: 100%;
+ bottom: 60px;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+.theme-dark .page-loader .logo-dark {
+ visibility: visible;
+}
+
+.theme-light .page-loader .logo-light {
+ visibility: visible;
+}
+
+.page-loader .animation {
+ position: absolute;
+ top: 45%;
+ left: 50%;
+ transform: translate(-50%, -50%) translateZ(1px);
+ width: 140px;
+ height: 140px;
+}
+.page-loader .animation > div {
+ box-sizing: border-box;
+ display: block;
+ position: absolute;
+ width: 124px;
+ height: 124px;
+ margin: 10px;
+ border: 10px solid rgb(219, 26, 90);
+ border-radius: 50%;
+ animation: animation 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
+ border-color: rgb(219, 26, 90) transparent transparent transparent;
+}
+.page-loader .animation > div:nth-child(1) {
+ animation-delay: -0.45s;
+}
+.page-loader .animation > div:nth-child(2) {
+ animation-delay: -0.3s;
+}
+.page-loader .animation > div:nth-child(3) {
+ animation-delay: -0.15s;
+}
+@keyframes animation {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
diff --git a/src/routes/(console)/project-[project]/studio/code/app.js b/src/routes/(console)/project-[project]/studio/code/app.js
new file mode 100644
index 000000000..9753d0378
--- /dev/null
+++ b/src/routes/(console)/project-[project]/studio/code/app.js
@@ -0,0 +1,34 @@
+import { fileURLToPath } from 'url';
+import { build, loadEnv } from 'vite';
+import kleur from 'kleur';
+
+const { bold, yellow } = kleur;
+const __dirname = fileURLToPath(new URL('.', import.meta.url));
+const env = loadEnv('production', __dirname, 'PUBLIC_');
+
+function log(text = '', prefix = '') {
+ console.log(`${bold().green(`# ${prefix}`)}${text}`);
+}
+
+function logEnv(key, value, fallback = 'not set') {
+ log(value || yellow(fallback), `${key}: `);
+}
+
+function logDelimiter() {
+ console.log(bold().green('#'.repeat(80)));
+}
+
+async function main() {
+ logDelimiter();
+ log();
+ log(bold().magenta('APPWRITE CONSOLE'));
+ log();
+ logEnv('CONSOLE MODE', env?.PUBLIC_CONSOLE_MODE);
+ logEnv('APPWRITE ENDPOINT', env?.PUBLIC_APPWRITE_ENDPOINT, 'relative');
+ logEnv('GROWTH ENDPOINT', env?.PUBLIC_GROWTH_ENDPOINT);
+ log();
+ logDelimiter();
+ await build();
+}
+
+main();