0.3.1 UI修复
This commit is contained in:
@@ -35,9 +35,9 @@ import { buildDocumentTree } from "@/lib/documents";
|
||||
import { useSidebarStore } from "@/store/sidebar";
|
||||
import type { SidebarInitialData, SidebarSectionId } from "@/components/sidebar/types";
|
||||
import { useSidebarData } from "@/hooks/use-sidebar-data";
|
||||
import { useConvexSidebarData } from "@/hooks/use-convex-sidebar-data";
|
||||
import { PrivateTree } from "@/components/sidebar/private-tree";
|
||||
import { buildSidebarSectionsFromTree, flattenDocumentTree } from "@/lib/sidebar-tree";
|
||||
import { getSupabaseBrowserClient } from "@/lib/supabase/client";
|
||||
import { useSearchPaletteStore } from "@/store/search-palette";
|
||||
import { useEditorBridgeStore } from "@/store/editor-bridge";
|
||||
import { FileTree } from "@/components/sidebar/file-tree";
|
||||
@@ -126,26 +126,56 @@ interface ContextMenuState {
|
||||
y: number;
|
||||
}
|
||||
|
||||
// 主 Sidebar 组件:根据模式路由到不同的子组件
|
||||
export function Sidebar({ initialData }: SidebarProps) {
|
||||
const useConvex = useMemo(() => Boolean(getMnoteRuntimeConfig().useConvex), []);
|
||||
|
||||
// 根据模式渲染不同的子组件,确保 Supabase 模式完全不调用 Convex hooks
|
||||
if (useConvex) {
|
||||
return <SidebarConvex initialData={initialData} />;
|
||||
}
|
||||
return <SidebarSupabase initialData={initialData} />;
|
||||
}
|
||||
|
||||
// Convex 模式专用组件 - 只调用 Convex hooks
|
||||
function SidebarConvex({ initialData }: SidebarProps) {
|
||||
const convexData = useConvexSidebarData(initialData.activeWorkspaceId);
|
||||
return <SidebarContent initialData={initialData} sidebarQuery={convexData} />;
|
||||
}
|
||||
|
||||
// Supabase 模式专用组件 - 只调用 Supabase hooks
|
||||
function SidebarSupabase({ initialData }: SidebarProps) {
|
||||
const supabaseData = useSidebarData(initialData);
|
||||
return <SidebarContent initialData={initialData} sidebarQuery={supabaseData} />;
|
||||
}
|
||||
|
||||
// 共享的 UI 内容组件 - 包含所有现有的 Sidebar 逻辑
|
||||
interface SidebarContentProps {
|
||||
initialData: SidebarInitialData;
|
||||
sidebarQuery: {
|
||||
data: SidebarInitialData | null | undefined;
|
||||
isLoading: boolean;
|
||||
refetch: () => Promise<unknown>;
|
||||
};
|
||||
}
|
||||
|
||||
function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
const { open, setOpen, width, setWidth, collapsedSections, toggleSection, setSectionCollapsed, trashConfirm, setTrashConfirm } =
|
||||
useSidebarStore();
|
||||
const useConvex = useMemo(() => Boolean(getMnoteRuntimeConfig().useConvex), []);
|
||||
const supabaseBrowser = useMemo(() => {
|
||||
if (useConvex) return null;
|
||||
try {
|
||||
return getSupabaseBrowserClient();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}, [useConvex]);
|
||||
const sectionsTrayOpen = useSidebarStore((state) => state.sectionsTrayOpen);
|
||||
const toggleSectionsTray = useSidebarStore((state) => state.toggleSectionsTray);
|
||||
const setSectionsTrayOpen = useSidebarStore((state) => state.setSectionsTrayOpen);
|
||||
const viewMode = useSidebarStore((state) => state.viewMode);
|
||||
const setViewMode = useSidebarStore((state) => state.setViewMode);
|
||||
const openSearchPalette = useSearchPaletteStore((state) => state.openSearch);
|
||||
const sidebarQuery = useSidebarData(initialData);
|
||||
const sidebarData = sidebarQuery.data ?? initialData;
|
||||
const openSearchPalette = useSearchPaletteStore((state) => state.openSearch);
|
||||
|
||||
// 处理数据
|
||||
const sidebarData = useMemo(() => {
|
||||
return sidebarQuery.data ?? initialData;
|
||||
}, [sidebarQuery, initialData]);
|
||||
|
||||
// isLoading 判断
|
||||
const isLoading = sidebarQuery.isLoading;
|
||||
const segments = useSelectedLayoutSegments();
|
||||
const router = useRouter();
|
||||
const activeId = segments?.[1] ?? "";
|
||||
@@ -253,45 +283,6 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
await sidebarQuery.refetch();
|
||||
}, [sidebarQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!supabaseBrowser) return;
|
||||
const channel = supabaseBrowser
|
||||
.channel("documents-feed")
|
||||
.on(
|
||||
"postgres_changes",
|
||||
{ event: "*", schema: "public", table: "documents" },
|
||||
() => {
|
||||
void refreshTree();
|
||||
},
|
||||
)
|
||||
.subscribe();
|
||||
return () => {
|
||||
supabaseBrowser.removeChannel(channel);
|
||||
};
|
||||
}, [refreshTree, supabaseBrowser]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!supabaseBrowser) return;
|
||||
const channel = supabaseBrowser
|
||||
.channel("media-assets-feed")
|
||||
.on(
|
||||
"postgres_changes",
|
||||
{
|
||||
event: "*",
|
||||
schema: "public",
|
||||
table: "media_assets",
|
||||
filter: `workspace_id=eq.${sidebarData.activeWorkspaceId}`,
|
||||
},
|
||||
() => {
|
||||
void sidebarQuery.refetch();
|
||||
},
|
||||
)
|
||||
.subscribe();
|
||||
return () => {
|
||||
supabaseBrowser.removeChannel(channel);
|
||||
};
|
||||
}, [sidebarData.activeWorkspaceId, sidebarQuery, supabaseBrowser]);
|
||||
|
||||
const sections = useMemo(() => buildSidebarSectionsFromTree(tree), [tree]);
|
||||
const starredNodes = useMemo(() => sections.find((section) => section.id === "starred")?.nodes ?? [], [sections]);
|
||||
const publicNodes = useMemo(() => sections.find((section) => section.id === "public")?.nodes ?? [], [sections]);
|
||||
@@ -498,29 +489,7 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
|
||||
const handleEmbedPrompt = useCallback(async (node: DocumentNode) => {
|
||||
openMoveEmbedPicker(node, "embed");
|
||||
return;
|
||||
if (sidebarData.activeWorkspaceId) {
|
||||
openMoveEmbedPicker(node, "embed");
|
||||
return;
|
||||
}
|
||||
if (typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
const target = window.prompt("输入希望嵌入到的页面 ID");
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
const response = await fetch("/api/documents/embed", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ sourceId: node.id, targetId: target.trim() }),
|
||||
});
|
||||
if (!response.ok) {
|
||||
window.alert("嵌入失败,请检查目标页面 ID");
|
||||
return;
|
||||
}
|
||||
window.alert("已在目标页面末尾插入引用块");
|
||||
}, []);
|
||||
}, [openMoveEmbedPicker]);
|
||||
|
||||
const toggleExpand = useCallback((id: string) => {
|
||||
setExpanded((prev) => {
|
||||
@@ -1492,22 +1461,8 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
const handleMovePrompt = useCallback(
|
||||
async (node: DocumentNode) => {
|
||||
openMoveEmbedPicker(node, "move");
|
||||
return;
|
||||
if (sidebarData.activeWorkspaceId) {
|
||||
openMoveEmbedPicker(node, "move");
|
||||
return;
|
||||
}
|
||||
if (typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
const target = window.prompt("输入目标父页面 ID(留空表示移动到根目录)", node.parent_id ?? "");
|
||||
if (target === null) {
|
||||
return;
|
||||
}
|
||||
const trimmed = target.trim();
|
||||
await handleMove(node.id, trimmed.length > 0 ? trimmed : null, 0);
|
||||
},
|
||||
[handleMove],
|
||||
[openMoveEmbedPicker],
|
||||
);
|
||||
|
||||
const handleDelete = useCallback(
|
||||
@@ -2035,8 +1990,8 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<aside className="hidden h-full min-w-0 overflow-hidden md:flex" style={{ width }}>
|
||||
<div className="flex h-full min-w-0 flex-1 flex-col overflow-hidden border-r border-[#e9edf5] bg-white">
|
||||
<aside className="hidden h-full min-w-0 overflow-hidden md:flex shrink-0" style={{ width }}>
|
||||
<div className="flex h-full min-w-0 flex-1 flex-col overflow-hidden border-r border-wolai-border bg-wolai-bg-sidebar">
|
||||
{sidebarBody}
|
||||
</div>
|
||||
<div className="w-1 cursor-col-resize bg-transparent" onMouseDown={handleResizeStart} />
|
||||
|
||||
Reference in New Issue
Block a user