From 89502213c4b83cb195e72a0a93c8305ea69aed61 Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 18 Oct 2024 22:05:01 -0600 Subject: [PATCH] world setup --- deno.json | 6 +- deno.lock | 94 ++++++++++++++++++++++- index.html | 3 + main.ts | 66 ----------------- server/main.ts | 135 ++++++++++++++++++++++++++++++++++ src/app.tsx | 7 +- src/{index.css => index.less} | 16 +++- src/main.tsx | 7 +- src/views/editor.tsx | 3 + src/views/home.tsx | 94 ++++++++++++++++++++--- vite.config.ts | 7 +- 11 files changed, 346 insertions(+), 92 deletions(-) delete mode 100644 main.ts create mode 100644 server/main.ts rename src/{index.css => index.less} (64%) create mode 100644 src/views/editor.tsx diff --git a/deno.json b/deno.json index af96e7d..d7a5bcd 100644 --- a/deno.json +++ b/deno.json @@ -1,9 +1,9 @@ { "tasks": { - "dev": "deno run -A --node-modules-dir npm:vite & deno run --allow-net --allow-read --allow-write --allow-env --watch ./main.ts", + "dev": "deno run -A --node-modules-dir npm:vite & deno run --allow-net --allow-read --allow-write --allow-env --watch ./server/main.ts", "build": "deno run -A --node-modules-dir npm:vite build", "preview": "deno run -A --node-modules-dir npm:vite preview", - "serve": "deno run --allow-net --allow-read --allow-write --allow-env ./main.ts" + "serve": "deno run --allow-net --allow-read --allow-write --allow-env ./server/main.ts" }, "compilerOptions": { "lib": ["ES2020", "DOM", "DOM.Iterable", "deno.ns"], @@ -17,9 +17,11 @@ "@cgg/sockpuppet/client": "../sockpuppet.ts/client/mod.ts", "@deno/vite-plugin": "npm:@deno/vite-plugin@^1.0.0", "@preact/preset-vite": "npm:@preact/preset-vite@^2.9.1", + "@std/fs": "jsr:@std/fs@^1.0.4", "@std/http": "jsr:@std/http@^1.0.8", "autoprefixer": "npm:autoprefixer@^10.4.20", "babel-plugin-transform-hook-names": "npm:babel-plugin-transform-hook-names@^1.0.2", + "less": "npm:less@^4.2.0", "postcss": "npm:postcss@^8.4.47", "preact": "npm:preact@^10.24.3", "react-router-dom": "npm:react-router-dom@^6.27.0", diff --git a/deno.lock b/deno.lock index 4f07b4d..460a2cb 100644 --- a/deno.lock +++ b/deno.lock @@ -18,6 +18,7 @@ "npm:@types/node@*": "22.5.4", "npm:autoprefixer@^10.4.20": "10.4.20_postcss@8.4.47", "npm:babel-plugin-transform-hook-names@^1.0.2": "1.0.2_@babel+core@7.25.8", + "npm:less@^4.2.0": "4.2.0", "npm:postcss@^8.4.47": "8.4.47", "npm:preact@^10.24.3": "10.24.3", "npm:react-router-dom@^6.27.0": "6.27.0_react@18.3.1_react-dom@18.3.1__react@18.3.1", @@ -111,7 +112,7 @@ "debug", "gensync", "json5", - "semver" + "semver@6.3.1" ] }, "@babel/generator@7.25.7": { @@ -136,7 +137,7 @@ "@babel/helper-validator-option", "browserslist", "lru-cache@5.1.1", - "semver" + "semver@6.3.1" ] }, "@babel/helper-module-imports@7.25.7": { @@ -394,7 +395,7 @@ "kolorist", "magic-string", "node-html-parser", - "source-map", + "source-map@0.7.4", "stack-trace", "vite" ] @@ -623,6 +624,12 @@ "convert-source-map@2.0.0": { "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, + "copy-anything@2.0.6": { + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dependencies": [ + "is-what" + ] + }, "cross-spawn@7.0.3": { "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dependencies": [ @@ -699,6 +706,12 @@ "entities@4.5.0": { "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" }, + "errno@0.1.8": { + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dependencies": [ + "prr" + ] + }, "esbuild@0.21.5": { "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dependencies": [ @@ -803,6 +816,9 @@ "globals@11.12.0": { "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, + "graceful-fs@4.2.11": { + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, "has-flag@3.0.0": { "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, @@ -815,6 +831,15 @@ "he@1.2.0": { "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, + "iconv-lite@0.6.3": { + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": [ + "safer-buffer" + ] + }, + "image-size@0.5.5": { + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==" + }, "is-binary-path@2.1.0": { "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dependencies": [ @@ -842,6 +867,9 @@ "is-number@7.0.0": { "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, + "is-what@3.14.1": { + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" + }, "isexe@2.0.0": { "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, @@ -867,6 +895,21 @@ "kolorist@1.8.0": { "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==" }, + "less@4.2.0": { + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "dependencies": [ + "copy-anything", + "errno", + "graceful-fs", + "image-size", + "make-dir", + "mime", + "needle", + "parse-node-version", + "source-map@0.6.1", + "tslib" + ] + }, "lilconfig@2.1.0": { "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==" }, @@ -897,6 +940,13 @@ "@jridgewell/sourcemap-codec" ] }, + "make-dir@2.1.0": { + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dependencies": [ + "pify@4.0.1", + "semver@5.7.2" + ] + }, "merge2@1.4.1": { "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, @@ -907,6 +957,9 @@ "picomatch" ] }, + "mime@1.6.0": { + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, "minimatch@9.0.5": { "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dependencies": [ @@ -930,6 +983,13 @@ "nanoid@3.3.7": { "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" }, + "needle@3.3.1": { + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "dependencies": [ + "iconv-lite", + "sax" + ] + }, "node-html-parser@6.1.13": { "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", "dependencies": [ @@ -961,6 +1021,9 @@ "package-json-from-dist@1.0.1": { "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" }, + "parse-node-version@1.0.1": { + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==" + }, "path-key@3.1.1": { "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, @@ -983,6 +1046,9 @@ "pify@2.3.0": { "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" }, + "pify@4.0.1": { + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, "pirates@4.0.6": { "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==" }, @@ -1038,6 +1104,9 @@ "preact@10.24.3": { "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==" }, + "prr@1.0.1": { + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==" + }, "queue-microtask@1.2.3": { "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, @@ -1074,7 +1143,7 @@ "read-cache@1.0.0": { "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", "dependencies": [ - "pify" + "pify@2.3.0" ] }, "readdirp@3.6.0": { @@ -1123,12 +1192,21 @@ "queue-microtask" ] }, + "safer-buffer@2.1.2": { + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax@1.4.1": { + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + }, "scheduler@0.23.2": { "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dependencies": [ "loose-envify" ] }, + "semver@5.7.2": { + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + }, "semver@6.3.1": { "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" }, @@ -1147,6 +1225,9 @@ "source-map-js@1.2.1": { "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" }, + "source-map@0.6.1": { + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, "source-map@0.7.4": { "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" }, @@ -1253,6 +1334,9 @@ "ts-interface-checker@0.1.13": { "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, + "tslib@2.8.0": { + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==" + }, "undici-types@6.19.8": { "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, @@ -1308,12 +1392,14 @@ "workspace": { "dependencies": [ "jsr:@bearmetal/store@^0.0.4", + "jsr:@std/fs@^1.0.4", "jsr:@std/http@^1.0.8", "npm:@babel/plugin-transform-react-jsx-development@^7.25.7", "npm:@deno/vite-plugin@1", "npm:@preact/preset-vite@^2.9.1", "npm:autoprefixer@^10.4.20", "npm:babel-plugin-transform-hook-names@^1.0.2", + "npm:less@^4.2.0", "npm:postcss@^8.4.47", "npm:preact@^10.24.3", "npm:react-router-dom@^6.27.0", diff --git a/index.html b/index.html index 40366c3..d87d9b9 100644 --- a/index.html +++ b/index.html @@ -5,6 +5,9 @@ Vite + Preact + TS +
diff --git a/main.ts b/main.ts deleted file mode 100644 index 0de1194..0000000 --- a/main.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { SockpuppetPlus } from "@cgg/sockpuppet"; -import { serveDir } from "@std/http/file-server"; -import { BearMetalStore } from "@bearmetal/store"; - -const installPath = Deno.env.get("BMP_INSTALL_DIR") || "./"; - -const sockpuppet = new SockpuppetPlus(); -sockpuppet.addHandler((req: Request) => { - if (new URL(req.url).pathname.startsWith("/api")) return; - - return serveDir(req, { - fsRoot: installPath + "dist", - }); -}); - -sockpuppet.addHandler(async (req: Request) => { - if (!new URL(req.url).pathname.startsWith("/api")) return; - const store = new BearMetalStore(); - - console.log("API", req.url); - - const API_DIR_ROUTE = new URLPattern({ - pathname: "/api/dir", - search: "?list", - }); - - const match = API_DIR_ROUTE.exec(req.url); - if (!match) return; - - switch (req.method) { - case "GET": { - const mcPath = store.get("mcPath") as string; - if (mcPath) { - for await (const file of Deno.readDir(mcPath)) { - if (file.isDirectory && file.name.startsWith("saves")) { - const worlds: string[] = []; - for await (const world of Deno.readDir(mcPath + "/" + file.name)) { - if (world.isDirectory) { - worlds.push(world.name); - } - } - return new Response(JSON.stringify({ worlds, mcPath }), { - status: 200, - }); - } - } - } - return new Response(JSON.stringify({ mcPath }), { - status: mcPath ? 200 : 500, - }); - } - case "POST": { - const formData = await req.formData(); - const dir = formData.get("dir") as string; - if (!dir) return new Response(null, { status: 400 }); - - Deno.env.set("MC_PATH", dir); - const mcPath = Deno.env.get("MC_PATH"); - if (!mcPath) return new Response(null, { status: 500 }); - - return new Response(null, { status: 200 }); - } - default: - return new Response(null, { status: 405 }); - } -}); diff --git a/server/main.ts b/server/main.ts new file mode 100644 index 0000000..5985de8 --- /dev/null +++ b/server/main.ts @@ -0,0 +1,135 @@ +import { SockpuppetPlus } from "@cgg/sockpuppet"; +import { serveDir, serveFile } from "@std/http/file-server"; +import { BearMetalStore } from "@bearmetal/store"; +import { ensureDir } from "@std/fs"; + +const installPath = Deno.env.get("BMP_INSTALL_DIR") || "./"; + +const sockpuppet = new SockpuppetPlus(); +sockpuppet.addHandler(async (req: Request) => { + console.log(req.url); + const url = new URL(req.url); + if (!url.pathname.startsWith("/images")) return; + + return serveFile(req, url.searchParams.get("location") as string); +}); + +sockpuppet.addHandler((req: Request) => { + if (new URL(req.url).pathname.startsWith("/api")) return; + + return serveDir(req, { + fsRoot: installPath + "dist", + }); +}); + +sockpuppet.addHandler(async (req: Request) => { + if (!new URL(req.url).pathname.startsWith("/api")) return; + const store = new BearMetalStore(); + + const API_DIR_ROUTE = new URLPattern({ + pathname: "/api/dir", + }); + + const match = API_DIR_ROUTE.exec(req.url); + if (!match) return; + + switch (req.method) { + case "GET": { + const mcPath = store.get("mcPath") as string; + if (mcPath) { + const worlds: { + world: string; + icon: string; + path: string; + }[] = []; + try { + for await (const file of Deno.readDir(mcPath)) { + if (file.isDirectory && file.name.startsWith("saves")) { + for await ( + const world of Deno.readDir(mcPath + "/" + file.name) + ) { + if (world.isDirectory) { + for await ( + const f of Deno.readDir( + mcPath + "/" + file.name + "/" + world.name, + ) + ) { + if (f.name.endsWith(".dat")) { + worlds.push({ + world: world.name, + icon: Deno.realPathSync( + mcPath + "/" + file.name + "/" + world.name + + "/icon.png", + ), + path: Deno.realPathSync( + mcPath + "/" + file.name + "/" + world.name, + ), + }); + } + } + } + } + } + } + } catch (e: any) { + store.set("mcPath", ""); + return new Response(e, { status: 500 }); + } + return new Response(JSON.stringify({ worlds, mcPath }), { + status: 200, + }); + } + return new Response(JSON.stringify({ mcPath }), { + status: mcPath ? 200 : 500, + }); + } + case "POST": { + const formData = await req.formData(); + const dir = formData.get("mcPath") as string; + if (!dir) return new Response(null, { status: 400 }); + + store.set("mcPath", dir); + if (!store.get("mcPath")) return new Response(null, { status: 500 }); + + return new Response(null, { status: 200 }); + } + default: + return new Response(null, { status: 405 }); + } +}); + +sockpuppet.addHandler(async (req: Request) => { + if (!new URL(req.url).pathname.startsWith("/api")) return; + const store = new BearMetalStore(); + + const API_WORLD_ROUTE = new URLPattern({ + pathname: "/api/world", + }); + + const match = API_WORLD_ROUTE.exec(req.url); + if (!match) return; + + switch (req.method) { + case "GET": { + return new Response(store.get("world").split("/").pop() || "", { + status: 200, + }); + } + case "POST": { + const worldPath = await req.text(); + if (!worldPath) return new Response(null, { status: 400 }); + + const mcPath = store.get("mcPath") as string; + if (!mcPath) { + return new Response("Tried to set world, but MC path is not set.", { + status: 500, + }); + } + const realWorldPath = Deno.realPathSync(worldPath); + store.set("world", realWorldPath); + store.set("packlocation", realWorldPath + "/datapacks/bmp_dev"); + await ensureDir(store.get("packlocation") as string); + return new Response(null, { status: 200 }); + } + } +}); diff --git a/src/app.tsx b/src/app.tsx index cfba4d1..02f867b 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,13 +1,14 @@ -import { BrowserRouter,Routes,Route } from "react-router-dom"; +import { BrowserRouter, Route, Routes } from "react-router-dom"; import { Home } from "./views/home.tsx"; +import { Editor } from "./views/editor.tsx"; export function App() { - return ( + - ) + ); } diff --git a/src/index.css b/src/index.less similarity index 64% rename from src/index.css rename to src/index.less index 83ebf9f..1430a9d 100644 --- a/src/index.css +++ b/src/index.less @@ -6,13 +6,27 @@ :root { @apply dark:bg-mixed-600 bg-primary-100 text-dark-600 dark:text-white; } + * { box-sizing: border-box; } - body, #app, html { + + body, + #app, + html { @apply h-full; } + button { @apply bg-primary-600 text-white rounded-md px-4 py-2 font-bold; } + + input, + select { + @apply bg-white text-dark-600 rounded-md px-4 py-2 font-bold; + + &:not(:last-child) { + @apply mr-2; + } + } } \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index 125b2d5..b030787 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,5 +1,4 @@ -import { render } from 'preact' -import { App } from './app.tsx' -import './index.css' +import { render } from "preact"; +import { App } from "./app.tsx"; -render(, document.getElementById('app') as HTMLElement) +render(, document.getElementById("app") as HTMLElement); diff --git a/src/views/editor.tsx b/src/views/editor.tsx new file mode 100644 index 0000000..2cfba90 --- /dev/null +++ b/src/views/editor.tsx @@ -0,0 +1,3 @@ +export const Editor = () => { + return
Editor
; +}; diff --git a/src/views/home.tsx b/src/views/home.tsx index 30c9a8c..a951f39 100644 --- a/src/views/home.tsx +++ b/src/views/home.tsx @@ -1,25 +1,99 @@ import { useEffect, useState } from "preact/hooks"; +import { useNavigate } from "react-router-dom"; export function Home() { const [loading, setLoading] = useState(true); const [mcPath, setMcPath] = useState(""); + const [worlds, setWorlds] = useState<{ + world: string; + icon: string; + path: string; + }[]>([]); + + const fetchWorlds = async () => { + const res = await fetch("/api/dir"); + const json = await res.json(); + setMcPath(json.mcPath); + setWorlds(json.worlds); + setLoading(false); + }; useEffect(() => { document.title = "BearMetal Packer"; - - fetch("/api/dir").then(res => res.json()).then(data => { - setMcPath(data); - setLoading(false); - }); + fetchWorlds(); }, []); - + + const submitMcPath = async (event: SubmitEvent) => { + setLoading(true); + event.preventDefault(); + const form = new FormData(event.target as HTMLFormElement); + const res = await fetch("/api/dir", { + method: "POST", + body: form, + }); + if (res.status === 200) { + fetchWorlds(); + } else setLoading(false); + }; + + const nav = useNavigate(); + + const setWorld = async (worldPath: string) => { + setLoading(true); + const res = await fetch("/api/world", { + method: "POST", + body: worldPath, + }); + + if (res.status === 200) { + nav("/editor"); + } else setLoading(false); + }; + return (
-
+

Welcome BearMetal Packer

An all in one toolkit to build datapacks for Minecraft.

-

Hold tight, we're doing some heavy lifting.

+ {loading ?

Hold tight, we're doing some heavy lifting.

: ( + <> + {mcPath + ? ( + <> +

Minecraft directory set to {mcPath}

+

Worlds:

+
    + {worlds.map((world) => ( +
  • setWorld(world.path)} + > + + {world.world} +
  • + ))} +
+ + ) + : ( + <> +

No Minecraft directory set, please set now:

+
+ + +
+ + )} + + )}
- ) -} \ No newline at end of file + ); +} diff --git a/vite.config.ts b/vite.config.ts index 8865a73..0ffc5a1 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -16,12 +16,15 @@ export default defineConfig({ "/api": { target: "http://localhost:8000", changeOrigin: true, - // rewrite: (path) => path.replace(/^\/api/, ""), }, "/puppet": { target: "http://localhost:8000", changeOrigin: true, - // rewrite: (path) => path.replace(/^\/puppet/, ""), + ws: true, + }, + "/images": { + target: "http://localhost:8000", + changeOrigin: true, ws: true, }, },