From a0f0486590dfcffc6c7399bd1d99870c2f6588e2 Mon Sep 17 00:00:00 2001 From: sfja Date: Wed, 10 Jun 2026 05:19:22 +0200 Subject: [PATCH] add tabbar --- editor/src/App.tsx | 10 +++- editor/src/Canvas.tsx | 8 +-- editor/src/Tabbar.tsx | 20 +++++++ editor/src/Toolbar.tsx | 30 ++++++---- editor/src/editor/Editor.ts | 1 - editor/src/editor/Renderer.ts | 11 +++- editor/src/index.css | 9 ++- editor/src/style.css | 110 +++++++++++++++++++++++++--------- 8 files changed, 148 insertions(+), 51 deletions(-) create mode 100644 editor/src/Tabbar.tsx diff --git a/editor/src/App.tsx b/editor/src/App.tsx index 9da2f87..b198aa4 100644 --- a/editor/src/App.tsx +++ b/editor/src/App.tsx @@ -3,6 +3,7 @@ import "./style.css"; import Canvas from "./Canvas"; import { Editor } from "./editor/Editor"; import Toolbar from "./Toolbar"; +import Tabbar from "./Tabbar"; function App(): ReactElement { const [editor] = useState(() => new Editor()); @@ -12,8 +13,13 @@ function App(): ReactElement { <>

nandsim

- - +
+ +
+
+ + +
); diff --git a/editor/src/Canvas.tsx b/editor/src/Canvas.tsx index 698ac13..e5c07ec 100644 --- a/editor/src/Canvas.tsx +++ b/editor/src/Canvas.tsx @@ -5,11 +5,9 @@ import { v2 } from "./editor/V2"; type Props = { editor: Editor; canvasRef: RefObject; - width: number; - height: number; }; -function Canvas({ editor, canvasRef, width, height }: Props): ReactElement { +function Canvas({ editor, canvasRef }: Props): ReactElement { useEffect(() => { if (!canvasRef.current) return; @@ -21,9 +19,7 @@ function Canvas({ editor, canvasRef, width, height }: Props): ReactElement {
{ const pos = v2(ev.nativeEvent.offsetX, ev.nativeEvent.offsetY); diff --git a/editor/src/Tabbar.tsx b/editor/src/Tabbar.tsx new file mode 100644 index 0000000..2fdf3d5 --- /dev/null +++ b/editor/src/Tabbar.tsx @@ -0,0 +1,20 @@ +import { useEffect, useState, type ReactElement } from "react"; +import type { Editor } from "./editor/Editor"; + +type Props = { editor: Editor }; + +function Tabbar({ editor }: Props): ReactElement { + const [selectedTool, setSelectedTool] = useState("select"); + + return ( + <> +
+ + + +
+ + ); +} + +export default Tabbar; diff --git a/editor/src/Toolbar.tsx b/editor/src/Toolbar.tsx index 02b97c3..8afe452 100644 --- a/editor/src/Toolbar.tsx +++ b/editor/src/Toolbar.tsx @@ -15,18 +15,24 @@ function Toolbar({ editor, canvasRef }: Props): ReactElement { return ( <>
- {editor.tools().map((tool, key) => ( - - ))} +

Toolbar

+
+ {editor.tools().map((tool, key) => ( + + ))} +
+
+ +
); diff --git a/editor/src/editor/Editor.ts b/editor/src/editor/Editor.ts index d4bf320..a119f4e 100644 --- a/editor/src/editor/Editor.ts +++ b/editor/src/editor/Editor.ts @@ -1,6 +1,5 @@ import { Cx, type Tool } from "./Cx"; import { EventBus } from "./events"; -import { V2 } from "./V2"; export class Editor { public events = new EventBus(); diff --git a/editor/src/editor/Renderer.ts b/editor/src/editor/Renderer.ts index dc2e4b1..c875fba 100644 --- a/editor/src/editor/Renderer.ts +++ b/editor/src/editor/Renderer.ts @@ -14,6 +14,13 @@ export class Renderer { clear() { const { canvas, c } = this; + + const width = canvas.offsetWidth; + const height = canvas.offsetHeight; + + canvas.width = width; + canvas.height = height; + c.fillStyle = "#666"; c.fillRect(0, 0, canvas.width, canvas.height); } @@ -25,8 +32,8 @@ export class Renderer { const gridSize = v2(20, 20); c.fillStyle = "#111"; - for (let y = 0; y < canvas.width / gridSize.x + 1; ++y) { - for (let x = 0; x < canvas.height / gridSize.y + 1; ++x) { + for (let y = 0; y < canvas.height / gridSize.y + 1; ++y) { + for (let x = 0; x < canvas.width / gridSize.x + 1; ++x) { c.fillRect( (this.offset.x % gridSize.x) + x * gridSize.x - dotSize.x / 2, (this.offset.y % gridSize.y) + y * gridSize.y - dotSize.y / 2, diff --git a/editor/src/index.css b/editor/src/index.css index d33751d..3965d58 100644 --- a/editor/src/index.css +++ b/editor/src/index.css @@ -2,14 +2,21 @@ color-scheme: light dark; } +* { + font-family: sans; +} + #root { margin: 0 auto; - min-height: 100svh; + height: 100svh; text-align: center; + display: flex; + flex-direction: column; } body { margin: 0; + height: 100vh; } h1 { diff --git a/editor/src/style.css b/editor/src/style.css index a4c629c..4ecab00 100644 --- a/editor/src/style.css +++ b/editor/src/style.css @@ -1,37 +1,93 @@ - .Editor { - display: flex; - flex-direction: row; - justify-content: center; - - .Toolbar { + display: flex; + flex-direction: row; + justify-content: center; + height: 100%; + .Toolbar { display: flex; flex-direction: column; gap: 2px; + max-width: 300px; + height: 100%; + background-color: #2b2a33; - button { - padding-left: 5px; - padding-right: 5px; - padding-top: 5px; - padding-bottom: 5px; - - font-size: 1rem; - text-transform: capitalize; - - width: 200px; - text-align: left; - border: 2px solid gray; - border-radius: 5px; - } - button.active { - border: 2px solid #ff8800; - } + h2 { + margin: 0; } - .Canvas { - canvas { - image-rendering: pixelated; - } + button { + padding-left: 20px; + padding-right: 20px; + padding-top: 5px; + padding-bottom: 5px; + + font-size: 1rem; + text-transform: capitalize; + font-weight: bold; + + min-width: 200px; + width: 100%; + text-align: left; + border: none; + border-bottom: 2px solid #2b2a33; } + button.active { + background-color: #373541; + border-bottom: 2px solid #ff8800; + } + + button.add { + text-align: center; + } + } + + .Tabbar { + display: flex; + flex-direction: row; + gap: 2px; + + button { + padding-left: 5px; + padding-right: 5px; + padding-top: 5px; + padding-bottom: 5px; + + font-size: 1rem; + text-transform: capitalize; + + max-width: 200px; + text-align: left; + border-radius: 10px 10px 0 0; + + border: none; + border-bottom: 2px solid #2b2a33; + } + button.active { + border-bottom: 2px solid #ff8800; + } + } + + .Canvas { + width: 100%; + height: 100%; + + canvas { + width: 100%; + height: 100%; + + image-rendering: pixelated; + } + } + + > div, + > main { + display: flex; + flex-direction: column; + } + + main { + height: 100%; + width: 100%; + } }