From 12fff735867d3984f7ff824b2a93b1093f8910d7 Mon Sep 17 00:00:00 2001 From: MetroWind Date: Fri, 29 Aug 2025 21:58:39 -0700 Subject: WIP --- index.html | 22 +++++++++++++ scripts/lib.js | 10 ++++++ scripts/main.js | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ scripts/tiles.js | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ styles.css | 23 ++++++++++++++ 5 files changed, 242 insertions(+) create mode 100644 index.html create mode 100644 scripts/lib.js create mode 100644 scripts/main.js create mode 100644 scripts/tiles.js create mode 100644 styles.css diff --git a/index.html b/index.html new file mode 100644 index 0000000..f46f57c --- /dev/null +++ b/index.html @@ -0,0 +1,22 @@ + + + + + + + + + + + + My test page + + +
+
+ + diff --git a/scripts/lib.js b/scripts/lib.js new file mode 100644 index 0000000..4e4850e --- /dev/null +++ b/scripts/lib.js @@ -0,0 +1,10 @@ +const h = preact.h; +const CELL_SIZE = 32; +const GRID_SIZE_X = 21; +const GRID_SIZE_Y = 21; + +const ASSET_SVG_PROPS = {"width": CELL_SIZE, "height": CELL_SIZE, + "version": "1.1"}; +const ASSET_WHITE_BG = h("rect", {"x": 0, "y": 0, "width": CELL_SIZE, + "height": CELL_SIZE, "fill": "white", + "stroke-width": 0 }); diff --git a/scripts/main.js b/scripts/main.js new file mode 100644 index 0000000..7a8b9d4 --- /dev/null +++ b/scripts/main.js @@ -0,0 +1,93 @@ +function genGrid(x_count, y_count, cell_size) +{ + let lines = []; + for(let x = 0; x < x_count+1; x++) + { + lines.push(h("line", { + "x1": x * cell_size + 0.5, "x2": x * cell_size + 0.5, "y1": 0.5, + "y2": y_count * cell_size + 0.5, + })); + } + for(let y = 0; y < y_count+1; y++) + { + lines.push(h("line", { + "y1": y * cell_size + 0.5, "y2": y * cell_size + 0.5, "x1": 0.5, + "x2": x_count * cell_size + 0.5, + })); + } + return h("g", {"stroke": "black", "stroke-width": 1}, lines); +} + +function AssetView({asset_index}) +{ + return h("div", {"class": "Asset", "draggable": true, + "id": `Asset${asset_index}`}, + h("svg", ASSET_SVG_PROPS, ASSET_WHITE_BG, + TILES[asset_index].inner_svg)); +} + +function AssetsView() +{ + let views = TILES.slice(1).map((t, i) => + h(AssetView, {asset_index: i + 1})); + return h("div", {}, views); +} + +function PlanGridView({content}) +{ + const [mouse_coord, setMouseCoord] = preactHooks.useState(null); + + function onDragOver(e) + { + e.preventDefault(); + let b = e.target.getBoundingClientRect(); + let x = e.clientX - b.left; + let y = e.clientY - b.top; + setMouseCoord([x, y]); + } + + function onDragLeave(e) + { + setMouseCoord(null); + } + + let hilight_box = null; + if(mouse_coord !== null) + { + let cell_x = Math.floor(mouse_coord[0] / (CELL_SIZE + 1)); + let cell_y = Math.floor(mouse_coord[1] / (CELL_SIZE + 1)); + hilight_box = h("rect", { + "x": cell_x * (CELL_SIZE + 1) + 0.5, "y": cell_y * (CELL_SIZE + 1) + 0.5, + "width": CELL_SIZE + 1, "height": CELL_SIZE + 1, + "stroke": "#2ed573", "stroke-width": 3, "fill": "transparent"}); + } + let grid_content = content.map((idx, i) => { + let cell_x = i % GRID_SIZE_X; + let cell_y = Math.floor(i / GRID_SIZE_Y); + return h("g", {"transform": `translate(${cell_x * (CELL_SIZE + 1)} \ +${cell_y * (CELL_SIZE + 1)})`}, TILES[idx]); + }); + + return h("svg", {"width": GRID_SIZE_X * (CELL_SIZE + 1) + 1, + "height": GRID_SIZE_Y * (CELL_SIZE + 1) + 1, + "version": "1.1", "ondragover": onDragOver, + "id": "Grid", "ondragleave": onDragLeave}, + grid_content, genGrid(GRID_SIZE_X, GRID_SIZE_Y, CELL_SIZE + 1), + hilight_box); +} + +function PlanView(props) +{ + return h("div", {}, + h("p", {}, "The plan:"), + h(PlanGridView, {})); +} + +function App(props) +{ + return h("div", {}, + h(AssetsView, {}), + h(PlanView, {})); +} + +preact.render(h(App, {}), document.getElementById("Plan")); diff --git a/scripts/tiles.js b/scripts/tiles.js new file mode 100644 index 0000000..f35887a --- /dev/null +++ b/scripts/tiles.js @@ -0,0 +1,94 @@ +const TILES = [ + null, + { + id: "blank", + name: "black", + inner_svg: null, + }, { + id: "teleporter", + name: "teleporter", + inner_svg: h("circle", { + "cx": CELL_SIZE * 0.5, "cy": CELL_SIZE * 0.5, + "r": (CELL_SIZE - 10) * 0.5, "stroke": "black", + "fill": "transparent", "stroke-width": 6, + }), + }, { + id: "fleet_command", + name: "fleet command", + inner_svg: h("polyline", { + "points": `3, ${CELL_SIZE} \ +3, ${CELL_SIZE - 15} \ +13, ${CELL_SIZE - 25} \ +13, ${CELL_SIZE - 5} \ +${CELL_SIZE - 13}, ${CELL_SIZE - 5} \ +${CELL_SIZE - 13}, ${CELL_SIZE - 25} \ +${CELL_SIZE - 3}, ${CELL_SIZE - 15} \ +${CELL_SIZE - 3}, ${CELL_SIZE}`, + "fill": "black", "stroke-width": 0, + }), + }, { + id: "scanner", + name: "scanner", + inner_svg: + h(preact.Fragment, {}, + h("circle", {"cx": CELL_SIZE * 0.5, "cy": CELL_SIZE * 0.5, + "r": CELL_SIZE * 0.5 - 2, "fill": "transparent", + "stroke": "black", "stroke-width": 2}), + h("circle", {"cx": CELL_SIZE * 0.5, "cy": CELL_SIZE * 0.5, + "r": CELL_SIZE * 0.25, "fill": "transparent", + "stroke": "black", "stroke-width": 2}), + h("line", {"x1": 2, "y1": CELL_SIZE * 0.5, + "x2": CELL_SIZE - 2, "y2": CELL_SIZE * 0.5, + "stroke": "black", "stroke-width": 2}), + h("line", {"y1": 2, "x1": CELL_SIZE * 0.5, + "y2": CELL_SIZE - 2, "x2": CELL_SIZE * 0.5, + "stroke": "black", "stroke-width": 2}), + h("line", {"x1": CELL_SIZE * 0.5, "y1": CELL_SIZE * 0.5, + "x2": CELL_SIZE * 0.5 + (CELL_SIZE * 0.5 - 2) * Math.cos(Math.PI / 6), + "y2": CELL_SIZE * 0.5 - (CELL_SIZE * 0.5 - 2) * Math.sin(Math.PI / 6), + "stroke": "black", "stroke-width": 2}), + h("circle", {"cx": 22, "cy": 6, "r": 2, "fill": "black", + "stroke-width": 0}), + h("circle", {"cx": 10, "cy": 22, "r": 4, "fill": "black", + "stroke-width": 0}), + + ), + }, { + id: "extractor", + name: "stellar extractor", + inner_svg: + h(preact.Fragment, {}, + h("circle", {"cx": CELL_SIZE * 0.5, "cy": 21, + "r": 10, "fill": "black", "stroke-width": 0}), + h("polygon", {"points": `${CELL_SIZE * 0.5 - 4}, 20 \ +${CELL_SIZE * 0.5 - 4}, 10 \ +${CELL_SIZE * 0.5 - 8}, 10 \ +${CELL_SIZE * 0.5}, 3 \ +${CELL_SIZE * 0.5 + 8}, 10 \ +${CELL_SIZE * 0.5 + 4}, 10 \ +${CELL_SIZE * 0.5 + 4}, 20`, + "stroke": "black", "stroke-width": 2, + "fill": "white"}), + ), + }, { + id: "storage", + name: "storage", + inner_svg: + h(preact.Fragment, {}, + h("rect", {"x": 4, "y": 4, "width": CELL_SIZE - 8, + "height": CELL_SIZE - 8, "rx": 2, "ry": 2, + "fill": "black", "stroke-width": 0}), + h("line", {"x1": 4, "y1": 14, "x2": CELL_SIZE - 4, "y2": 14, + "stroke": "white", "stroke-width": 2}), + h("rect", {"x": CELL_SIZE * 0.5 - 4, "y": 10, "width": 8, "height": 8, + "fill": "white", "stroke-width": 0}), + ), + }, { + id: "plant", + name: "double cultivation chamber", + inner_svg: h("path", {"d": "m3.02 17.7a13 13 0 0013 13 13 13 0 00-13-13m13 13a13 13 0 0013-13 13 13 0 00-13 13m8.66-27.4v7.21a8.66 8.66 0 01-8.66 8.66 8.66 8.66 0 01-8.66-8.66v-7.21c1.07 0 2.12.173 3.12.563.793.332 1.5.821 2.09 1.44l3.43-3.43 3.43 3.43c.591-.622 1.3-1.11 2.09-1.44.996-.388 2.05-.563 3.12-.563z", + "fill": "black", "stroke-width": 0}), + } +]; + +const TILE_MAP = Object.fromEntries(TILES.slice(1).map(t => [t.id, t])); diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..aca9b9b --- /dev/null +++ b/styles.css @@ -0,0 +1,23 @@ +body +{ + background-color: #a4b0be; +} + +* +{ + box-sizing: border-box; +} + +.Asset +{ + display: inline-block; + border: solid black 1px; + width: 34px; + height: 34px; +} + +/* Prevent SVG elements from interferring with drag n drop. */ +#Grid * +{ + pointer-events: none; +} -- cgit v1.2.3-70-g09d2