From 7d4a087c10d2cdd13273e92497226f068932d370 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 28 Feb 2026 02:33:50 +0100 Subject: [PATCH] Sidbar more elegant --- src/components/sidebar/AppSidebar.tsx | 82 +++++++++++++++++++++------ 1 file changed, 66 insertions(+), 16 deletions(-) diff --git a/src/components/sidebar/AppSidebar.tsx b/src/components/sidebar/AppSidebar.tsx index d0c07d8..f262885 100644 --- a/src/components/sidebar/AppSidebar.tsx +++ b/src/components/sidebar/AppSidebar.tsx @@ -12,6 +12,16 @@ import { SidebarProvider, useSidebar, } from "@/components/ui/sidebar"; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogDescription, +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; import EntitySwitch from "./Entity"; import { @@ -25,6 +35,7 @@ import { import { ChevronDown } from "lucide-react"; import { Route, SetState, Workspace } from "@/lib/types"; import { listWorkspaces, saveWorkspaceToLocalStorage } from "@/lib/workspace"; +import { openFileDialog } from "@/lib/import"; // Simple ID generator const id = (prefix = "t") => @@ -48,6 +59,13 @@ export default function AppSidebar({ Workspace[] >([]); + const [isRenameOpen, setIsRenameOpen] = React.useState(false); + const [proposedName, setProposedName] = React.useState(workspace.name); + + React.useEffect(() => { + setProposedName(workspace.name); + }, [workspace.name]); + // reload list when component mounts or whenever the current workspace changes React.useEffect(() => { setAvailableWorkspaces(listWorkspaces()); @@ -57,14 +75,10 @@ export default function AppSidebar({ setRoute({ workspace: id }); }; - const importWorkspace = () => { - const json = window.prompt( - "Paste a workspace JSON to import (generated by export)", - ); - if (!json) return; - + const importWorkspace = async () => { try { - const parsed = JSON.parse(json); + const { content } = await openFileDialog(".json"); + const parsed = JSON.parse(content); if (parsed && typeof parsed.id === "string") { saveWorkspaceToLocalStorage(parsed); setAvailableWorkspaces(listWorkspaces()); @@ -74,28 +88,34 @@ export default function AppSidebar({ } } catch (err) { console.error("Failed to import workspace:", err); - window.alert("Import failed: invalid JSON"); + window.alert("Import failed: invalid file"); } }; const exportWorkspace = () => { try { const text = JSON.stringify(workspace, null, 2); - navigator.clipboard.writeText(text); - window.alert("Workspace JSON copied to clipboard"); + const blob = new Blob([text], { type: "application/json" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `workspace-${workspace.name}.json`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); } catch (err) { console.error("Export failed", err); - window.alert("Failed to copy workspace JSON"); + window.alert("Failed to download workspace"); } }; - const renameWorkspace = () => { - const newName = window.prompt("New workspace name", workspace.name); - if (!newName || newName === workspace.name) return; + const renameWorkspace = (name: string) => { + if (!name || name === workspace.name) return; const updated: Workspace = { ...workspace, - name: newName, + name, updatedAt: Date.now(), }; saveWorkspaceToLocalStorage(updated); @@ -142,7 +162,7 @@ export default function AppSidebar({ Import Workspace - + setIsRenameOpen(true)}> Rename Workspace @@ -172,6 +192,36 @@ export default function AppSidebar({
{children}
+ + {/* rename dialog */} + + + + Rename workspace + + Provide a new name for the workspace. + + + setProposedName(e.target.value)} + className="w-full" + /> + + + + + + ); }