diff --git a/src/components/AITutor/AIExploreCourseListing.tsx b/src/components/AITutor/AIExploreCourseListing.tsx index 8fbcc366f..15ac7c9ef 100644 --- a/src/components/AITutor/AIExploreCourseListing.tsx +++ b/src/components/AITutor/AIExploreCourseListing.tsx @@ -86,7 +86,7 @@ export function AIExploreCourseListing() { {!isExploreAiCoursesLoading && courses && courses.length > 0 && ( <div className="flex flex-col gap-2"> - <div className="grid grid-cols-3 gap-2"> + <div className="grid grid-cols-1 gap-2 md:grid-cols-2 lg:grid-cols-3"> {courses.map((course) => ( <AICourseCard key={course._id} diff --git a/src/components/AITutor/AITutorLayout.tsx b/src/components/AITutor/AITutorLayout.tsx index c7663c48f..b50849495 100644 --- a/src/components/AITutor/AITutorLayout.tsx +++ b/src/components/AITutor/AITutorLayout.tsx @@ -1,4 +1,7 @@ +import { Menu } from 'lucide-react'; +import { useState } from 'react'; import { AITutorSidebar, type AITutorTab } from './AITutorSidebar'; +import { RoadmapLogoIcon } from '../ReactIcons/RoadmapLogo'; type AITutorLayoutProps = { children: React.ReactNode; @@ -8,12 +11,32 @@ type AITutorLayoutProps = { export function AITutorLayout(props: AITutorLayoutProps) { const { children, activeTab } = props; + const [isSidebarFloating, setIsSidebarFloating] = useState(false); + return ( - <div className="flex flex-grow flex-row"> - <AITutorSidebar activeTab={activeTab} /> - <div className="flex flex-grow h-screen overflow-y-scroll flex-col bg-gray-100 px-4 py-4"> - {children} + <> + <div className="flex flex-row items-center justify-between border-b border-slate-200 px-4 py-3 lg:hidden"> + <a href="/" className="flex flex-row items-center gap-1.5"> + <RoadmapLogoIcon className="size-6 text-gray-500" color="black" /> + </a> + <button + className="flex flex-row items-center gap-1" + onClick={() => setIsSidebarFloating(!isSidebarFloating)} + > + <Menu className="size-5 text-gray-500" /> + </button> + </div> + + <div className="flex flex-grow flex-row"> + <AITutorSidebar + onClose={() => setIsSidebarFloating(false)} + isFloating={isSidebarFloating} + activeTab={activeTab} + /> + <div className="flex flex-grow flex-col overflow-y-scroll bg-gray-100 p-3 lg:px-4 lg:py-4"> + {children} + </div> </div> - </div> + </> ); } diff --git a/src/components/AITutor/AITutorSidebar.tsx b/src/components/AITutor/AITutorSidebar.tsx index c6b1a7aa5..5ee4fccc2 100644 --- a/src/components/AITutor/AITutorSidebar.tsx +++ b/src/components/AITutor/AITutorSidebar.tsx @@ -1,8 +1,10 @@ -import { BookOpen, Compass, Plus, Star, Users2 } from 'lucide-react'; +import { BookOpen, Compass, Plus, Star, X } from 'lucide-react'; import { AITutorLogo } from '../ReactIcons/AITutorLogo'; type AITutorSidebarProps = { + isFloating: boolean; activeTab: AITutorTab; + onClose: () => void; }; const sidebarItems = [ @@ -35,49 +37,68 @@ const sidebarItems = [ export type AITutorTab = (typeof sidebarItems)[number]['key']; export function AITutorSidebar(props: AITutorSidebarProps) { - const { activeTab } = props; + const { activeTab, isFloating, onClose } = props; return ( - <aside className="hidden w-[255px] shrink-0 border-r border-slate-200 md:block"> - <div className="flex flex-col items-start justify-center px-6 py-5"> - <div className="flex flex-row items-center gap-1"> - <AITutorLogo className="size-11 text-gray-500" color="black" /> + <> + <aside + className={`w-[255px] shrink-0 border-r border-slate-200 ${ + isFloating + ? 'fixed top-0 bottom-0 left-0 z-50 block border-r-0 bg-white shadow-xl' + : 'hidden lg:block' + }`} + > + {isFloating && ( + <button className="absolute top-3 right-3" onClick={onClose}> + <X + strokeWidth={3} + className="size-3.5 text-gray-400 hover:text-black" + /> + </button> + )} + <div className="flex flex-col items-start justify-center px-6 py-5"> + <div className="flex flex-row items-center gap-1"> + <AITutorLogo className="size-11 text-gray-500" color="black" /> + </div> + <div className="my-3 flex flex-col"> + <h2 className="-mb-px text-base font-semibold text-black"> + AI Tutor + </h2> + <span className="text-xs text-gray-500"> + by{' '} + <a href="/" className="underline-offset-2 hover:underline"> + roadmap.sh + </a> + </span> + </div> + <p className="max-w-[150px] text-xs text-gray-500"> + Your personalized learning companion for any topic + </p> </div> - <div className="my-3 flex flex-col"> - <h2 className="-mb-px text-base font-semibold text-black"> - AI Tutor - </h2> - <span className="text-xs text-gray-500"> - by{' '} - <a href="/" className="underline-offset-2 hover:underline"> - roadmap.sh - </a> - </span> - </div> - <p className="max-w-[150px] text-xs text-gray-500"> - Your personalized learning companion for any topic - </p> - </div> - <ul className="space-y-1"> - {sidebarItems.map((item) => ( - <li key={item.key}> - <a - href={item.href} - className={`font-regular flex w-full items-center border-r-2 px-5 py-2 text-sm transition-all ${ - activeTab === item.key - ? 'border-r-black bg-gray-100 text-black' - : 'border-r-transparent text-gray-500 hover:border-r-gray-300' - }`} - > - <span className="flex grow items-center"> - <item.icon className="mr-2 size-4" /> - {item.label} - </span> - </a> - </li> - ))} - </ul> - </aside> + <ul className="space-y-1"> + {sidebarItems.map((item) => ( + <li key={item.key}> + <a + href={item.href} + className={`font-regular flex w-full items-center border-r-2 px-5 py-2 text-sm transition-all ${ + activeTab === item.key + ? 'border-r-black bg-gray-100 text-black' + : 'border-r-transparent text-gray-500 hover:border-r-gray-300' + }`} + > + <span className="flex grow items-center"> + <item.icon className="mr-2 size-4" /> + {item.label} + </span> + </a> + </li> + ))} + </ul> + </aside> + {isFloating && ( + <div className="fixed inset-0 z-40 bg-black/50" onClick={onClose} /> + )} + </> ); } diff --git a/src/components/GenerateCourse/AICourse.tsx b/src/components/GenerateCourse/AICourse.tsx index eba3cecd5..2e6fffb70 100644 --- a/src/components/GenerateCourse/AICourse.tsx +++ b/src/components/GenerateCourse/AICourse.tsx @@ -72,11 +72,11 @@ export function AICourse(props: AICourseProps) { } return ( - <div className="mx-auto flex w-full max-w-3xl flex-grow flex-col justify-center"> - <h1 className="mb-2.5 text-center text-4xl font-semibold max-sm:mb-2 max-sm:text-left max-sm:text-xl"> + <div className="mx-auto flex w-full max-w-3xl flex-grow flex-col pt-4 md:justify-center md:pt-10 lg:pt-0"> + <h1 className="mb-0.5 text-center text-4xl font-semibold max-md:text-left max-md:text-xl lg:mb-3"> What can I help you learn? </h1> - <p className="mb-6 text-center text-lg text-gray-600 max-sm:hidden max-sm:text-left max-sm:text-sm"> + <p className="mb-3 text-balance text-center text-lg text-gray-600 max-md:text-left max-md:text-sm lg:mb-6"> Enter a topic below to generate a personalized course for it </p> @@ -100,7 +100,7 @@ export function AICourse(props: AICourseProps) { maxLength={50} /> - <div className="flex flex-row items-center justify-between gap-2 px-4 pb-4"> + <div className="flex flex-col items-start justify-between gap-2 px-4 pb-4 md:flex-row md:items-center"> <div className="flex flex-row items-center gap-2"> <div className="flex flex-row gap-2"> <DifficultyDropdown @@ -119,7 +119,8 @@ export function AICourse(props: AICourseProps) { className="mr-1" id="fine-tune-checkbox" /> - Explain more for a better course + Explain more + <span className="hidden md:inline"> for a better course</span> </label> </div> @@ -127,7 +128,7 @@ export function AICourse(props: AICourseProps) { type="submit" disabled={!keyword.trim()} className={cn( - 'flex items-center justify-center rounded-full px-4 py-1 text-sm text-white transition-colors', + 'hidden items-center justify-center rounded-full px-4 py-1 text-sm text-white transition-colors md:flex', !keyword.trim() ? 'cursor-not-allowed bg-gray-400' : 'bg-black hover:bg-gray-800', @@ -148,6 +149,20 @@ export function AICourse(props: AICourseProps) { setGoal={setGoal} setCustomInstructions={setCustomInstructions} /> + + <button + type="submit" + disabled={!keyword.trim()} + className={cn( + 'mx-4 mb-3 flex items-center justify-center rounded-full px-4 py-1 text-sm text-white transition-colors md:hidden', + !keyword.trim() + ? 'cursor-not-allowed bg-gray-400' + : 'bg-black hover:bg-gray-800', + )} + > + <WandIcon size={18} className="mr-2" /> + Generate Course + </button> </form> </div> </div>