From 9fb00a617f8050adb60a64570cfe1882f1c6346c Mon Sep 17 00:00:00 2001 From: Arik Chakma Date: Wed, 5 Mar 2025 21:54:14 +0600 Subject: [PATCH] wip: autogrow textarea & examples --- package.json | 1 + pnpm-lock.yaml | 77 +++++++++++++++ .../AICourseFollowUpPopover.tsx | 99 +++++++++++++++++-- 3 files changed, 168 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index ae7bed2a5..70cce2884 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-textarea-autosize": "^8.5.7", "react-tooltip": "^5.28.0", "reactflow": "^11.11.4", "rehype-external-links": "^3.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 378361fba..6d1855787 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-textarea-autosize: + specifier: ^8.5.7 + version: 8.5.7(@types/react@18.3.18)(react@18.3.1) react-tooltip: specifier: ^5.28.0 version: 5.28.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -356,6 +359,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/runtime@7.26.9': + resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} + engines: {node: '>=6.9.0'} + '@babel/template@7.25.9': resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} engines: {node: '>=6.9.0'} @@ -2901,6 +2908,12 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} + react-textarea-autosize@8.5.7: + resolution: {integrity: sha512-2MqJ3p0Jh69yt9ktFIaZmORHXw4c4bxSIhCeWiFwmJ9EYKgLmuNII3e9c9b2UO+ijl4StnpZdqpxNIhTdHvqtQ==} + engines: {node: '>=10'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-tooltip@5.28.0: resolution: {integrity: sha512-R5cO3JPPXk6FRbBHMO0rI9nkUG/JKfalBSQfZedZYzmqaZQgq7GLzF8vcCWx6IhUCKg0yPqJhXIzmIO5ff15xg==} peerDependencies: @@ -2924,6 +2937,9 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + regex-recursion@5.1.1: resolution: {integrity: sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w==} @@ -3304,6 +3320,33 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + use-composed-ref@1.4.0: + resolution: {integrity: sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-isomorphic-layout-effect@1.2.0: + resolution: {integrity: sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-latest@1.3.0: + resolution: {integrity: sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + use-sync-external-store@1.4.0: resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==} peerDependencies: @@ -3662,6 +3705,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/runtime@7.26.9': + dependencies: + regenerator-runtime: 0.14.1 + '@babel/template@7.25.9': dependencies: '@babel/code-frame': 7.26.2 @@ -6299,6 +6346,15 @@ snapshots: react-refresh@0.14.2: {} + react-textarea-autosize@8.5.7(@types/react@18.3.18)(react@18.3.1): + dependencies: + '@babel/runtime': 7.26.9 + react: 18.3.1 + use-composed-ref: 1.4.0(@types/react@18.3.18)(react@18.3.1) + use-latest: 1.3.0(@types/react@18.3.18)(react@18.3.1) + transitivePeerDependencies: + - '@types/react' + react-tooltip@5.28.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@floating-ui/dom': 1.6.13 @@ -6332,6 +6388,8 @@ snapshots: dependencies: picomatch: 2.3.1 + regenerator-runtime@0.14.1: {} + regex-recursion@5.1.1: dependencies: regex: 5.1.1 @@ -6872,6 +6930,25 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + use-composed-ref@1.4.0(@types/react@18.3.18)(react@18.3.1): + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + use-isomorphic-layout-effect@1.2.0(@types/react@18.3.18)(react@18.3.1): + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.18 + + use-latest@1.3.0(@types/react@18.3.18)(react@18.3.1): + dependencies: + react: 18.3.1 + use-isomorphic-layout-effect: 1.2.0(@types/react@18.3.18)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.18 + use-sync-external-store@1.4.0(react@18.3.1): dependencies: react: 18.3.1 diff --git a/src/components/GenerateCourse/AICourseFollowUpPopover.tsx b/src/components/GenerateCourse/AICourseFollowUpPopover.tsx index a39097574..41028ec68 100644 --- a/src/components/GenerateCourse/AICourseFollowUpPopover.tsx +++ b/src/components/GenerateCourse/AICourseFollowUpPopover.tsx @@ -19,6 +19,7 @@ import { markdownToHtml } from '../../lib/markdown'; import { cn } from '../../lib/classname'; import { getAiCourseLimitOptions } from '../../queries/ai-course'; import { queryClient } from '../../stores/query-client'; +import TextareaAutosize from 'react-textarea-autosize'; export type AllowedAIChatRole = 'user' | 'assistant'; export type AIChatHistoryType = { @@ -198,11 +199,23 @@ export function AICourseFollowUpPopover(props: AICourseFollowUpPopoverProps) {
{courseAIChatHistory.map((chat, index) => { return ( - + <> + + + {chat.isDefault && ( +
+
+ {capabilities.map((capability, index) => ( + + ))} +
+
+ )} + ); })} @@ -219,7 +232,7 @@ export function AICourseFollowUpPopover(props: AICourseFollowUpPopoverProps) {
{isLimitExceeded && ( @@ -228,17 +241,22 @@ export function AICourseFollowUpPopover(props: AICourseFollowUpPopoverProps) {

You have reached the AI usage limit for today.

)} - setMessage(e.target.value)} autoFocus={true} + onKeyDown={(e) => { + if (e.key === 'Enter' && !e.shiftKey) { + handleChatSubmit(e as unknown as FormEvent); + } + }} /> @@ -285,3 +303,66 @@ function AIChatCard(props: AIChatCardProps) { ); } + +type CapabilityCardProps = { + icon: React.ReactNode; + title: string; + description: string; + className?: string; +}; + +function CapabilityCard({ + icon, + title, + description, + className, +}: CapabilityCardProps) { + return ( +
+
+ {icon} + + {title} + +
+

{description}

+
+ ); +} + +const capabilities = [ + { + icon: ( + + ), + title: 'Clarify Concepts', + description: "If you don't understand a concept, ask me to clarify it", + }, + { + icon: ( + + ), + title: 'More Details', + description: 'Get deeper insights about topics covered in the lesson', + }, + { + icon: ( + + ), + title: 'Code Help', + description: 'Share your code and ask me to help you debug it', + }, + { + icon: , + title: 'Best Practices', + description: 'Share your code and ask me the best way to do something', + }, +] as const;