diff --git a/react/src/main.tsx b/react/src/main.tsx
index 01908c8..a6a99b3 100644
--- a/react/src/main.tsx
+++ b/react/src/main.tsx
@@ -4594,6 +4594,87 @@ function SidePanelDock({
);
}
+type CardLibraryTreeKind = "subject" | "level" | "series" | "card" | "task";
+
+function CardLibraryTreeRow({
+ id,
+ depth,
+ kind,
+ title,
+ label,
+ refValue,
+ stateValue,
+ stateKind,
+ hasChildren = false,
+ expanded = false,
+ onToggle,
+ href,
+ current = false,
+ unavailable = false,
+ onNavigate,
+}: {
+ id: string;
+ depth: number;
+ kind: CardLibraryTreeKind;
+ title: string;
+ label: React.ReactNode;
+ refValue: React.ReactNode;
+ stateValue: React.ReactNode;
+ stateKind?: string;
+ hasChildren?: boolean;
+ expanded?: boolean;
+ onToggle?: () => void;
+ href?: string;
+ current?: boolean;
+ unavailable?: boolean;
+ onNavigate?: () => void;
+}) {
+ const nodeLabel = href ? (
+
+ {label}
+
+ ) : (
+ {label}
+ );
+ return (
+
+
+ {hasChildren ? (
+
+ ) : (
+
+ )}
+ {nodeLabel}
+
+ {refValue}
+
+ {stateValue}
+
+
+ );
+}
+
function CardLibraryPanel({
library,
onNavigate,
@@ -4626,141 +4707,169 @@ function CardLibraryPanel({
),
0,
);
+ const [expandedNodes, setExpandedNodes] = useState>(() => {
+ const initial = new Set();
+ library.subjects.forEach(subject => {
+ const subjectKey = `subject:${subject.id}`;
+ if (subject.current) initial.add(subjectKey);
+ subject.levels.forEach(level => {
+ const levelKey = `${subjectKey}:level:${level.id}`;
+ if (level.current) initial.add(levelKey);
+ level.series.forEach(series => {
+ const seriesKey = `${levelKey}:series:${series.id}`;
+ if (series.current) initial.add(seriesKey);
+ series.cards.forEach(card => {
+ if (card.current && (card.tasks?.length ?? 0) > 0) {
+ initial.add(`${seriesKey}:card:${card.id}`);
+ }
+ });
+ });
+ });
+ });
+ return initial;
+ });
+ const isExpanded = (id: string) => expandedNodes.has(id);
+ const toggle = (id: string) => {
+ setExpandedNodes(current => {
+ const next = new Set(current);
+ if (next.has(id)) next.delete(id);
+ else next.add(id);
+ return next;
+ });
+ };
return (