feat: update knowledge and agent UI

This commit is contained in:
吉鑫升 committed 2026-06-11 16:18:38 +08:00
1 parent bebe4feccf
commit 7efd811e75
27 files changed
+2949 -782

No files matched your search

+31 -24
View File
@@ -17,13 +17,11 @@ import { ScrollArea } from "@/components/ui/scroll-area";
import { Textarea } from "@/components/ui/textarea";
import { EmptyDocumentState } from "@/components/wiki/EmptyDocumentState";
import { KnowledgeSidebar } from "@/components/wiki/KnowledgeSidebar";
import { TocPanel } from "@/components/wiki/TocPanel";
import { WikiContent } from "@/components/wiki/WikiContent";
import { WikiHeader } from "@/components/wiki/WikiHeader";
import {
buildKnowledgeTree,
downloadMarkdown,
extractToc,
findAncestorFolderIds,
} from "@/components/wiki/wikiUtils";
import { ModelNameSelect } from "@/components/workspace/model-name-select";
@@ -41,6 +39,16 @@ import MarkdownRenderer, {
type WikiLinkTarget,
} from "@/strategy-components/MarkdownRenderer";
const SIDEBAR_COLLAPSED_KEY = "wiki.sidebar.collapsed";
function readSidebarCollapsed(): boolean {
try {
return window.localStorage.getItem(SIDEBAR_COLLAPSED_KEY) === "1";
} catch {
return false;
}
}
function useDebounced<T>(value: T, delay = 350): T {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
@@ -461,6 +469,7 @@ export default function KnowledgeBasePage() {
const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set());
const treeInitializedRef = useRef(false);
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
const [sidebarCollapsed, setSidebarCollapsed] = useState(readSidebarCollapsed);
// --- dialogs ---
const [createOpen, setCreateOpen] = useState(false);
@@ -469,9 +478,6 @@ export default function KnowledgeBasePage() {
const [dedupOpen, setDedupOpen] = useState(false);
const [vaultPath, setVaultPath] = useState<string | null>(null);
// --- reading state ---
const [activeHeadingId, setActiveHeadingId] = useState<string | null>(null);
const params = useMemo(
() => ({
keyword: debouncedKeyword || undefined,
@@ -488,10 +494,6 @@ export default function KnowledgeBasePage() {
const { data: note, isLoading: noteLoading } = useKnowledgeNote(noteId);
const { data: wikiLinks } = useNoteWikilinks(noteId);
const tocItems = useMemo(
() => (note ? extractToc(note.content_md) : []),
[note],
);
// First load: expand the root-level folders so the tree reads as a directory.
useEffect(() => {
@@ -529,11 +531,16 @@ export default function KnowledgeBasePage() {
navigate(`/page/workspace/knowledge/${item.id}`);
};
const handleTocClick = (id: string) => {
setActiveHeadingId(id);
document
.getElementById(id)
?.scrollIntoView({ behavior: "smooth", block: "start" });
const handleToggleSidebarCollapse = () => {
setSidebarCollapsed((prev) => {
const next = !prev;
try {
window.localStorage.setItem(SIDEBAR_COLLAPSED_KEY, next ? "1" : "0");
} catch {
// localStorage unavailable (private mode) — state stays session-only.
}
return next;
});
};
const handleWikiLink = (link: WikiLinkTarget) => {
@@ -555,7 +562,14 @@ export default function KnowledgeBasePage() {
onCreate={() => setCreateOpen(true)}
/>
<div className="grid min-h-0 flex-1 grid-cols-1 md:grid-cols-[300px_minmax(0,1fr)] xl:grid-cols-[300px_minmax(0,1fr)_280px]">
<div
className={cn(
"grid min-h-0 flex-1 grid-cols-1",
sidebarCollapsed && !mobileSidebarOpen
? "md:grid-cols-[44px_minmax(0,1fr)]"
: "md:grid-cols-[288px_minmax(0,1fr)]",
)}
>
{mobileSidebarOpen ? (
<div
className="fixed inset-0 z-40 bg-black/30 md:hidden"
@@ -578,6 +592,8 @@ export default function KnowledgeBasePage() {
onExportNote={downloadMarkdown}
total={data?.total ?? 0}
isLoading={isLoading}
collapsed={sidebarCollapsed && !mobileSidebarOpen}
onToggleCollapse={handleToggleSidebarCollapse}
className={cn(
"max-md:fixed max-md:inset-y-0 max-md:left-0 max-md:z-50 max-md:w-[300px] max-md:shadow-xl max-md:transition-transform max-md:duration-200",
mobileSidebarOpen ? "max-md:translate-x-0" : "max-md:-translate-x-full",
@@ -599,19 +615,10 @@ export default function KnowledgeBasePage() {
) : (
<WikiContent
note={note}
toc={tocItems}
wikiLinks={wikiLinks}
onWikiLinkClick={handleWikiLink}
onActiveHeadingChange={setActiveHeadingId}
/>
)}
<TocPanel
items={tocItems}
activeId={activeHeadingId}
onItemClick={handleTocClick}
className="hidden xl:block"
/>
</div>
<CreateNoteDialog open={createOpen} onOpenChange={setCreateOpen} />