feat(textbooks): add force-graph component and update graph components

- Add force-graph.tsx for new graph visualization

- Update graph-toolbar, knowledge-graph, knowledge-point-list, textbook-reader

- Update use-graph-data hook and types

- Update textbooks error boundary pages
This commit is contained in:
SpecialX
2026-07-04 10:22:24 +08:00
parent 25dca843be
commit 6ea8ba763b
11 changed files with 667 additions and 153 deletions

View File

@@ -11,12 +11,14 @@ import {
SelectTrigger,
SelectValue,
} from "@/shared/components/ui/select"
import type { GraphViewMode } from "../types"
import type { GraphLayoutMode, GraphViewMode } from "../types"
interface GraphToolbarProps {
viewMode: GraphViewMode
onViewModeChange: (mode: GraphViewMode) => void
availableViewModes: GraphViewMode[]
layoutMode: GraphLayoutMode
onLayoutModeChange: (mode: GraphLayoutMode) => void
searchText: string
onSearchChange: (text: string) => void
onResetView: () => void
@@ -30,14 +32,22 @@ const ALL_VIEW_MODES: readonly GraphViewMode[] = [
"class-mastery",
]
const ALL_LAYOUT_MODES: readonly GraphLayoutMode[] = ["hierarchical", "force"]
function isGraphViewMode(value: string): value is GraphViewMode {
return ALL_VIEW_MODES.some((mode) => mode === value)
}
function isGraphLayoutMode(value: string): value is GraphLayoutMode {
return ALL_LAYOUT_MODES.some((mode) => mode === value)
}
export function GraphToolbar({
viewMode,
onViewModeChange,
availableViewModes,
layoutMode,
onLayoutModeChange,
searchText,
onSearchChange,
onResetView,
@@ -45,15 +55,32 @@ export function GraphToolbar({
}: GraphToolbarProps) {
const t = useTranslations("textbooks")
const handleValueChange = (v: string): void => {
const handleViewModeChange = (v: string): void => {
if (isGraphViewMode(v)) {
onViewModeChange(v)
}
}
const handleLayoutModeChange = (v: string): void => {
if (isGraphLayoutMode(v)) {
onLayoutModeChange(v)
}
}
return (
<div className="flex flex-wrap items-center gap-2 p-2 border-b bg-background/95 shrink-0">
<Select value={viewMode} onValueChange={handleValueChange}>
{/* 布局切换:分层有向图 / Obsidian 风格力导向图 */}
<Select value={layoutMode} onValueChange={handleLayoutModeChange}>
<SelectTrigger className="w-[120px] h-8 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="hierarchical">{t("graph.layout.hierarchical")}</SelectItem>
<SelectItem value="force">{t("graph.layout.force")}</SelectItem>
</SelectContent>
</Select>
<Select value={viewMode} onValueChange={handleViewModeChange}>
<SelectTrigger className="w-[140px] h-8 text-xs">
<SelectValue />
</SelectTrigger>