From 8bd8f6d6fda10ac3c3457ac08afce99720a6fd9e Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Thu, 5 Nov 2026 23:27:45 +0800 Subject: [PATCH] refactor: keep only dashboard sidebars and their state --- src/app/dashboard/dashboard.tsx | 942 +++++--------------------------- src/app/dashboard/page.tsx | 7 +- src/styles/globals.css | 10 + 3 files changed, 145 insertions(+), 814 deletions(-) diff --git a/src/app/dashboard/dashboard.tsx b/src/app/dashboard/dashboard.tsx index 5e53f1c..2b9d1c5 100644 --- a/src/app/dashboard/dashboard.tsx +++ b/src/app/dashboard/dashboard.tsx @@ -1,101 +1,44 @@ "use client"; -import { useEffect, useRef, useState, type FormEvent } from "react"; +import { useEffect, useState } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import Link from "next/link"; import { - ArrowUpRight, Plus, - Search, Folder, FileText, LayoutGrid, LogOut, ChevronDown, - PanelLeftClose, - PanelLeftOpen, Check, - MoreHorizontal, - X, - ArrowLeft, Sun, Moon, } from "lucide-react"; import { Brand } from "@/components/brand"; import { Icon } from "@/components/icon"; -import { Button } from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogDescription, - DialogFooter, -} from "@/components/ui/dialog"; import { api, errorText, type Profile } from "@/lib/api"; -import { - createBoard, - loadWorkspaceHome, - type Workspace, -} from "@/lib/workspace"; -type Board = { - id: string; - title: string; - updated: string; - style: number; - text: string; -}; -const initialBoards: Board[] = [ - { - id: "morning", - title: "城市清晨", - updated: "刚刚", - style: 0, - text: "让阳光穿过叶片,落在安静的房间里。", - }, - { - id: "ideas", - title: "灵感收集", - updated: "昨天", - style: 1, - text: "把一闪而过的念头,留给下一次创作。", - }, - { - id: "journey", - title: "下一站,去哪里", - updated: "2 天前", - style: 2, - text: "为一段还未开始的旅程,收集一些可能。", - }, +import { loadWorkspaceHome, type Workspace } from "@/lib/workspace"; + +type Board = { id: string; title: string }; +const demoBoards: Board[] = [ + { id: "morning", title: "城市清晨" }, + { id: "ideas", title: "灵感收集" }, + { id: "journey", title: "下一站,去哪里" }, ]; + export default function Dashboard() { const router = useRouter(); const demo = useSearchParams().get("demo") === "1"; - const mutationVersion = useRef(0); - const [boardsLoading, setBoardsLoading] = useState(false); - const [spacesLoaded, setSpacesLoaded] = useState(false); - const [ready, setReady] = useState(false), - [profile, setProfile] = useState(null), - [workspaces, setWorkspaces] = useState([]), - [workspace, setWorkspace] = useState(""), - [boards, setBoards] = useState([]), - [query, setQuery] = useState(""), - [view, setView] = useState("全部文件"), - [canvas, setCanvas] = useState(null), - [sidebar, setSidebar] = useState(true), - [dialog, setDialog] = useState<"board" | "workspace" | null>(null), - [title, setTitle] = useState(""), - [error, setError] = useState(""), - [busy, setBusy] = useState(false), - [workspaceMenu, setWorkspaceMenu] = useState(false), - [notice, setNotice] = useState(""), - [dark, setDark] = useState(false), - [checked, setChecked] = useState(false), - [zoom, setZoom] = useState(100), - [nodeText, setNodeText] = useState(""), - [note, setNote] = useState(""); + const [profile, setProfile] = useState(null); + const [workspaces, setWorkspaces] = useState([]); + const [workspace, setWorkspace] = useState(""); + const [boards, setBoards] = useState([]); + const [view, setView] = useState("全部文件"); + const [workspaceMenu, setWorkspaceMenu] = useState(false); + const [error, setError] = useState(""); + const [dark, setDark] = useState(false); + useEffect(() => { - let active = true; if (demo) { setProfile({ id: "demo", @@ -105,144 +48,61 @@ export default function Dashboard() { }); setWorkspaces([{ id: "demo", name: "个人空间" }]); setWorkspace("demo"); - setSpacesLoaded(true); - let stored: Board[] | null = null; - try { - stored = JSON.parse( - localStorage.getItem("endoleap_demo_boards_demo") || "null", - ); - } catch {} - setBoards(stored || initialBoards); - setReady(true); return; } + let active = true; const controller = new AbortController(); loadWorkspaceHome(api, controller.signal) .then(({ profile, workspaces: list }) => { if (!active) return; setProfile(profile); setWorkspaces(list); - setSpacesLoaded(true); setWorkspace(list[0]?.id || ""); - setReady(true); }) .catch((e) => { if (!active) return; if (e.message === "invalid_session") router.replace("/login"); - else { - setError(errorText(e)); - setReady(true); - } + else setError(errorText(e)); }); return () => { active = false; controller.abort(); }; }, [demo, router]); + useEffect(() => { - if (demo && ready) - localStorage.setItem( - "endoleap_demo_boards_" + workspace, - JSON.stringify(boards), - ); - }, [boards, demo, ready, workspace]); - useEffect(() => { - if (!workspace || demo) { - setBoardsLoading(false); + if (!workspace) return; + setError(""); + if (demo) { + try { + setBoards( + JSON.parse( + localStorage.getItem("endoleap_demo_boards_" + workspace) || "null", + ) || demoBoards, + ); + } catch { + setBoards(demoBoards); + } return; } let active = true; const controller = new AbortController(); - const version = mutationVersion.current; - setBoardsLoading(true); - setBoards([]); - api<{ items: { id: string; title: string }[] }>( - "workspaces/" + - workspace + - "/materials?kind=board&sort=modified&limit=100", + api<{ items: Board[] }>( + "workspaces/" + workspace + "/materials?kind=board&sort=modified&limit=100", { signal: controller.signal }, ) - .then((r) => { - if (active && version === mutationVersion.current) - setBoards( - r.items.map((b, i) => ({ - id: b.id, - title: b.title, - updated: "最近", - style: i % 3, - text: "", - })), - ); + .then((result) => { + if (active) setBoards(result.items); }) .catch((e) => { if (active) setError(errorText(e)); - }) - .finally(() => { - if (active) setBoardsLoading(false); }); return () => { active = false; controller.abort(); }; }, [workspace, demo]); - useEffect(() => { - if (notice) { - const timer = setTimeout(() => setNotice(""), 3500); - return () => clearTimeout(timer); - } - }, [notice]); - async function create(e: FormEvent) { - e.preventDefault(); - if (!title.trim()) return; - setBusy(true); - setError(""); - try { - if (dialog === "workspace") { - const w = demo - ? { id: crypto.randomUUID(), name: title.trim() } - : await api("workspaces", { - method: "POST", - body: JSON.stringify({ name: title.trim() }), - }); - setWorkspaces([...workspaces, w]); - setWorkspace(w.id); - setBoards([]); - } else { - if (!workspace && !spacesLoaded) - throw new Error("workspace_not_loaded"); - const id = demo - ? crypto.randomUUID() - : ( - await createBoard(api, title, workspace, (w) => { - setWorkspaces((previous) => - previous.some((x) => x.id === w.id) - ? previous - : [...previous, w], - ); - setWorkspace(w.id); - }) - ).id; - mutationVersion.current += 1; - setBoards((previous) => [ - { - id, - title: title.trim(), - updated: "刚刚", - style: boards.length % 3, - text: "一张空白画布,等待你的第一个念头。", - }, - ...previous, - ]); - } - setDialog(null); - setTitle(""); - setNotice("已创建"); - } catch (e) { - setError(errorText(e)); - } finally { - setBusy(false); - } - } + async function logout() { try { if (!demo) await api("auth/logout", { method: "POST" }); @@ -251,35 +111,10 @@ export default function Dashboard() { setError(errorText(e)); } } - function open(b: Board) { - setCanvas(b); - setNote(b.text); - setNodeText(""); - if (!demo) setNotice("当前为画布界面预览;服务端已保存画布名称。"); - } - function saveNote() { - if (!canvas) return; - if (demo) { - setBoards( - boards.map((b) => (b.id === canvas.id ? { ...b, text: note } : b)), - ); - setNotice("已保存到当前浏览器"); - } else setNotice("画布文字编辑将在布局接口接入后保存。"); - } - const names = - workspaces.find((w) => w.id === workspace)?.name || "创建你的空间"; - const filtered = boards.filter((b) => - b.title.toLowerCase().includes(query.toLowerCase()), - ); - if (!ready) - return ( -
- -

正在打开你的创作空间…

-
- ); + + const names = workspaces.find((w) => w.id === workspace)?.name || "工作空间"; return ( -
+
- {sidebar && ( - - )} -
-
- - {names} - / - {canvas ? canvas.title : "工作台"} -
- {demo && ( - - 本地演示 · 内容保存在此浏览器{" "} - - - )} - -
-
- {error && ( -
- {error} - -
- )} - {canvas ? ( -
-
- - {canvas.title} - 已打开 -
-
- - {zoom}% - - -
-
-
- 灵感片段 -

- 把日常, -
- 拍成一场电影。 -

- 一闪而过的想法。 -
-
-
- 镜头研究 子画布 · 740 × 600 -
-
-

清晨光线

-