Sidebar elements editor

This commit is contained in:
2026-02-28 02:41:17 +01:00
parent 7d4a087c10
commit b543988f02
4 changed files with 501 additions and 40 deletions
+116 -2
View File
@@ -1,7 +1,11 @@
import { Entity, EntityId, Workspace } from "@/lib/types";
import { Entity, EntityId, LayoutNode, Workspace } from "@/lib/types";
import {
loadWorkspaceFromLocalStorage,
saveWorkspaceToLocalStorage,
addLayoutItem,
addLayoutGroup,
removeLayoutNode,
renameLayoutGroup,
} from "@/lib/workspace";
import { useEffect, useState } from "react";
@@ -23,6 +27,105 @@ export function useWorkspace() {
);
};
const renameEntity = (entityId: EntityId, newName: string) => {
updateEntity(entityId, (e) => ({ ...e, name: newName }));
};
const deleteEntity = (entityId: EntityId) => {
setWorkspace((prev) => {
if (!prev) return prev;
const { [entityId]: _, ...rest } = prev.entities;
// also remove from layout
const { layout: newLayout } = removeLayoutNode(prev.layout, entityId);
return {
...prev,
entities: rest,
layout: newLayout,
updatedAt: Date.now(),
};
});
};
const addEntity = (type: "todo" | "doc", parentGroupId: string | null) => {
if (!workspace) return;
const now = Date.now();
const id = crypto.randomUUID();
let entity: Entity;
if (type === "todo") {
entity = {
id,
type: "todo",
name: "New list",
config: { statuses: [] },
tags: {},
tasks: {},
createdAt: now,
updatedAt: now,
} as any;
} else {
entity = {
id,
type: "doc",
name: "New doc",
content: { version: "2.28.0", time: now, blocks: [] },
createdAt: now,
updatedAt: now,
} as any;
}
setWorkspace((prev) => {
if (!prev) return prev;
const newEntities = { ...prev.entities, [id]: entity };
const newLayout = addLayoutItem(prev.layout, parentGroupId, {
type: "item",
entityId: id,
});
return {
...prev,
entities: newEntities,
layout: newLayout,
updatedAt: Date.now(),
};
});
return id;
};
const addGroup = (name = "New group", parentGroupId: string | null) => {
const id = crypto.randomUUID();
const group: LayoutNode = { type: "group", id, name, children: [] };
setWorkspace((prev) => {
if (!prev) return prev;
const newLayout = addLayoutGroup(prev.layout, parentGroupId, group);
return { ...prev, layout: newLayout, updatedAt: Date.now() };
});
return id;
};
const removeNode = (id: string) => {
setWorkspace((prev) => {
if (!prev) return prev;
const { layout: newLayout, removedEntityIds } = removeLayoutNode(
prev.layout,
id,
);
const newEntities = { ...prev.entities } as Record<string, Entity>;
removedEntityIds.forEach((eid) => delete newEntities[eid]);
return {
...prev,
entities: newEntities,
layout: newLayout,
updatedAt: Date.now(),
};
});
};
const renameGroup = (id: string, newName: string) => {
setWorkspace((prev) => {
if (!prev) return prev;
const newLayout = renameLayoutGroup(prev.layout, id, newName);
return { ...prev, layout: newLayout, updatedAt: Date.now() };
});
};
const loadWorkspace = (workspaceId: string | undefined) => {
if (!workspaceId) {
return setWorkspace(undefined);
@@ -37,5 +140,16 @@ export function useWorkspace() {
if (workspace) saveWorkspaceToLocalStorage(workspace);
}, [workspace]);
return { workspace, loadWorkspace, updateEntity, setWorkspace };
return {
workspace,
loadWorkspace,
updateEntity,
renameEntity,
deleteEntity,
addEntity,
addGroup,
removeNode,
renameGroup,
setWorkspace,
};
}