diff --git a/globalSettings.yml b/globalSettings.yml index 1553301..d0372cc 100644 --- a/globalSettings.yml +++ b/globalSettings.yml @@ -1,12 +1,6 @@ courses: - - path: ./4850_AdvancedFE/2025-fall-alex/modules/ - name: Adv Frontend - path: ./1420/2025-fall-alex/modules/ name: "1420" - - path: ./1810/2025-fall-alex/modules/ - name: Web Intro - - path: ./1430/2025-fall-alex/modules/ - name: UX - path: ./1425/2025-fall-alex/modules/ name: "1425" - path: ./4850_AdvancedFE/2026-spring-alex/modules @@ -25,5 +19,3 @@ courses: name: distributed-old - path: ./3840_Telemetry/2025_spring_alex/modules/ name: telemetry-old - - path: ./3840_Telemetry/2024Spring_alex/modules/ - name: telemetry-old-old diff --git a/src/app/course/[courseName]/CollapsableSidebar.tsx b/src/app/course/[courseName]/CollapsableSidebar.tsx index b904747..67572e1 100644 --- a/src/app/course/[courseName]/CollapsableSidebar.tsx +++ b/src/app/course/[courseName]/CollapsableSidebar.tsx @@ -10,12 +10,15 @@ const collapseThreshold = 1400; export default function CollapsableSidebar() { const [windowCollapseRecommended, setWindowCollapseRecommended] = - useState(window.innerWidth <= collapseThreshold); + useState(false); const [userCollapsed, setUserCollapsed] = useState< "unset" | "collapsed" | "uncollapsed" >("unset"); useEffect(() => { + // Initialize on mount + setWindowCollapseRecommended(window.innerWidth <= collapseThreshold); + function handleResize() { if (window.innerWidth <= collapseThreshold) { setWindowCollapseRecommended(true); diff --git a/src/app/course/[courseName]/CourseNavigation.tsx b/src/app/course/[courseName]/CourseNavigation.tsx index 443224c..cedd7ab 100644 --- a/src/app/course/[courseName]/CourseNavigation.tsx +++ b/src/app/course/[courseName]/CourseNavigation.tsx @@ -1,4 +1,5 @@ "use client"; +import { BreadCrumbs } from "@/components/BreadCrumbs"; import { Spinner } from "@/components/Spinner"; import { useCanvasAssignmentsQuery, @@ -19,7 +20,6 @@ import { } from "@/features/canvas/hooks/canvasQuizHooks"; import { useLocalCourseSettingsQuery } from "@/features/local/course/localCoursesHooks"; import { useQueryClient } from "@tanstack/react-query"; -import Link from "next/link"; export function CourseNavigation() { const { data: settings } = useLocalCourseSettingsQuery(); @@ -33,9 +33,8 @@ export function CourseNavigation() { return (
- - Back to Course List - + + - + diff --git a/src/app/course/[courseName]/lecture/[lectureDay]/EditLectureTitle.tsx b/src/app/course/[courseName]/lecture/[lectureDay]/EditLectureTitle.tsx index 5c4bff6..6ec18ca 100644 --- a/src/app/course/[courseName]/lecture/[lectureDay]/EditLectureTitle.tsx +++ b/src/app/course/[courseName]/lecture/[lectureDay]/EditLectureTitle.tsx @@ -1,10 +1,11 @@ import { useLocalCourseSettingsQuery } from "@/features/local/course/localCoursesHooks"; import { getDateFromString } from "@/features/local/utils/timeUtils"; import { getLectureWeekName } from "@/features/local/lectures/lectureUtils"; -import { getCourseUrl, getLecturePreviewUrl } from "@/services/urlUtils"; +import { getLecturePreviewUrl } from "@/services/urlUtils"; import { useCourseContext } from "../../context/courseContext"; import Link from "next/link"; import { getDayOfWeek } from "@/features/local/course/localCourseSettings"; +import { BreadCrumbs } from "@/components/BreadCrumbs"; export default function EditLectureTitle({ lectureDay, @@ -17,16 +18,7 @@ export default function EditLectureTitle({ const lectureWeekName = getLectureWeekName(settings.startDate, lectureDay); return (
-
- - {courseName} - -
+

Lecture

diff --git a/src/app/course/[courseName]/lecture/[lectureDay]/preview/LecturePreviewPage.tsx b/src/app/course/[courseName]/lecture/[lectureDay]/preview/LecturePreviewPage.tsx index d70f792..115c239 100644 --- a/src/app/course/[courseName]/lecture/[lectureDay]/preview/LecturePreviewPage.tsx +++ b/src/app/course/[courseName]/lecture/[lectureDay]/preview/LecturePreviewPage.tsx @@ -1,17 +1,14 @@ "use client"; import LecturePreview from "../LecturePreview"; -import { getCourseUrl, getLectureUrl } from "@/services/urlUtils"; -import { useCourseContext } from "../../../context/courseContext"; -import Link from "next/link"; import { useLecturesSuspenseQuery } from "@/features/local/lectures/lectureHooks"; +import { BreadCrumbs } from "@/components/BreadCrumbs"; export default function LecturePreviewPage({ lectureDay, }: { lectureDay: string; }) { - const { courseName } = useCourseContext(); const { data: weeks } = useLecturesSuspenseQuery(); const lecture = weeks .flatMap(({ lectures }) => lectures.map((lecture) => lecture)) @@ -23,20 +20,7 @@ export default function LecturePreviewPage({ return (
-
- - Edit Lecture - -
-
- - Course Calendar - -
+
- - {courseName} - - -
{assignmentName}
+
+
+ + + + +
{assignmentName}
+
+
+ +
); } diff --git a/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/UpdateAssignmentName.tsx b/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/UpdateAssignmentName.tsx index 055c9ad..c33e744 100644 --- a/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/UpdateAssignmentName.tsx +++ b/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/UpdateAssignmentName.tsx @@ -40,8 +40,7 @@ export function UpdateAssignmentName({ if (name === assignmentName) closeModal(); setIsLoading(true); // page refresh resets flag - try{ - + try { await updateAssignment.mutateAsync({ assignment: assignment, moduleName, @@ -50,17 +49,28 @@ export function UpdateAssignmentName({ previousAssignmentName: assignmentName, courseName, }); - + // update url (will trigger reload...) router.replace( getModuleItemUrl(courseName, moduleName, "assignment", name), {} ); - }finally { + } finally { setIsLoading(false); } }} > +
+ Warning: does not rename in Canvas +
- - {courseName} - - -
{pageName}
+
+
+ + + + +
{pageName}
+
+
+ +
); } diff --git a/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/UpdatePageName.tsx b/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/UpdatePageName.tsx index cce8cd0..268c0c3 100644 --- a/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/UpdatePageName.tsx +++ b/src/app/course/[courseName]/modules/[moduleName]/page/[pageName]/UpdatePageName.tsx @@ -56,6 +56,17 @@ export function UpdatePageName({ ); }} > +
+ Warning: does not rename in Canvas +
{isLoading && } diff --git a/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuizHeader.tsx b/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuizHeader.tsx index 612814f..db31cb2 100644 --- a/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuizHeader.tsx +++ b/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/EditQuizHeader.tsx @@ -1,7 +1,6 @@ -import { useCourseContext } from "@/app/course/[courseName]/context/courseContext"; -import { getCourseUrl } from "@/services/urlUtils"; -import Link from "next/link"; +import { RightSingleChevron } from "@/components/icons/RightSingleChevron"; import { UpdateQuizName } from "./UpdateQuizName"; +import { BreadCrumbs } from "@/components/BreadCrumbs"; export default function EditQuizHeader({ moduleName, @@ -10,19 +9,18 @@ export default function EditQuizHeader({ quizName: string; moduleName: string; }) { - const { courseName } = useCourseContext(); return ( -
- - {courseName} - - -
{quizName}
+
+
+ + + + +
{quizName}
+
+
+ +
); } diff --git a/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/UpdateQuizName.tsx b/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/UpdateQuizName.tsx index f1968a0..5af26a7 100644 --- a/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/UpdateQuizName.tsx +++ b/src/app/course/[courseName]/modules/[moduleName]/quiz/[quizName]/UpdateQuizName.tsx @@ -56,6 +56,17 @@ export function UpdateQuizName({ ); }} > +
+ Warning: does not rename in Canvas +
{isLoading && } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 043dd9f..1793b71 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -20,7 +20,7 @@ export default async function RootLayout({ return ( - +
@@ -29,7 +29,7 @@ export default async function RootLayout({ {children} - +
diff --git a/src/components/BreadCrumbs.tsx b/src/components/BreadCrumbs.tsx new file mode 100644 index 0000000..566f38e --- /dev/null +++ b/src/components/BreadCrumbs.tsx @@ -0,0 +1,98 @@ +"use client"; + +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import HomeIcon from "./icons/HomeIcon"; +import { RightSingleChevron } from "./icons/RightSingleChevron"; + +export const BreadCrumbs = () => { + const pathname = usePathname(); + + const pathSegments = pathname?.split("/").filter(Boolean) || []; + const isCourseRoute = pathSegments[0] === "course"; + const isOnCoursePage = isCourseRoute && pathSegments.length === 2; + + const courseName = + isCourseRoute && !isOnCoursePage && pathSegments[1] + ? decodeURIComponent(pathSegments[1]) + : null; + + const isLectureRoute = isCourseRoute && pathSegments[2] === "lecture"; + const isOnLecturePage = isLectureRoute && pathSegments.length === 4; + const lectureDate = + isLectureRoute && !isOnLecturePage && pathSegments[3] + ? decodeURIComponent(pathSegments[3]) + : null; + + const sharedBackgroundClassNames = ` + group + hover:bg-blue-900/30 + rounded-lg + h-full + flex + items-center + transition + `; + const sharedLinkClassNames = ` + text-slate-300 + transition + group-hover:text-slate-100 + rounded-lg + h-full + flex + items-center + px-3 + `; + + return ( + + ); +}; diff --git a/src/components/icons/ExpandIcon.tsx b/src/components/icons/ExpandIcon.tsx index 6a3f10e..0ae03b8 100644 --- a/src/components/icons/ExpandIcon.tsx +++ b/src/components/icons/ExpandIcon.tsx @@ -16,19 +16,19 @@ export default function ExpandIcon({ fill="none" xmlns="http://www.w3.org/2000/svg" > - + diff --git a/src/components/icons/HomeIcon.tsx b/src/components/icons/HomeIcon.tsx new file mode 100644 index 0000000..6c59799 --- /dev/null +++ b/src/components/icons/HomeIcon.tsx @@ -0,0 +1,23 @@ +import React from "react"; + +// https://www.svgrepo.com/collection/wolf-kit-solid-glyph-icons/?search=home +export default function HomeIcon() { + return ( + + + + + + + + ); +} diff --git a/src/components/icons/RightSingleChevron.tsx b/src/components/icons/RightSingleChevron.tsx new file mode 100644 index 0000000..4d4f8ea --- /dev/null +++ b/src/components/icons/RightSingleChevron.tsx @@ -0,0 +1,27 @@ +import React from "react"; + +// https://www.svgrepo.com/svg/491374/chevron-small-right +export const RightSingleChevron = () => { + return ( + + + + + + + + ); +};