Files
mnote/wolai-frontend/src/components/breadcrumb.tsx
T

84 lines
3.5 KiB
TypeScript
Raw Normal View History

2025-11-23 10:55:04 +08:00
"use client";
import Link from "next/link";
import { useParams, useSelectedLayoutSegments } from "next/navigation";
import { ChevronRight, MoreHorizontal, Star } from "lucide-react";
2026-01-22 18:53:20 +08:00
import { useMutation, useQuery } from "convex/react";
2025-11-23 10:55:04 +08:00
import type { DocumentRecord } from "@/lib/documents";
import { findBreadcrumb } from "@/lib/documents";
import { usePageLayoutStore } from "@/store/page-layout";
2026-01-22 18:53:20 +08:00
import { api } from "@/lib/convex/api";
2025-11-23 10:55:04 +08:00
interface BreadcrumbProps {
documents: DocumentRecord[];
}
export function Breadcrumb({ documents }: BreadcrumbProps) {
const segments = useSelectedLayoutSegments();
const params = useParams<{ id?: string }>();
const paramId = typeof params?.id === "string" ? params.id : "";
const activeId = paramId || segments?.[1] || "";
const path = findBreadcrumb(documents, activeId);
const showInspector = usePageLayoutStore((state) => state.showInspector);
const toggleInspector = usePageLayoutStore((state) => state.toggleInspector);
2026-01-22 18:53:20 +08:00
const isStarred = useQuery(api.documentStars.isStarred, activeId ? { documentId: activeId } : "skip");
const toggleStar = useMutation(api.documentStars.toggle);
2025-11-23 10:55:04 +08:00
2026-01-10 23:08:56 +08:00
// 新建页面后,侧边栏数据可能还没同步到 layout(SSR)注入的 documents,导致 findBreadcrumb 暂时为空。
// 这里用 activeId 兜底,避免右上角“收藏/更多”按钮消失。
if (!activeId) {
2025-11-23 10:55:04 +08:00
return <div className="text-sm text-gray-400">请选择一个页面</div>;
}
2026-01-10 23:08:56 +08:00
const displayPath: Array<Pick<DocumentRecord, "id" | "title">> = path.length
? path
: [{ id: activeId, title: "无标题" }];
2025-11-23 10:55:04 +08:00
return (
<div className="flex flex-1 items-center justify-between">
2026-01-18 19:01:31 +08:00
<nav className="flex items-center text-sm text-wolai-text-secondary">
2026-01-10 23:08:56 +08:00
{displayPath.map((node, index) => {
const isLast = index === displayPath.length - 1;
2025-11-23 10:55:04 +08:00
return (
<span key={node.id} className="flex items-center">
{index > 0 && <ChevronRight className="mx-1 h-4 w-4 text-gray-400" />}
{isLast ? (
2026-01-18 19:01:31 +08:00
<span className="font-medium text-wolai-text-primary">{node.title || "无标题"}</span>
2025-11-23 10:55:04 +08:00
) : (
2026-01-18 19:01:31 +08:00
<Link
href={`/documents/${node.id}`}
className="hover:bg-wolai-bg-hover hover:text-wolai-text-primary px-1.5 py-0.5 rounded cursor-pointer transition-colors"
>
2025-11-23 10:55:04 +08:00
{node.title || "无标题"}
</Link>
)}
</span>
);
})}
</nav>
2026-01-18 19:01:31 +08:00
<div className="flex items-center gap-2 text-wolai-text-secondary">
<button
type="button"
className="hover:bg-wolai-bg-hover hover:text-wolai-text-primary rounded-full px-3 py-1 text-sm transition-colors"
2026-01-22 18:53:20 +08:00
onClick={() => void toggleStar({ documentId: activeId })}
disabled={!activeId}
2026-01-18 19:01:31 +08:00
>
2026-01-22 18:53:20 +08:00
<Star
className={`mr-1 inline h-4 w-4 ${isStarred ? "text-[#f5a623]" : ""}`}
fill={isStarred ? "currentColor" : "none"}
/>
2025-11-23 10:55:04 +08:00
收藏
</button>
<button
type="button"
2026-01-18 19:01:31 +08:00
className="hover:bg-wolai-bg-hover hover:text-wolai-text-primary rounded-full p-2 transition-colors"
2025-11-23 10:55:04 +08:00
onClick={toggleInspector}
aria-label={showInspector ? "隐藏页面选项" : "显示页面选项"}
title={showInspector ? "隐藏页面选项" : "显示页面选项"}
>
<MoreHorizontal className="h-4 w-4" />
</button>
</div>
</div>
);
}