Sidebar
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
@@ -16,11 +18,13 @@ import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "../ui/dropdown-menu";
|
||||
|
||||
import { ChevronDown } from "lucide-react";
|
||||
import { Route, SetState, Workspace } from "@/lib/types";
|
||||
import { listWorkspaces, saveWorkspaceToLocalStorage } from "@/lib/workspace";
|
||||
|
||||
// Simple ID generator
|
||||
const id = (prefix = "t") =>
|
||||
@@ -30,13 +34,77 @@ type AppSidebarProps = {
|
||||
children: React.ReactNode;
|
||||
workspace: Workspace;
|
||||
setRoute: SetState<Route>;
|
||||
/** optional setter for the current workspace, used for rename */
|
||||
setWorkspace?: React.Dispatch<React.SetStateAction<Workspace | undefined>>;
|
||||
};
|
||||
|
||||
export default function AppSidebar({
|
||||
children,
|
||||
workspace,
|
||||
setRoute,
|
||||
setWorkspace,
|
||||
}: AppSidebarProps) {
|
||||
const [availableWorkspaces, setAvailableWorkspaces] = React.useState<
|
||||
Workspace[]
|
||||
>([]);
|
||||
|
||||
// reload list when component mounts or whenever the current workspace changes
|
||||
React.useEffect(() => {
|
||||
setAvailableWorkspaces(listWorkspaces());
|
||||
}, [workspace]);
|
||||
|
||||
const switchWorkspace = (id: string) => {
|
||||
setRoute({ workspace: id });
|
||||
};
|
||||
|
||||
const importWorkspace = () => {
|
||||
const json = window.prompt(
|
||||
"Paste a workspace JSON to import (generated by export)",
|
||||
);
|
||||
if (!json) return;
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(json);
|
||||
if (parsed && typeof parsed.id === "string") {
|
||||
saveWorkspaceToLocalStorage(parsed);
|
||||
setAvailableWorkspaces(listWorkspaces());
|
||||
switchWorkspace(parsed.id);
|
||||
} else {
|
||||
throw new Error("invalid shape");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to import workspace:", err);
|
||||
window.alert("Import failed: invalid JSON");
|
||||
}
|
||||
};
|
||||
|
||||
const exportWorkspace = () => {
|
||||
try {
|
||||
const text = JSON.stringify(workspace, null, 2);
|
||||
navigator.clipboard.writeText(text);
|
||||
window.alert("Workspace JSON copied to clipboard");
|
||||
} catch (err) {
|
||||
console.error("Export failed", err);
|
||||
window.alert("Failed to copy workspace JSON");
|
||||
}
|
||||
};
|
||||
|
||||
const renameWorkspace = () => {
|
||||
const newName = window.prompt("New workspace name", workspace.name);
|
||||
if (!newName || newName === workspace.name) return;
|
||||
|
||||
const updated: Workspace = {
|
||||
...workspace,
|
||||
name: newName,
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
saveWorkspaceToLocalStorage(updated);
|
||||
setAvailableWorkspaces(listWorkspaces());
|
||||
if (setWorkspace) {
|
||||
setWorkspace(updated);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<Sidebar>
|
||||
@@ -56,9 +124,30 @@ export default function AppSidebar({
|
||||
align="start"
|
||||
className="w-[--radix-popper-anchor-width]"
|
||||
>
|
||||
{/* Future: real workspace switching */}
|
||||
<DropdownMenuItem>Rename Workspace</DropdownMenuItem>
|
||||
<DropdownMenuItem>Export Workspace</DropdownMenuItem>
|
||||
{/* list all known workspaces */}
|
||||
{availableWorkspaces.map((w) => (
|
||||
<DropdownMenuItem
|
||||
key={w.id}
|
||||
className={
|
||||
w.id === workspace.id ? "font-semibold" : undefined
|
||||
}
|
||||
onSelect={() => switchWorkspace(w.id)}
|
||||
>
|
||||
{w.name}
|
||||
{w.id === workspace.id ? " (current)" : ""}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onSelect={importWorkspace}>
|
||||
Import Workspace
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onSelect={renameWorkspace}>
|
||||
Rename Workspace
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onSelect={exportWorkspace}>
|
||||
Export Workspace
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SidebarMenuItem>
|
||||
|
||||
Reference in New Issue
Block a user