diff --git a/package.json b/package.json
index 5050b7e5..a671d0d0 100644
--- a/package.json
+++ b/package.json
@@ -47,6 +47,8 @@
"@protobuf-ts/grpcweb-transport": "^2.9.1",
"@protobuf-ts/runtime": "^2.9.1",
"@tauri-apps/api": "^1.5.1",
+ "codejar": "^4.2.0",
+ "highlight.js": "^11.9.0",
"idb-keyval": "^6.2.1",
"svelte-google-materialdesign-icons": "^0.8.2",
"zod": "^3.22.4"
diff --git a/src/lib/GlobalCssProperties.json b/src/lib/GlobalCssProperties.json
index 9f5b3a2f..2d20ddb7 100644
--- a/src/lib/GlobalCssProperties.json
+++ b/src/lib/GlobalCssProperties.json
@@ -95,6 +95,18 @@
0.39901960784,
0.43823529411
],
+ "--editor-keyword-color": [
+ "display-p3",
+ 0.52549019608,
+ 0.58823529411,
+ 0.98823529412
+ ],
+ "--editor-comment-color": [
+ "display-p3",
+ 0.52549019608,
+ 0.52549019608,
+ 0.52549019608
+ ],
"--engine-ui-underline-color": ["display-p3", 1, 1, 1],
"--engine-ui-error-underline-color": [
"display-p3",
@@ -247,6 +259,12 @@
0.14666666666,
0.17019607843
],
+ "--editor-keyword-color": [
+ "display-p3",
+ 0.52549019608,
+ 0.58823529411,
+ 0.98823529412
+ ],
"--engine-ui-underline-color": ["display-p3", 1, 1, 1],
"--engine-ui-error-underline-color": [
"display-p3",
diff --git a/src/lib/classes/styling/ZodSchemas/CSSVariables.ts b/src/lib/classes/styling/ZodSchemas/CSSVariables.ts
index 6d1a4ebc..cdb01a55 100644
--- a/src/lib/classes/styling/ZodSchemas/CSSVariables.ts
+++ b/src/lib/classes/styling/ZodSchemas/CSSVariables.ts
@@ -34,6 +34,8 @@ export const ColorVariables = z
"--sidebar-text-color": ColorAttribute,
"--sidebar-element-color": ColorAttribute,
"--sidebar-element-hover-color": ColorAttribute,
+ "--editor-keyword-color": ColorAttribute,
+ "--editor-comment-color": ColorAttribute,
"--engine-ui-underline-color": ColorAttribute,
"--engine-ui-error-underline-color": ColorAttribute,
"--engine-ui-input-text-placeholder-color": ColorAttribute,
diff --git a/src/lib/components/canvas/Canvas.svelte b/src/lib/components/canvas/Canvas.svelte
new file mode 100644
index 00000000..91d3c239
--- /dev/null
+++ b/src/lib/components/canvas/Canvas.svelte
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/src/lib/components/canvas/CanvasNav.svelte b/src/lib/components/canvas/CanvasNav.svelte
new file mode 100644
index 00000000..0a7a6086
--- /dev/null
+++ b/src/lib/components/canvas/CanvasNav.svelte
@@ -0,0 +1,65 @@
+
+
+
+
+
diff --git a/src/lib/components/canvas/state.ts b/src/lib/components/canvas/state.ts
new file mode 100644
index 00000000..ff940457
--- /dev/null
+++ b/src/lib/components/canvas/state.ts
@@ -0,0 +1,54 @@
+import { Component, GlobalDeclarations, System } from "$lib/classes/automaton";
+import { activeView } from "$lib/globalState/activeProject";
+import { writable } from "svelte/store";
+import { editor } from "$lib/components/editor/state";
+
+export enum CanvasModes {
+ Draw,
+ Editor,
+}
+
+export enum CanvasSupports {
+ OnlyDraw,
+ OnlyEditor,
+ Both,
+}
+
+export const canvasSupports = writable(CanvasSupports.OnlyEditor);
+export const canvasModes = writable(CanvasModes.Editor);
+
+canvasSupports.subscribe((newSupports) => {
+ canvasModes.update((currentMode) => {
+ if (
+ newSupports == CanvasSupports.OnlyEditor &&
+ currentMode == CanvasModes.Draw
+ )
+ return CanvasModes.Editor;
+ else if (
+ newSupports == CanvasSupports.OnlyDraw &&
+ currentMode == CanvasModes.Editor
+ )
+ return CanvasModes.Draw;
+ else return currentMode;
+ });
+});
+
+activeView.subscribe((view) => {
+ if (view instanceof Component) {
+ canvasSupports.set(CanvasSupports.Both);
+ editor.change.set(view.declarations);
+ editor.push.set((code: string) => {
+ view.declarations = code;
+ });
+ } else if (view instanceof System) {
+ canvasSupports.set(CanvasSupports.OnlyDraw);
+ } else if (view instanceof GlobalDeclarations) {
+ canvasSupports.set(CanvasSupports.OnlyEditor);
+ editor.change.set(view.declarations);
+ editor.push.set((code: string) => {
+ view.declarations = code;
+ });
+ } else {
+ canvasSupports.set(CanvasSupports.OnlyEditor);
+ }
+});
diff --git a/src/lib/components/editor/Editor.svelte b/src/lib/components/editor/Editor.svelte
new file mode 100644
index 00000000..b07188b7
--- /dev/null
+++ b/src/lib/components/editor/Editor.svelte
@@ -0,0 +1,131 @@
+
+
+
+
+
diff --git a/src/lib/components/editor/state.ts b/src/lib/components/editor/state.ts
new file mode 100644
index 00000000..9941e3e5
--- /dev/null
+++ b/src/lib/components/editor/state.ts
@@ -0,0 +1,17 @@
+import { writable } from "svelte/store";
+
+/**
+ * A handler for the editor
+ * */
+export const editor = {
+ /**
+ * The writable containing the function that runs whenever the editor pushes
+ * */
+ push: writable((s: string) => {
+ s;
+ }),
+ /**
+ * The writable that whenever set overwrites what is displayed in the editor
+ * */
+ change: writable(""),
+};
diff --git a/src/lib/components/project/globalDeclaration/GlobalDeclaration.svelte b/src/lib/components/project/globalDeclaration/GlobalDeclaration.svelte
index d45cce9d..f0dbe21c 100644
--- a/src/lib/components/project/globalDeclaration/GlobalDeclaration.svelte
+++ b/src/lib/components/project/globalDeclaration/GlobalDeclaration.svelte
@@ -1,8 +1,12 @@
diff --git a/src/lib/components/settings/state.ts b/src/lib/components/settings/state.ts
new file mode 100644
index 00000000..4deec4d1
--- /dev/null
+++ b/src/lib/components/settings/state.ts
@@ -0,0 +1,3 @@
+import { writable } from "svelte/store";
+
+export const showSettings = writable(false);
diff --git a/src/lib/components/svgView/SvgView.svelte b/src/lib/components/svgView/SvgView.svelte
index 67273447..43dfb235 100644
--- a/src/lib/components/svgView/SvgView.svelte
+++ b/src/lib/components/svgView/SvgView.svelte
@@ -11,6 +11,8 @@
import Location from "$lib/components/svgView/Location.svelte";
import { System } from "$lib/classes/automaton";
+ export let isHidden: boolean;
+
/**
* The parent svg element that the entire view is shown with.
*/
@@ -62,6 +64,7 @@
on:pointerdown={(event) => panzoom?.handleDown(event)}
on:wheel={(event) => panzoom?.zoomWithWheel(event)}
class="panzoom-parent"
+ style={isHidden ? "visibility:hidden; height:0px;" : "visibility:visible;"}
>
>();
@@ -186,9 +190,11 @@ class ActiveViewStore implements Writable {
"Cannot set an active view when no project is open",
);
} else if (
- ![...projectValue.components, ...projectValue.systems].includes(
- value,
- )
+ ![
+ ...projectValue.components,
+ ...projectValue.systems,
+ projectValue.globalDeclarations,
+ ].includes(value)
) {
throw new TypeError(
"Cannot set an active view that is not part of the active project",
@@ -246,9 +252,11 @@ function closeActiveViewIfDeleted() {
if (activeViewValue === undefined) return;
if (
!projectValue ||
- ![...projectValue.components, ...projectValue.systems].includes(
- activeViewValue,
- )
+ ![
+ ...projectValue.components,
+ ...projectValue.systems,
+ projectValue.globalDeclarations,
+ ].includes(activeViewValue)
) {
activeView.set(undefined);
}
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 1048c621..c8af29d9 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -4,13 +4,14 @@
import TopBar from "$lib/components/topBar/TopBar.svelte";
import SidePanel from "$lib/components/sidePanel/SidePanel.svelte";
import { SidePanelEnum } from "$lib/components/sidePanel/SidePanelEnum";
- import SvgView from "$lib/components/svgView/SvgView.svelte";
import Console from "$lib/components/console/Console.svelte";
import ProjectNav from "$lib/components/project/ProjectNav.svelte";
import GlobalDeclaration from "$lib/components/project/globalDeclaration/GlobalDeclaration.svelte";
import Queries from "$lib/components/query/Queries.svelte";
import QueryNav from "$lib/components/query/QueryNav.svelte";
import ProjectItems from "$lib/components/project/ProjectItems.svelte";
+ import Canvas from "$lib/components/canvas/Canvas.svelte";
+ import CanvasNav from "$lib/components/canvas/CanvasNav.svelte";
@@ -31,9 +32,8 @@
-
-
-
+
+
@@ -66,12 +66,6 @@
overflow: hidden;
}
- .inner-nav2 {
- background-color: var(--canvas-topbar-color);
- color: var(--navigationbar-text-color);
- border: none;
- }
-
.canvas {
color: var(--canvas-text-color);
display: flex;
diff --git a/tests/lib/components/editor/editor.test.ts b/tests/lib/components/editor/editor.test.ts
new file mode 100644
index 00000000..cf1f143d
--- /dev/null
+++ b/tests/lib/components/editor/editor.test.ts
@@ -0,0 +1,107 @@
+import { test, expect } from "@playwright/test";
+
+test.beforeEach(async ({ page }) => {
+ await page.goto("/");
+ await page.getByRole("button", { name: "Ecdar university" }).click();
+});
+
+test("Write in editor", async ({ page }) => {
+ await page
+ .locator("#administration-1")
+ .getByRole("button", { name: "folder special Administration 1" })
+ .click();
+ const span1 = await page
+ .locator("#editor")
+ .locator(".editor-text")
+ .locator("span")
+ .innerHTML();
+ expect(span1).toBe("clock");
+ await expect(page.getByText("clock z;")).toBeVisible();
+
+ await page.locator("#editor").locator(".editor-text").click();
+ for (let i = 0; i <= 8; i++) {
+ await page.keyboard.press("ArrowRight");
+ }
+ await page.keyboard.press("Enter");
+
+ await page.keyboard.type("clock x;");
+
+ await page
+ .locator("#administration-2")
+ .getByRole("button", { name: "folder special Administration 2" })
+ .click();
+ await page
+ .locator("#administration-1")
+ .getByRole("button", { name: "folder special Administration 1" })
+ .click();
+
+ await expect(page.getByText("clock x;")).toBeVisible();
+});
+
+test("Correct line numbers in editor", async ({ page }) => {
+ function randomLineNumber(min: number, max: number) {
+ return Math.floor(Math.random() * (max - min + 1) + min);
+ }
+
+ await page
+ .locator("#coffee-machine-1")
+ .getByRole("button", { name: "folder special Coffee Machine 1" })
+ .click();
+ await page.locator("#editor").locator(".editor-text").click();
+
+ const createLines = randomLineNumber(5, 30);
+
+ for (let i = 0; i < createLines; i++) {
+ await page.keyboard.press("Enter");
+ }
+
+ await expect(page.locator(".editor-linenum")).toHaveCount(createLines + 1);
+
+ const deleteLines = randomLineNumber(5, createLines);
+
+ for (let i = 0; i < deleteLines; i++) {
+ await page.keyboard.press("Backspace");
+ }
+
+ await expect(page.locator(".editor-linenum")).toHaveCount(
+ createLines + 1 - deleteLines,
+ );
+});
+
+test("Change between editor- and svg-view", async ({ page }) => {
+ await page
+ .locator("#administration-1")
+ .getByRole("button", { name: "folder special Administration 1" })
+ .click();
+ await expect(page.getByText("clock z;")).toBeVisible();
+
+ const toggleDraw = await page
+ .locator("#canvas-nav")
+ .locator("svg")
+ .getAttribute("id");
+ expect(toggleDraw).toBe("toggle-draw");
+
+ await page.locator("#canvas-nav").getByRole("button").click();
+
+ await expect(page.getByText("L0")).toBeVisible();
+ const toggleEditor = await page
+ .locator("#canvas-nav")
+ .locator("svg")
+ .getAttribute("id");
+ expect(toggleEditor).toBe("toggle-editor");
+});
+
+test("Pressing Global Declarations, removes the button to change between draw and editor", async ({
+ page,
+}) => {
+ await page
+ .getByRole("button", { name: "description Global Declarations" })
+ .click();
+
+ const canvasNav = await page
+ .locator("#canvas-nav")
+ .locator("div")
+ .innerHTML();
+
+ expect(canvasNav).toBe(" ");
+});
diff --git a/yarn.lock b/yarn.lock
index b7835cb2..f3e40248 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -916,6 +916,11 @@ code-red@^1.0.3:
estree-walker "^3.0.3"
periscopic "^3.1.0"
+codejar@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/codejar/-/codejar-4.2.0.tgz#ad72aa63f794a16900a1b079eaf44acae84460ca"
+ integrity sha512-U8OZe+2B400W5nSSbXxaoboBN5i1hxWdBZJ9kcTy0DBuc4muwkPE/ph/MGX4yooIE8hztfNLPNU1CbcNYch69A==
+
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
@@ -1382,6 +1387,11 @@ has-flag@^4.0.0:
resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+highlight.js@^11.9.0:
+ version "11.9.0"
+ resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.9.0.tgz#04ab9ee43b52a41a047432c8103e2158a1b8b5b0"
+ integrity sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==
+
idb-keyval@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.1.tgz#94516d625346d16f56f3b33855da11bfded2db33"