From ae233f14625c93c568edb365e626e668139b9bd2 Mon Sep 17 00:00:00 2001 From: Zaid Ahmad <109442753+zaidahmad16@users.noreply.github.com> Date: Mon, 13 Jul 2026 20:35:13 -0400 Subject: [PATCH 1/2] Default Explorer to core courses with toggle for full graph The full course graph is overwhelming on first load with heavy edge fan-out. Default to showing only core CS-program courses, with a toggle in the Explorer view to switch to the full course set. Filtering happens outside computeLayout: the visible course set is derived first (core vs all), edges are filtered to those with both endpoints visible, and layout is recomputed over that set so later filter modes can follow the same pattern. --- .gitignore | 3 +- src/pages/Explorer.tsx | 65 +++++++++++++++++++++++++++++--------- src/store/explorerStore.ts | 5 +++ 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index fc6b291..dcaea37 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ dist-ssr *.sw? # Output -scripts/output/*.json \ No newline at end of file +scripts/output/*.json +coverage \ No newline at end of file diff --git a/src/pages/Explorer.tsx b/src/pages/Explorer.tsx index a198501..ead845e 100644 --- a/src/pages/Explorer.tsx +++ b/src/pages/Explorer.tsx @@ -19,8 +19,14 @@ import { type Edge, } from '@xyflow/react'; import dagre from '@dagrejs/dagre'; -import { courseList, courses, prereqEdges } from '@/data/loadCourses'; +import { + courseList, + coreCourseList, + courses, + prereqEdges, +} from '@/data/loadCourses'; import { useExplorerStore } from '@/store/explorerStore'; +import type { Course } from '@/types/course'; import CourseNode from '@/components/CourseNode'; import type { CourseNodeData } from '@/components/CourseNode'; import CourseDetailPanel from '@/components/CourseDetailPanel'; @@ -28,14 +34,10 @@ import CourseDetailPanel from '@/components/CourseDetailPanel'; const NODE_W = 180; const NODE_H = 60; -// Only draw edges where both endpoints are in our course set; SYSC courses that -// appear in COMP 3004's prereqs are not nodes yet (see TODO #3 above). -const knownCodes = new Set(courseList.map((c) => c.code)); -const visibleEdges = prereqEdges.filter( - (e) => knownCodes.has(e.from) && knownCodes.has(e.to), -); - -function computeLayout(): { +function computeLayout( + visibleCourses: Course[], + visibleEdges: { from: string; to: string }[], +): { nodes: Node[]; edges: Edge[]; } { @@ -43,7 +45,7 @@ function computeLayout(): { g.setDefaultEdgeLabel(() => ({})); g.setGraph({ rankdir: 'TB', ranksep: 80, nodesep: 40 }); - for (const course of courseList) { + for (const course of visibleCourses) { g.setNode(course.code, { width: NODE_W, height: NODE_H }); } @@ -55,7 +57,7 @@ function computeLayout(): { dagre.layout(g); - const nodes: Node[] = courseList.map((course) => { + const nodes: Node[] = visibleCourses.map((course) => { const pos = g.node(course.code); return { id: course.code, @@ -78,11 +80,35 @@ function computeLayout(): { const nodeTypes: NodeTypes = { courseNode: CourseNode }; export default function Explorer() { - const { selectedCourse, highlightedSet, setSelectedCourse } = - useExplorerStore(); + const { + selectedCourse, + highlightedSet, + setSelectedCourse, + showAllCourses, + toggleShowAllCourse, + } = useExplorerStore(); + + // The single source of truth for "what's shown" — later filter modes + // (reachable-on-click, department/year, search) should derive their own + // visible set the same way, upstream of layout. + const visibleCourses = showAllCourses ? courseList : coreCourseList; + const visibleCodes = useMemo( + () => new Set(visibleCourses.map((c) => c.code)), + [visibleCourses], + ); + const visibleEdges = useMemo( + () => + prereqEdges.filter( + (e) => visibleCodes.has(e.from) && visibleCodes.has(e.to), + ), + [visibleCodes], + ); - // Layout is derived entirely from static import-time data; deps array is empty. - const { nodes, edges: layoutEdges } = useMemo(() => computeLayout(), []); + // Layout is recomputed whenever the visible course set changes. + const { nodes, edges: layoutEdges } = useMemo( + () => computeLayout(visibleCourses, visibleEdges), + [visibleCourses, visibleEdges], + ); // Re-derive edge styles when selection changes. const edges = useMemo( @@ -107,6 +133,8 @@ export default function Explorer() { return (
+ setSelectedCourse(null)} diff --git a/src/store/explorerStore.ts b/src/store/explorerStore.ts index f259594..aa93872 100644 --- a/src/store/explorerStore.ts +++ b/src/store/explorerStore.ts @@ -6,6 +6,8 @@ interface ExplorerState { selectedCourse: string | null; highlightedSet: Set; setSelectedCourse: (code: string | null) => void; + showAllCourses: boolean; + toggleShowAllCourse: () => void; } export const useExplorerStore = create((set) => ({ @@ -23,4 +25,7 @@ export const useExplorerStore = create((set) => ({ ...getDescendants(code, prereqEdges), ]), }), + showAllCourses: false, + toggleShowAllCourse: () => + set((state) => ({ showAllCourses: !state.showAllCourses })), })); From 264e505615cd0dce35380e22b0cbc7f4b1f72ddf Mon Sep 17 00:00:00 2001 From: Zaid Ahmad <109442753+zaidahmad16@users.noreply.github.com> Date: Mon, 13 Jul 2026 21:04:55 -0400 Subject: [PATCH 2/2] test