feat: rename graph titles with select-then-edit interaction
This commit is contained in:
@@ -7,9 +7,10 @@ import { AnimatePresence, motion, useReducedMotion } from "motion/react";
|
||||
import { Check, ChevronsUpDown, FilePlus2, Home, Network, PanelLeftClose, PanelLeftOpen, Plus, Search, Settings } from "lucide-react";
|
||||
import { IconButton } from "@/components/ui/icon-button";
|
||||
import { api, errorText, type Profile } from "@/lib/api";
|
||||
import { boardHref, createBoard, DEFAULT_BOARD_TITLE, loadWorkspaceHome, type Board, type Workspace } from "@/lib/workspace";
|
||||
import { boardHref, createBoard, renameBoard, DEFAULT_BOARD_TITLE, loadWorkspaceHome, type Board, type Workspace } from "@/lib/workspace";
|
||||
import { useActiveBoard } from "@/components/workspace/active-board";
|
||||
import toolbar from "@/components/ui/toolbar.module.css";
|
||||
import { EditableTitle } from "@/components/workspace/editable-title";
|
||||
import { UserAvatar } from "@/components/workspace/user-avatar";
|
||||
import { AccountPanel } from "@/components/workspace/account-panel";
|
||||
import { readDemoBoards } from "@/lib/demo-workspace";
|
||||
@@ -17,7 +18,7 @@ import styles from "@/components/workspace/workspace.module.css";
|
||||
|
||||
export default function DashboardSidebar() {
|
||||
const router = useRouter();
|
||||
const { board: activeBoard } = useActiveBoard();
|
||||
const { board: activeBoard, setBoard: setActiveBoard } = useActiveBoard();
|
||||
const reduceMotion = useReducedMotion();
|
||||
const params = useParams<{ workspace?: string; board?: string }>();
|
||||
const searchParams = useSearchParams();
|
||||
@@ -139,6 +140,19 @@ export default function DashboardSidebar() {
|
||||
const filtered = boards.filter((b) => b.title.toLocaleLowerCase().includes(query.trim().toLocaleLowerCase()));
|
||||
const canCreate = status === "ready" && (!workspace || Boolean(currentWorkspace && currentWorkspace.role !== "viewer"));
|
||||
|
||||
async function renameTitle(title: string) {
|
||||
const id = params.board;
|
||||
if (!id || !workspace) return;
|
||||
try {
|
||||
if (demo) {
|
||||
const list = readDemoBoards(workspace);
|
||||
localStorage.setItem("endoleap_demo_boards_" + workspace, JSON.stringify(list.map((board) => board.id === id ? { ...board, title } : board)));
|
||||
} else await renameBoard(api, workspace, id, title);
|
||||
setBoards((list) => list.map((board) => board.id === id ? { ...board, title } : board));
|
||||
setActiveBoard((board) => board?.id === id && board.workspace_id === workspace ? { ...board, title } : board);
|
||||
} catch (error) { throw new Error(errorText(error)); }
|
||||
}
|
||||
|
||||
const createButton = <IconButton icon={FilePlus2} label={creating ? "正在创建图谱" : "新建页面"} disabled={!canCreate || creating} onClick={newPage} aria-busy={creating} />;
|
||||
|
||||
const transition = { duration: reduceMotion ? 0 : 0.24, ease: [0.22, 1, 0.36, 1] as const };
|
||||
@@ -159,7 +173,9 @@ export default function DashboardSidebar() {
|
||||
srcSet="/brand/png/logo-light/endoleap-32.png 1x, /brand/png/logo-light/endoleap-64.png 2x, /brand/png/logo-light/endoleap-128.png 4x"
|
||||
width={20} height={20} alt="" />
|
||||
</Link>
|
||||
<h1 className={styles.floatingTitle} title={currentTitle}>{currentTitle}</h1>
|
||||
<EditableTitle key={workspace + ":" + (params.board || "home")} title={currentTitle}
|
||||
editable={Boolean(params.board && activeBoard?.id === params.board && activeBoard.workspace_id === workspace && canCreate)}
|
||||
onSave={renameTitle} className={styles.floatingTitle} />
|
||||
<button type="button" className={styles.floatingAvatarButton} popoverTarget="workspace-account" aria-label="账户和工作空间">
|
||||
<UserAvatar name={name} url={profile?.avatar_url} />
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user