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 */}
+
);
}