From bfce0b4bb7f188c5546671d7ed4b3c0eeb260e0b Mon Sep 17 00:00:00 2001 From: Arik Chakma Date: Fri, 28 Mar 2025 23:40:40 +0600 Subject: [PATCH] feat: make chat resizeable --- package.json | 1 + pnpm-lock.yaml | 14 + .../GenerateCourse/AICourseContent.tsx | 10 +- .../GenerateCourse/AICourseLesson.tsx | 426 ++++++++++-------- .../GenerateCourse/AICourseLessonChat.tsx | 36 +- src/components/GenerateCourse/Resizeable.tsx | 42 ++ 6 files changed, 296 insertions(+), 233 deletions(-) create mode 100644 src/components/GenerateCourse/Resizeable.tsx diff --git a/package.json b/package.json index aeb3d2be3..aaa3f40f0 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "react-calendar-heatmap": "^1.9.0", "react-confetti": "^6.1.0", "react-dom": "^18.3.1", + "react-resizable-panels": "^2.1.7", "react-textarea-autosize": "^8.5.7", "react-tooltip": "^5.28.0", "reactflow": "^11.11.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a8d60a16..8c4b70579 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -113,6 +113,9 @@ importers: react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) + react-resizable-panels: + specifier: ^2.1.7 + version: 2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-textarea-autosize: specifier: ^8.5.7 version: 8.5.7(@types/react@18.3.18)(react@18.3.1) @@ -2988,6 +2991,12 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} + react-resizable-panels@2.1.7: + resolution: {integrity: sha512-JtT6gI+nURzhMYQYsx8DKkx6bSoOGFp7A3CwMrOb8y5jFHFyqwo9m68UhmXRw57fRVJksFn1TSlm3ywEQ9vMgA==} + peerDependencies: + react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-textarea-autosize@8.5.7: resolution: {integrity: sha512-2MqJ3p0Jh69yt9ktFIaZmORHXw4c4bxSIhCeWiFwmJ9EYKgLmuNII3e9c9b2UO+ijl4StnpZdqpxNIhTdHvqtQ==} engines: {node: '>=10'} @@ -6503,6 +6512,11 @@ snapshots: react-refresh@0.14.2: {} + react-resizable-panels@2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-textarea-autosize@8.5.7(@types/react@18.3.18)(react@18.3.1): dependencies: '@babel/runtime': 7.26.9 diff --git a/src/components/GenerateCourse/AICourseContent.tsx b/src/components/GenerateCourse/AICourseContent.tsx index ce9b6085d..c080c959b 100644 --- a/src/components/GenerateCourse/AICourseContent.tsx +++ b/src/components/GenerateCourse/AICourseContent.tsx @@ -39,7 +39,7 @@ export function AICourseContent(props: AICourseContentProps) { const [showUpgradeModal, setShowUpgradeModal] = useState(false); const [showAILimitsPopup, setShowAILimitsPopup] = useState(false); - const [isAIChatsOpen, setIsAIChatsOpen] = useState(true); + const [isAIChatsOpen, setIsAIChatsOpen] = useState(false); const [activeModuleIndex, setActiveModuleIndex] = useState(0); const [activeLessonIndex, setActiveLessonIndex] = useState(0); @@ -211,12 +211,6 @@ export function AICourseContent(props: AICourseContentProps) { const isViewingLesson = viewMode === 'module'; - useEffect(() => { - if (window && window?.innerWidth < 1024 && isAIChatsOpen) { - setIsAIChatsOpen(false); - } - }, []); - return (
{modals} @@ -257,7 +251,7 @@ export function AICourseContent(props: AICourseContentProps) { )} )} - + + {!isGenerating && !isLoading && ( +
+ - { - generateAiCourseContent(true, prompt); - }} - /> - + +
+ )} - )} - -

- {currentLessonTitle?.replace(/^Lesson\s*?\d+[\.:]\s*/, '')} -

- - {!error && isLoggedIn() && ( -
- )} - - {error && isLoggedIn() && ( -
- {error.includes('reached the limit') ? ( -
-

- Limit reached -

-

- You have reached the AI usage limit for today. - {!isPaidUser && ( - <>Please upgrade your account to continue. - )} - {isPaidUser && ( - <> Please wait until tomorrow to continue. - )} -

+

+ {currentLessonTitle?.replace(/^Lesson\s*?\d+[\.:]\s*/, '')} +

- {!isPaidUser && ( - + {!error && isLoggedIn() && ( +
+ )} + + {error && isLoggedIn() && ( +
+ {error.includes('reached the limit') ? ( +
+

+ Limit reached +

+

+ You have reached the AI usage limit for today. + {!isPaidUser && ( + <>Please upgrade your account to continue. + )} + {isPaidUser && ( + <> Please wait until tomorrow to continue. + )} +

+ + {!isPaidUser && ( + + )} +
+ ) : ( +

{error}

)}
- ) : ( -

{error}

)} -
- )} - - {!isLoggedIn() && ( -
- -

- Please login to generate course content -

-
- )} - - {!isLoading && !isGenerating && !error && ( - - )} - -
-
)} - > - - Previous  Lesson - - -
- + +
+ + } + }} + disabled={cantGoForward || isTogglingDone} + className={cn( + 'flex items-center rounded-full px-4 py-2 disabled:opacity-50 max-lg:px-3 max-lg:py-1.5 max-lg:text-sm', + cantGoForward + ? 'cursor-not-allowed text-gray-400' + : 'bg-gray-800 text-white hover:bg-gray-700', + )} + > + {isTogglingDone ? ( + <> + + Please wait ... + + ) : ( + <> + Next{' '} +  Lesson + + + )} + +
+
+ +
+ + {isAIChatsOpen && ( + <> + + + + + + )} - +
+
+ + +
-
- - setIsAIChatsOpen(false)} - isAIChatsOpen={isAIChatsOpen} - setIsAIChatsOpen={setIsAIChatsOpen} - /> +
); } diff --git a/src/components/GenerateCourse/AICourseLessonChat.tsx b/src/components/GenerateCourse/AICourseLessonChat.tsx index e834b09b4..14a023ec7 100644 --- a/src/components/GenerateCourse/AICourseLessonChat.tsx +++ b/src/components/GenerateCourse/AICourseLessonChat.tsx @@ -46,25 +46,11 @@ type AICourseLessonChatProps = { lessonTitle: string; onUpgradeClick: () => void; isDisabled?: boolean; - - onClose: () => void; - - isAIChatsOpen: boolean; - setIsAIChatsOpen: (isAIChatsOpen: boolean) => void; }; export function AICourseLessonChat(props: AICourseLessonChatProps) { - const { - courseSlug, - moduleTitle, - lessonTitle, - onUpgradeClick, - isDisabled, - onClose, - - isAIChatsOpen, - setIsAIChatsOpen, - } = props; + const { courseSlug, moduleTitle, lessonTitle, onUpgradeClick, isDisabled } = + props; const toast = useToast(); const scrollareaRef = useRef(null); @@ -211,24 +197,8 @@ export function AICourseLessonChat(props: AICourseLessonChatProps) { return ( <> - {isAIChatsOpen && ( -
- )} -
+
- -

Course AI

diff --git a/src/components/GenerateCourse/Resizeable.tsx b/src/components/GenerateCourse/Resizeable.tsx new file mode 100644 index 000000000..8f8092491 --- /dev/null +++ b/src/components/GenerateCourse/Resizeable.tsx @@ -0,0 +1,42 @@ +import { GripVertical } from 'lucide-react'; +import * as ResizablePrimitive from 'react-resizable-panels'; +import { cn } from '../../lib/classname'; + +const ResizablePanelGroup = ({ + className, + ...props +}: React.ComponentProps) => ( + +); + +const ResizablePanel = ResizablePrimitive.Panel; + +const ResizableHandle = ({ + withHandle, + className, + ...props +}: React.ComponentProps & { + withHandle?: boolean; +}) => ( + div]:rotate-90', + className, + )} + {...props} + > + {withHandle && ( +
+ +
+ )} +
+); + +export { ResizablePanelGroup, ResizablePanel, ResizableHandle };