From 3f7d58d4fe91738640721eeb297952d5f27ab13d Mon Sep 17 00:00:00 2001 From: xyroscar Date: Mon, 24 Nov 2025 13:26:52 -0800 Subject: [PATCH] added workspace create and update with map --- bun.lockb | Bin 65904 -> 70942 bytes package.json | 4 +- .../components/ui/dialog/dialog-close.svelte | 7 + .../ui/dialog/dialog-content.svelte | 43 ++++ .../ui/dialog/dialog-description.svelte | 17 ++ .../components/ui/dialog/dialog-footer.svelte | 20 ++ .../components/ui/dialog/dialog-header.svelte | 20 ++ .../ui/dialog/dialog-overlay.svelte | 20 ++ .../components/ui/dialog/dialog-title.svelte | 17 ++ .../ui/dialog/dialog-trigger.svelte | 7 + src/lib/components/ui/dialog/index.ts | 37 +++ src/lib/components/ui/input/index.ts | 7 + src/lib/components/ui/input/input.svelte | 52 +++++ src/lib/components/ui/label/index.ts | 7 + src/lib/components/ui/label/label.svelte | 20 ++ src/lib/services/workspaces.ts | 75 ++++-- src/routes/workspaces/+page.svelte | 221 +++++++++++++----- 17 files changed, 499 insertions(+), 75 deletions(-) create mode 100644 src/lib/components/ui/dialog/dialog-close.svelte create mode 100644 src/lib/components/ui/dialog/dialog-content.svelte create mode 100644 src/lib/components/ui/dialog/dialog-description.svelte create mode 100644 src/lib/components/ui/dialog/dialog-footer.svelte create mode 100644 src/lib/components/ui/dialog/dialog-header.svelte create mode 100644 src/lib/components/ui/dialog/dialog-overlay.svelte create mode 100644 src/lib/components/ui/dialog/dialog-title.svelte create mode 100644 src/lib/components/ui/dialog/dialog-trigger.svelte create mode 100644 src/lib/components/ui/dialog/index.ts create mode 100644 src/lib/components/ui/input/index.ts create mode 100644 src/lib/components/ui/input/input.svelte create mode 100644 src/lib/components/ui/label/index.ts create mode 100644 src/lib/components/ui/label/label.svelte diff --git a/bun.lockb b/bun.lockb index 1c9283a5cbcc8f98412fb2c1bdc4fde16544b7d0..e0f6621ce854e61a466d6091c26f3e5bcfd23519 100755 GIT binary patch delta 13157 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

o7+^Fo3K$6#03QM)fZ@O}fLkyg;OXZz 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 O#as{3xHP}9xb`2vP74+Q diff --git a/package.json b/package.json index 7474fd1..ee6837c 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "@tauri-apps/plugin-opener": "^2" }, "devDependencies": { - "@lucide/svelte": "^0.554.0", + "@internationalized/date": "^3.8.1", + "@lucide/svelte": "^0.544.0", "@sveltejs/adapter-static": "^3.0.6", "@sveltejs/kit": "^2.9.0", "@sveltejs/vite-plugin-svelte": "^5.0.0", @@ -25,6 +26,7 @@ "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "^4.1.17", "@tauri-apps/cli": "^2", + "bits-ui": "^2.11.0", "clsx": "^2.1.1", "svelte": "^5.0.0", "svelte-check": "^4.0.0", diff --git a/src/lib/components/ui/dialog/dialog-close.svelte b/src/lib/components/ui/dialog/dialog-close.svelte new file mode 100644 index 0000000..840b2f6 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-close.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/lib/components/ui/dialog/dialog-content.svelte b/src/lib/components/ui/dialog/dialog-content.svelte new file mode 100644 index 0000000..9d7c7f5 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-content.svelte @@ -0,0 +1,43 @@ + + + + + + {@render children?.()} + {#if showCloseButton} + + + Close + + {/if} + + diff --git a/src/lib/components/ui/dialog/dialog-description.svelte b/src/lib/components/ui/dialog/dialog-description.svelte new file mode 100644 index 0000000..3845023 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-description.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/lib/components/ui/dialog/dialog-footer.svelte b/src/lib/components/ui/dialog/dialog-footer.svelte new file mode 100644 index 0000000..e7ff446 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-footer.svelte @@ -0,0 +1,20 @@ + + +

diff --git a/src/lib/components/ui/dialog/dialog-header.svelte b/src/lib/components/ui/dialog/dialog-header.svelte new file mode 100644 index 0000000..4e5c447 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-header.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/src/lib/components/ui/dialog/dialog-overlay.svelte b/src/lib/components/ui/dialog/dialog-overlay.svelte new file mode 100644 index 0000000..f81ad83 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-overlay.svelte @@ -0,0 +1,20 @@ + + + diff --git a/src/lib/components/ui/dialog/dialog-title.svelte b/src/lib/components/ui/dialog/dialog-title.svelte new file mode 100644 index 0000000..067e55e --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-title.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/lib/components/ui/dialog/dialog-trigger.svelte b/src/lib/components/ui/dialog/dialog-trigger.svelte new file mode 100644 index 0000000..9d1e801 --- /dev/null +++ b/src/lib/components/ui/dialog/dialog-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/lib/components/ui/dialog/index.ts b/src/lib/components/ui/dialog/index.ts new file mode 100644 index 0000000..dce1d9d --- /dev/null +++ b/src/lib/components/ui/dialog/index.ts @@ -0,0 +1,37 @@ +import { Dialog as DialogPrimitive } from "bits-ui"; + +import Title from "./dialog-title.svelte"; +import Footer from "./dialog-footer.svelte"; +import Header from "./dialog-header.svelte"; +import Overlay from "./dialog-overlay.svelte"; +import Content from "./dialog-content.svelte"; +import Description from "./dialog-description.svelte"; +import Trigger from "./dialog-trigger.svelte"; +import Close from "./dialog-close.svelte"; + +const Root = DialogPrimitive.Root; +const Portal = DialogPrimitive.Portal; + +export { + Root, + Title, + Portal, + Footer, + Header, + Trigger, + Overlay, + Content, + Description, + Close, + // + Root as Dialog, + Title as DialogTitle, + Portal as DialogPortal, + Footer as DialogFooter, + Header as DialogHeader, + Trigger as DialogTrigger, + Overlay as DialogOverlay, + Content as DialogContent, + Description as DialogDescription, + Close as DialogClose, +}; diff --git a/src/lib/components/ui/input/index.ts b/src/lib/components/ui/input/index.ts new file mode 100644 index 0000000..f47b6d3 --- /dev/null +++ b/src/lib/components/ui/input/index.ts @@ -0,0 +1,7 @@ +import Root from "./input.svelte"; + +export { + Root, + // + Root as Input, +}; diff --git a/src/lib/components/ui/input/input.svelte b/src/lib/components/ui/input/input.svelte new file mode 100644 index 0000000..960167d --- /dev/null +++ b/src/lib/components/ui/input/input.svelte @@ -0,0 +1,52 @@ + + +{#if type === "file"} + +{:else} + +{/if} diff --git a/src/lib/components/ui/label/index.ts b/src/lib/components/ui/label/index.ts new file mode 100644 index 0000000..8bfca0b --- /dev/null +++ b/src/lib/components/ui/label/index.ts @@ -0,0 +1,7 @@ +import Root from "./label.svelte"; + +export { + Root, + // + Root as Label, +}; diff --git a/src/lib/components/ui/label/label.svelte b/src/lib/components/ui/label/label.svelte new file mode 100644 index 0000000..d0afda3 --- /dev/null +++ b/src/lib/components/ui/label/label.svelte @@ -0,0 +1,20 @@ + + + diff --git a/src/lib/services/workspaces.ts b/src/lib/services/workspaces.ts index 7caf735..2b5ef30 100644 --- a/src/lib/services/workspaces.ts +++ b/src/lib/services/workspaces.ts @@ -1,33 +1,70 @@ import type { Workspace } from "$lib/types/workspace"; -let ws: Workspace[] = [ +const ws: Map = new Map([ + [ + "1", { - Id: "1", - Name: "Test 1", - Description: "This is a test description" + Id: "1", + Name: "Test 1", + Description: "This is a test description", }, + ], + [ + "2", { - Id: "2", - Name: "Test 2", - Description: "This is a longer test description" + Id: "2", + Name: "Test 2", + Description: "This is a longer test description", }, + ], + [ + "3", { - Id: "3", - Name: "Test 3", - Description: "This is a slightly longer test description" + Id: "3", + Name: "Test 3", + Description: "This is a slightly longer test description", }, + ], + [ + "4", { - Id: "4", - Name: "Test 4", - Description: "This is an even slightly longer test description" + Id: "4", + Name: "Test 4", + Description: "This is an even slightly longer test description", }, + ], + [ + "5", { - Id: "5", - Name: "Test 5", - Description: "This is a veryyyyyyyyyyyyyyyyyyyyyyyyyyy longggggggggggggggggggggggggggg test descriptionnnnnnnnnnnnnnnnnnnnnnnnnnnnnn" + Id: "5", + Name: "Test 5", + Description: + "This is a veryyyyyyyyyyyyyyyyyyyyyyyyyyy longggggggggggggggggggggggggggg test descriptionnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", }, -] + ], +]); + +function convert_to_list(ws: Map): Workspace[] { + return [...ws.values()]; +} export async function get_workspaces(): Promise { - return ws -} \ No newline at end of file + return convert_to_list(ws); +} + +export async function update_workspace(workspace: Workspace): Promise { + let w = ws.get(workspace.Id); + if (w != undefined) { + w.Name = workspace.Name; + w.Description = workspace.Description; + } else { + return false; + } + return true; +} + +export async function create_workspace(workspace: Workspace): Promise { + workspace.Id = crypto.randomUUID(); + ws.set(workspace.Id, workspace); + return true; +} diff --git a/src/routes/workspaces/+page.svelte b/src/routes/workspaces/+page.svelte index 432e7cf..283ec5c 100644 --- a/src/routes/workspaces/+page.svelte +++ b/src/routes/workspaces/+page.svelte @@ -2,66 +2,177 @@ import * as Empty from "$lib/components/ui/empty/index.js"; import { Button } from "$lib/components/ui/button/index.js"; import FolderCodeIcon from "@lucide/svelte/icons/folder-code"; - import { get_workspaces } from "$lib/services/workspaces"; + import { + create_workspace, + get_workspaces, + update_workspace, + } from "$lib/services/workspaces"; import type { Workspace } from "$lib/types/workspace"; import * as Card from "$lib/components/ui/card/index"; + import * as Dialog from "$lib/components/ui/dialog/index.js"; + import { Input } from "$lib/components/ui/input/index.js"; + import { Label } from "$lib/components/ui/label/index.js"; - let showPrompt = false; - let workspaces: Workspace[] = []; - - get_workspaces().then((ws) => { - if (ws.length == 0) { - showPrompt = true; - } else { - workspaces = ws; - } + $effect(() => { + get_workspaces().then((ws) => { + if (ws.length == 0) { + showPrompt = true; + } else { + console.log(ws); + workspaces = ws; + } + }); }); + + let showPrompt = $state(false); + let workspaces = $state([]); + let dialogOpen = $state(false); + let dialogMode = $state<"create" | "edit">("create"); + let selectedWorkspace = $state(null); + let workspaceName = $state(""); + let workspaceDescription = $state(""); + + function openCreateDialog() { + dialogMode = "create"; + selectedWorkspace = null; + workspaceName = ""; + workspaceDescription = ""; + dialogOpen = true; + } + + function openEditDialog(workspace: Workspace) { + dialogMode = "edit"; + selectedWorkspace = workspace; + workspaceName = workspace.Name ?? ""; + workspaceDescription = workspace.Description ?? ""; + dialogOpen = true; + } + + async function handleDialogSubmit() { + let success = false; + if (dialogMode === "create") { + const w: Workspace = { + // Id will be assigned in create_workspace + Id: "", + Name: workspaceName, + Description: workspaceDescription, + }; + success = await create_workspace(w); + } else if (selectedWorkspace != null) { + const w: Workspace = { + Id: selectedWorkspace.Id, + Name: workspaceName, + Description: workspaceDescription, + }; + success = await update_workspace(w); + } + + if (success) { + const updated = await get_workspaces(); + workspaces = updated; + showPrompt = updated.length === 0; + } + + dialogOpen = false; + } -{#if showPrompt} - - - - - - No Workspaces Yet - - You haven't created any Workspaces yet. Get started by creating your - first project. - - - -
- -
-
-
-{:else} -
-
+ {#if showPrompt} + - {#each workspaces as workspace (workspace.Id)} - - - {workspace.Name} - - {workspace.Description} - - - - - - - - {/each} + + + + + No Workspaces Yet + + You haven't created any Workspaces yet. Get started by creating your + first project. + + + +
+ +
+
+
+ {:else} +
+
+

Workspaces

+ +
+
+ {#each workspaces as workspace (workspace.Id)} + + + {workspace.Name} + + {workspace.Description} + + + + + + + + {/each} +
-
-{/if} + {/if} + + + + + {dialogMode === "create" ? "Create workspace" : "Edit workspace"} + + + {#if dialogMode === "create"} + Create a new workspace. Fill in the details below and click create. + {:else} + Update your workspace details and click save. + {/if} + + +
+
+ + +
+
+ + +
+ + + +
+
+