Working layout editor
This commit is contained in:
@@ -36,7 +36,6 @@ import { ChevronDown } from "lucide-react";
|
||||
import { Route, SetState, Workspace } from "@/lib/types";
|
||||
import { listWorkspaces, saveWorkspaceToLocalStorage } from "@/lib/workspace";
|
||||
import { openFileDialog } from "@/lib/import";
|
||||
import { useWorkspace } from "@/hooks/workspace";
|
||||
|
||||
// Simple ID generator
|
||||
const id = (prefix = "t") =>
|
||||
@@ -47,7 +46,17 @@ type AppSidebarProps = {
|
||||
workspace: Workspace;
|
||||
setRoute: SetState<Route>;
|
||||
/** optional setter for the current workspace, used for rename */
|
||||
setWorkspace?: React.Dispatch<React.SetStateAction<Workspace | undefined>>;
|
||||
setWorkspace: React.Dispatch<React.SetStateAction<Workspace | undefined>>;
|
||||
addEntity: (
|
||||
type: "todo" | "doc",
|
||||
parentGroupId: string | null,
|
||||
name?: string,
|
||||
) => string | undefined;
|
||||
addGroup: (name: string | undefined, parentGroupId: string | null) => string;
|
||||
renameEntity: (entityId: string, newName: string) => void;
|
||||
deleteEntity: (entityId: string) => void;
|
||||
removeNode: (id: string) => void;
|
||||
renameGroup: (id: string, name: string) => void;
|
||||
};
|
||||
|
||||
export default function AppSidebar({
|
||||
@@ -55,8 +64,14 @@ export default function AppSidebar({
|
||||
workspace,
|
||||
setRoute,
|
||||
setWorkspace,
|
||||
addEntity,
|
||||
addGroup,
|
||||
renameEntity,
|
||||
deleteEntity,
|
||||
removeNode,
|
||||
renameGroup,
|
||||
}: AppSidebarProps) {
|
||||
const { addEntity, addGroup, renameEntity } = useWorkspace();
|
||||
// actions are passed from parent `useWorkspace` instance
|
||||
|
||||
const [availableWorkspaces, setAvailableWorkspaces] = React.useState<
|
||||
Workspace[]
|
||||
@@ -64,6 +79,11 @@ export default function AppSidebar({
|
||||
|
||||
const [isRenameOpen, setIsRenameOpen] = React.useState(false);
|
||||
const [proposedName, setProposedName] = React.useState(workspace.name);
|
||||
const [isCreateOpen, setIsCreateOpen] = React.useState(false);
|
||||
const [createMode, setCreateMode] = React.useState<"list" | "doc" | "group">(
|
||||
"list",
|
||||
);
|
||||
const [createValue, setCreateValue] = React.useState("");
|
||||
|
||||
React.useEffect(() => {
|
||||
setProposedName(workspace.name);
|
||||
@@ -163,44 +183,27 @@ export default function AppSidebar({
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
onSelect={() => {
|
||||
const name = window.prompt(
|
||||
"Name for new list",
|
||||
"New list",
|
||||
);
|
||||
const id = addEntity("todo", null);
|
||||
if (id && name) {
|
||||
// rename newly created entity
|
||||
// obtain hook function
|
||||
// import renameEntity above
|
||||
renameEntity(id, name);
|
||||
}
|
||||
if (id) setRoute({ workspace: workspace.id, entity: id });
|
||||
setCreateMode("list");
|
||||
setCreateValue("New list");
|
||||
setIsCreateOpen(true);
|
||||
}}
|
||||
>
|
||||
New list (root)
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onSelect={() => {
|
||||
const name = window.prompt(
|
||||
"Name for new document",
|
||||
"New doc",
|
||||
);
|
||||
const id = addEntity("doc", null);
|
||||
if (id && name) {
|
||||
renameEntity(id, name);
|
||||
}
|
||||
if (id) setRoute({ workspace: workspace.id, entity: id });
|
||||
setCreateMode("doc");
|
||||
setCreateValue("New doc");
|
||||
setIsCreateOpen(true);
|
||||
}}
|
||||
>
|
||||
New doc (root)
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onSelect={() => {
|
||||
const name = window.prompt(
|
||||
"Name for new group",
|
||||
"New group",
|
||||
);
|
||||
addGroup(name || "New group", null);
|
||||
setCreateMode("group");
|
||||
setCreateValue("New group");
|
||||
setIsCreateOpen(true);
|
||||
}}
|
||||
>
|
||||
New group (root)
|
||||
@@ -231,6 +234,12 @@ export default function AppSidebar({
|
||||
node={node}
|
||||
workspace={workspace}
|
||||
setRoute={setRoute}
|
||||
addEntity={addEntity}
|
||||
addGroup={addGroup}
|
||||
renameEntity={renameEntity}
|
||||
deleteEntity={deleteEntity}
|
||||
removeNode={removeNode}
|
||||
renameGroup={renameGroup}
|
||||
/>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
@@ -270,6 +279,55 @@ export default function AppSidebar({
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
{/* create dialog */}
|
||||
<Dialog open={isCreateOpen} onOpenChange={setIsCreateOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{createMode === "group"
|
||||
? "Create group"
|
||||
: createMode === "doc"
|
||||
? "Create document"
|
||||
: "Create list"}
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
{createMode === "group" && "Provide a name for the new group."}
|
||||
{createMode === "doc" && "Provide a name for the new document."}
|
||||
{createMode === "list" && "Provide a name for the new list."}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Input
|
||||
value={createValue}
|
||||
onChange={(e) => setCreateValue(e.target.value)}
|
||||
className="w-full"
|
||||
/>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setIsCreateOpen(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (createMode === "group") {
|
||||
addGroup?.(createValue || "New group", null);
|
||||
} else if (createMode === "doc") {
|
||||
const id = addEntity?.("doc", null, createValue || "New doc");
|
||||
if (id) setRoute({ workspace: workspace.id, entity: id });
|
||||
} else {
|
||||
const id = addEntity?.(
|
||||
"todo",
|
||||
null,
|
||||
createValue || "New list",
|
||||
);
|
||||
if (id) setRoute({ workspace: workspace.id, entity: id });
|
||||
}
|
||||
setIsCreateOpen(false);
|
||||
}}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</SidebarProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
import { Collapsible, CollapsibleContent } from "../ui/collapsible";
|
||||
import { ChevronDown, MoreHorizontal } from "lucide-react";
|
||||
import { Route, Workspace, LayoutNode } from "@/lib/types";
|
||||
import { useWorkspace } from "@/hooks/workspace";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -36,18 +35,29 @@ type Props = {
|
||||
node: LayoutNode;
|
||||
workspace: Workspace;
|
||||
setRoute: (route: Route) => void;
|
||||
addEntity: (
|
||||
type: "todo" | "doc",
|
||||
parentGroupId: string | null,
|
||||
name?: string,
|
||||
) => string | undefined;
|
||||
addGroup: (name: string | undefined, parentGroupId: string | null) => string;
|
||||
renameEntity: (entityId: string, newName: string) => void;
|
||||
deleteEntity: (entityId: string) => void;
|
||||
removeNode: (id: string) => void;
|
||||
renameGroup: (id: string, name: string) => void;
|
||||
};
|
||||
|
||||
export default function EntitySwitch({ node, workspace, setRoute }: Props) {
|
||||
const {
|
||||
renameEntity,
|
||||
deleteEntity,
|
||||
addEntity,
|
||||
addGroup,
|
||||
removeNode,
|
||||
renameGroup,
|
||||
} = useWorkspace();
|
||||
|
||||
export default function EntitySwitch({
|
||||
node,
|
||||
workspace,
|
||||
setRoute,
|
||||
addEntity,
|
||||
addGroup,
|
||||
renameEntity,
|
||||
deleteEntity,
|
||||
removeNode,
|
||||
renameGroup,
|
||||
}: Props) {
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [dialogValue, setDialogValue] = useState("");
|
||||
@@ -74,11 +84,7 @@ export default function EntitySwitch({ node, workspace, setRoute }: Props) {
|
||||
renameEntity(node.entityId, dialogValue);
|
||||
} else if (dialogMode === "add-item") {
|
||||
const parentId = node.type === "group" ? node.id : null;
|
||||
const id = addEntity("todo", parentId);
|
||||
// optionally could rename newly created entity name
|
||||
if (id && dialogValue) {
|
||||
renameEntity(id, dialogValue);
|
||||
}
|
||||
addEntity("todo", parentId, dialogValue || "New list");
|
||||
} else if (dialogMode === "add-group") {
|
||||
const parentId = node.type === "group" ? node.id : null;
|
||||
addGroup(dialogValue || "New group", parentId);
|
||||
@@ -144,6 +150,12 @@ export default function EntitySwitch({ node, workspace, setRoute }: Props) {
|
||||
node={child}
|
||||
workspace={workspace}
|
||||
setRoute={setRoute}
|
||||
addEntity={addEntity}
|
||||
addGroup={addGroup}
|
||||
renameEntity={renameEntity}
|
||||
deleteEntity={deleteEntity}
|
||||
removeNode={removeNode}
|
||||
renameGroup={renameGroup}
|
||||
/>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
|
||||
Reference in New Issue
Block a user