From a3e8cda6f4fa15084fe72dbfb89167d491d1e7c6 Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Fri, 4 Apr 2025 10:52:03 -0500 Subject: [PATCH] course view tabs for mobile view sidebar for full screen --- .../content/courses/CourseSidebar.js | 179 +++++++++--------- src/config/appConfig.js | 1 + src/pages/course/[slug]/index.js | 167 +++++++++------- 3 files changed, 190 insertions(+), 157 deletions(-) diff --git a/src/components/content/courses/CourseSidebar.js b/src/components/content/courses/CourseSidebar.js index 95cee03..fe6e7ee 100644 --- a/src/components/content/courses/CourseSidebar.js +++ b/src/components/content/courses/CourseSidebar.js @@ -1,110 +1,111 @@ import React from 'react'; import { Tag } from 'primereact/tag'; -import { Button } from 'primereact/button'; import Image from 'next/image'; import { useImageProxy } from '@/hooks/useImageProxy'; -const CourseSidebar = ({ - lessons, - activeIndex, - onLessonSelect, - completedLessons, - isMobileView, - onClose, - sidebarVisible +const CourseSidebar = ({ + lessons, + activeIndex, + onLessonSelect, + completedLessons, + isMobileView, + onClose, + sidebarVisible, }) => { - const { returnImageProxy } = useImageProxy(); + const { returnImageProxy } = useImageProxy(); - const LessonItem = ({ lesson, index }) => ( -
  • ( +
  • onLessonSelect(index)} - > -
    - {lesson.image && ( -
    - {`Lesson -
    - )} -
    -
    - - Lesson {index + 1} - - {completedLessons.includes(lesson.id) && ( - - )} -
    -

    - {lesson.title} -

    -
    -
    -
  • - ); + onClick={() => onLessonSelect(index)} + > +
    + {lesson.image && ( +
    + {`Lesson +
    + )} +
    +
    + + Lesson {index + 1} + + {completedLessons.includes(lesson.id) && ( + + )} +
    +

    + {lesson.title} +

    +
    +
    + + ); - // For desktop sidebar - const DesktopSidebarContent = () => ( + // Desktop sidebar implementation + if (!isMobileView) { + return ( +
    -
    -
    -

    Course Lessons

    -
    -
    -
      - {lessons.map((lesson, index) => ( - - ))} -
    -
    +
    +
    +

    Course Lessons

    -
    - ); - - // For mobile sidebar - const MobileSidebarContent = () => ( -
    -
    -

    Course Lessons

    -
    -
      +
      +
        {lessons.map((lesson, index) => ( - + ))} -
      +
    +
    +
    +
    ); + } - // Desktop sidebar - if (!isMobileView) { - return ( -
    - -
    - ); - } + // Mobile sidebar implementation - completely restructured for better scrolling + if (isMobileView && sidebarVisible) { + return ( +
    +
    +

    Course Lessons

    +
    + + {/* Scrollable container with fixed height */} +
    +
    +
      + {lessons.map((lesson, index) => ( + + ))} +
    +
    +
    +
    + ); + } - // Mobile sidebar - now integrated with tab system - if (isMobileView && sidebarVisible) { - return ( -
    - -
    - ); - } - - return null; + return null; }; -export default CourseSidebar; \ No newline at end of file +export default CourseSidebar; diff --git a/src/config/appConfig.js b/src/config/appConfig.js index d24e55d..092e7da 100644 --- a/src/config/appConfig.js +++ b/src/config/appConfig.js @@ -12,6 +12,7 @@ const appConfig = { authorPubkeys: [ 'f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741', 'c67cd3e1a83daa56cff16f635db2fdb9ed9619300298d4701a58e68e84098345', + '6260f29fa75c91aaa292f082e5e87b438d2ab4fdf96af398567b01802ee2fcd4', ], customLightningAddresses: [ { diff --git a/src/pages/course/[slug]/index.js b/src/pages/course/[slug]/index.js index c667716..bf4d13f 100644 --- a/src/pages/course/[slug]/index.js +++ b/src/pages/course/[slug]/index.js @@ -5,17 +5,17 @@ import CourseDetails from '@/components/content/courses/CourseDetails'; import VideoLesson from '@/components/content/courses/VideoLesson'; import DocumentLesson from '@/components/content/courses/DocumentLesson'; import CombinedLesson from '@/components/content/courses/CombinedLesson'; +import CourseSidebar from '@/components/content/courses/CourseSidebar'; import { useNDKContext } from '@/context/NDKContext'; import { useSession } from 'next-auth/react'; import { nip19 } from 'nostr-tools'; import { useToast } from '@/hooks/useToast'; import { ProgressSpinner } from 'primereact/progressspinner'; -import { Accordion, AccordionTab } from 'primereact/accordion'; -import { Tag } from 'primereact/tag'; import { useDecryptContent } from '@/hooks/encryption/useDecryptContent'; import dynamic from 'next/dynamic'; import ZapThreadsWrapper from '@/components/ZapThreadsWrapper'; import appConfig from '@/config/appConfig'; +import useWindowWidth from '@/hooks/useWindowWidth'; const MDDisplay = dynamic(() => import('@uiw/react-markdown-preview'), { ssr: false, @@ -176,11 +176,15 @@ const Course = () => { const { ndk, addSigner } = useNDKContext(); const { data: session, update } = useSession(); const { showToast } = useToast(); - const [expandedIndex, setExpandedIndex] = useState(null); + const [activeIndex, setActiveIndex] = useState(0); const [completedLessons, setCompletedLessons] = useState([]); const [nAddresses, setNAddresses] = useState({}); const [nsec, setNsec] = useState(null); const [npub, setNpub] = useState(null); + const [sidebarVisible, setSidebarVisible] = useState(false); + const windowWidth = useWindowWidth(); + const isMobileView = windowWidth <= 968; + const [activeTab, setActiveTab] = useState('content'); // Default to content tab on mobile const setCompleted = useCallback(lessonId => { setCompletedLessons(prev => [...prev, lessonId]); @@ -220,12 +224,20 @@ const Course = () => { if (router.isReady) { const { active } = router.query; if (active !== undefined) { - setExpandedIndex(parseInt(active, 10)); + setActiveIndex(parseInt(active, 10)); } else { - setExpandedIndex(null); + setActiveIndex(0); + } + + // Auto-open sidebar on desktop, close on mobile + setSidebarVisible(!isMobileView); + + // Reset to content tab when switching to mobile + if (isMobileView) { + setActiveTab('content'); } } - }, [router.isReady, router.query]); + }, [router.isReady, router.query, isMobileView]); useEffect(() => { if (uniqueLessons.length > 0) { @@ -256,15 +268,15 @@ const Course = () => { setNpub(null); } }, [session]); + + const handleLessonSelect = index => { + setActiveIndex(index); + router.push(`/course/${router.query.slug}?active=${index}`, undefined, { shallow: true }); - const handleAccordionChange = e => { - const newIndex = e.index === expandedIndex ? null : e.index; - setExpandedIndex(newIndex); - - if (newIndex !== null) { - router.push(`/course/${router.query.slug}?active=${newIndex}`, undefined, { shallow: true }); - } else { - router.push(`/course/${router.query.slug}`, undefined, { shallow: true }); + // On mobile, switch to content tab after selection + if (isMobileView) { + setActiveTab('content'); + setSidebarVisible(false); } }; @@ -285,6 +297,15 @@ const Course = () => { ); }; + const toggleTab = tab => { + setActiveTab(tab); + if (tab === 'lessons') { + setSidebarVisible(true); + } else { + setSidebarVisible(false); + } + }; + if (courseLoading || decryptionLoading) { return (
    @@ -339,62 +360,72 @@ const Course = () => { handlePaymentError={handlePaymentError} /> )} - - {uniqueLessons.length > 0 && - uniqueLessons.map((lesson, index) => ( - - {`Lesson ${index + 1}: ${lesson.title}`} - {completedLessons.includes(lesson.id) ? ( - - ) : null} -
    - } + +
    + {/* Mobile tab navigation */} + {isMobileView && ( +
    + + +
    + )} + +
    + {/* Course Sidebar Component */} + { + setSidebarVisible(false); + if (isMobileView) setActiveTab('content'); + }} + sidebarVisible={sidebarVisible} + /> + + {/* Main content */} +
    + {uniqueLessons.length > 0 && uniqueLessons[activeIndex] ? ( +
    + {renderLesson(uniqueLessons[activeIndex])}
    - - ))} - -
    - {course?.content && } + ) : ( +
    +

    Select a lesson from the sidebar to begin learning.

    +
    + )} + + {course?.content && ( +
    + +
    + )} +
    +
    );