From d742298b0df423e3cde3c615cd982556992785e5 Mon Sep 17 00:00:00 2001 From: Owais Jamil Date: Mon, 22 Dec 2025 13:33:56 -0600 Subject: [PATCH] feat: titlebar with info modal --- apps/web/src/lib/canvas/Canvas.svelte | 2 + apps/web/src/lib/components/TitleBar.svelte | 173 ++++++++++++++++++ apps/web/src/lib/tests/Canvas.history.test.ts | 2 +- apps/web/src/lib/tests/Canvas.svelte.test.ts | 9 +- .../web/src/lib/tests/TitleBar.svelte.test.ts | 26 +++ 5 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 apps/web/src/lib/components/TitleBar.svelte create mode 100644 apps/web/src/lib/tests/TitleBar.svelte.test.ts diff --git a/apps/web/src/lib/canvas/Canvas.svelte b/apps/web/src/lib/canvas/Canvas.svelte index 2865de4..0fd459a 100644 --- a/apps/web/src/lib/canvas/Canvas.svelte +++ b/apps/web/src/lib/canvas/Canvas.svelte @@ -1,6 +1,7 @@
+ diff --git a/apps/web/src/lib/components/TitleBar.svelte b/apps/web/src/lib/components/TitleBar.svelte new file mode 100644 index 0000000..b85b06e --- /dev/null +++ b/apps/web/src/lib/components/TitleBar.svelte @@ -0,0 +1,173 @@ + + +
+
+ +
+
Inkfinite
+
Infinite canvas playground
+
+
+
+ +
+ + +
+

About Inkfinite

+

+ Inkfinite is a Svelte-native infinite canvas prototype. The goal is to build a cross-platform editor with a + framework-agnostic core so the same engine powers both the web and desktop apps. +

+ +
+

Quick Tips

+
    + {#each keyboardTips as tip} +
  • {tip}
  • + {/each} +
+
+ +
+

Need help?

+ +
+
+
+ + diff --git a/apps/web/src/lib/tests/Canvas.history.test.ts b/apps/web/src/lib/tests/Canvas.history.test.ts index 9d2ba6d..39c206d 100644 --- a/apps/web/src/lib/tests/Canvas.history.test.ts +++ b/apps/web/src/lib/tests/Canvas.history.test.ts @@ -53,7 +53,7 @@ vi.mock( update: () => {}, }), createSnapStore: () => ({ - get: () => ({ snapEnabled: false, gridEnabled: false, gridSize: 10 }), + get: () => ({ snapEnabled: false, gridEnabled: true, gridSize: 25 }), subscribe: () => () => {}, update: () => {}, set: () => {}, diff --git a/apps/web/src/lib/tests/Canvas.svelte.test.ts b/apps/web/src/lib/tests/Canvas.svelte.test.ts index 3a673d9..f130000 100644 --- a/apps/web/src/lib/tests/Canvas.svelte.test.ts +++ b/apps/web/src/lib/tests/Canvas.svelte.test.ts @@ -23,7 +23,7 @@ vi.mock("$lib/status", () => { update: () => {}, }), createSnapStore: () => ({ - get: () => ({ snapEnabled: false, gridEnabled: false, gridSize: 10 }), + get: () => ({ snapEnabled: false, gridEnabled: true, gridSize: 25 }), subscribe: () => () => {}, update: () => {}, set: () => {}, @@ -104,6 +104,13 @@ describe("Canvas component", () => { expect(statusBar).toBeTruthy(); }); + it("should render the header with info button", () => { + const { container } = render(Canvas); + const titleBar = container.querySelector(".titlebar"); + expect(titleBar).toBeTruthy(); + expect(titleBar?.querySelector(".titlebar__info")).toBeTruthy(); + }); + it("should render all tool buttons in toolbar", () => { const { container } = render(Canvas); const toolButtons = container.querySelectorAll(".tool-button"); diff --git a/apps/web/src/lib/tests/TitleBar.svelte.test.ts b/apps/web/src/lib/tests/TitleBar.svelte.test.ts new file mode 100644 index 0000000..98ee1f1 --- /dev/null +++ b/apps/web/src/lib/tests/TitleBar.svelte.test.ts @@ -0,0 +1,26 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { cleanup, render } from "vitest-browser-svelte"; +import TitleBar from "../components/TitleBar.svelte"; + +describe("TitleBar", () => { + beforeEach(() => { + cleanup(); + }); + + it("renders title/logo and info button", () => { + const { container } = render(TitleBar); + expect(container.querySelector(".titlebar")).toBeTruthy(); + expect(container.querySelector(".titlebar__logo")?.textContent).toContain("∞"); + expect(container.querySelector(".titlebar__info")).toBeTruthy(); + }); + + it("opens info dialog when button clicked", async () => { + const { container } = render(TitleBar); + const button = container.querySelector(".titlebar__info") as HTMLButtonElement; + expect(button).toBeTruthy(); + + button.click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(container.querySelector(".about")).toBeTruthy(); + }); +}); -- 2.51.2