diff --git a/.astro/types.d.ts b/.astro/types.d.ts index 03d7cc43f..f964fe0cf 100644 --- a/.astro/types.d.ts +++ b/.astro/types.d.ts @@ -1,2 +1 @@ /// -/// \ No newline at end of file diff --git a/src/components/AITutor/AITutorSidebar.tsx b/src/components/AITutor/AITutorSidebar.tsx index 7182a8502..809161aa0 100644 --- a/src/components/AITutor/AITutorSidebar.tsx +++ b/src/components/AITutor/AITutorSidebar.tsx @@ -1,26 +1,29 @@ +import { useQuery } from '@tanstack/react-query'; import { BookOpen, + ChevronDown, + ChevronRight, Compass, + FileText, Map, MessageCircle, - Plus, Star, Swords, X, + Zap } from 'lucide-react'; import { useEffect, useState } from 'react'; -import { isLoggedIn } from '../../lib/jwt'; -import { useIsPaidUser } from '../../queries/billing'; -import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal'; -import { AITutorLogo } from '../ReactIcons/AITutorLogo'; -import { queryClient } from '../../stores/query-client'; -import { aiLimitOptions } from '../../queries/ai-course'; -import { useQuery } from '@tanstack/react-query'; -import { getPercentage } from '../../lib/number'; -import { AILimitsPopup } from '../GenerateCourse/AILimitsPopup'; +import { getUrlParams } from '../../lib/browser'; import { cn } from '../../lib/classname'; -import { UserDropdown } from './UserDropdown'; +import { isLoggedIn } from '../../lib/jwt'; +import { aiLimitOptions } from '../../queries/ai-course'; +import { useIsPaidUser } from '../../queries/billing'; +import { queryClient } from '../../stores/query-client'; +import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal'; +import { AILimitsPopup } from '../GenerateCourse/AILimitsPopup'; +import { AITutorLogo } from '../ReactIcons/AITutorLogo'; import { UpgradeSidebarCard } from './UpgradeSidebarCard'; +import { UserDropdown } from './UserDropdown'; type AITutorSidebarProps = { isFloating: boolean; @@ -33,13 +36,33 @@ const sidebarItems = [ key: 'new', label: 'Create with AI', href: '/ai', - icon: Plus, - }, - { - key: 'quiz', - label: 'Test my Skills', - href: '/ai/quiz', - icon: Swords, + icon: Zap, + children: [ + { + key: 'create-course', + label: 'Course', + href: '/ai?format=course', + icon: BookOpen, + }, + { + key: 'create-guide', + label: 'Guide', + href: '/ai?format=guide', + icon: FileText, + }, + { + key: 'create-roadmap', + label: 'Roadmap', + href: '/ai?format=roadmap', + icon: Map, + }, + { + key: 'quiz', + label: 'Quiz', + href: '/ai/quiz', + icon: Swords, + }, + ], }, { key: 'chat', @@ -78,7 +101,11 @@ export type AITutorTab = (typeof sidebarItems)[number]['key']; export function AITutorSidebar(props: AITutorSidebarProps) { const { activeTab, isFloating, onClose } = props; + const [format, setFormat] = useState(''); const [isInitialLoad, setIsInitialLoad] = useState(true); + const [expandedItems, setExpandedItems] = useState>({ + new: true, // Keep "Create with AI" expanded by default + }); const [showAILimitsPopup, setShowAILimitsPopup] = useState(false); const [isUpgradeModalOpen, setIsUpgradeModalOpen] = useState(false); @@ -89,15 +116,21 @@ export function AITutorSidebar(props: AITutorSidebarProps) { queryClient, ); - const { used, limit } = limits ?? { used: 0, limit: 0 }; - const totalPercentage = getPercentage(used, limit); - useEffect(() => { + const { format } = getUrlParams(); + setFormat(format || 'course'); setIsInitialLoad(false); }, []); const isLoading = isPaidUserLoading || isLimitsLoading; + const toggleExpanded = (key: string) => { + setExpandedItems((prev) => ({ + ...prev, + [key]: !prev[key], + })); + }; + return ( <> {isUpgradeModalOpen && ( @@ -156,7 +189,27 @@ export function AITutorSidebar(props: AITutorSidebarProps) { toggleExpanded(item.key)} /> + {item.children && expandedItems[item.key] && ( +
    +
    + {item.children.map((child) => ( +
  • + +
  • + ))} +
+ )} ))} @@ -179,35 +232,83 @@ export function AITutorSidebar(props: AITutorSidebarProps) { ); } +type SidebarItem = { + key: string; + label: string; + href: string; + icon: any; + children?: { + key: string; + label: string; + href: string; + icon: any; + }[]; +}; + +type ChildItem = { + key: string; + label: string; + href: string; + icon: any; +}; + type AITutorSidebarItemProps = { - item: (typeof sidebarItems)[number]; + item: SidebarItem | ChildItem; as?: 'a' | 'button'; onClick?: () => void; className?: string; isActive?: boolean; + isExpanded?: boolean; + onToggleExpanded?: () => void; + isChild?: boolean; }; function AITutorSidebarItem(props: AITutorSidebarItemProps) { - const { item, as = 'a', onClick, className, isActive } = props; + const { + item, + as = 'a', + onClick, + className, + isActive, + isExpanded, + onToggleExpanded, + isChild, + } = props; - const Component = as; + const hasChildren = 'children' in item && item.children; + const Component = hasChildren ? 'button' : as; return ( - + {!isChild && } {item.label} + {hasChildren && ( + + {isExpanded ? ( + + ) : ( + + )} + + )} ); } diff --git a/src/components/ContentGenerator/ContentGenerator.tsx b/src/components/ContentGenerator/ContentGenerator.tsx index a1e3388c0..e546f68f9 100644 --- a/src/components/ContentGenerator/ContentGenerator.tsx +++ b/src/components/ContentGenerator/ContentGenerator.tsx @@ -21,7 +21,7 @@ import { } from './QuestionAnswerChat'; import { useToast } from '../../hooks/use-toast'; import { cn } from '../../lib/classname'; -import { getUrlParams } from '../../lib/browser'; +import { getUrlParams, setUrlParams } from '../../lib/browser'; import { useParams } from '../../hooks/use-params'; import { useQuery } from '@tanstack/react-query'; import { aiLimitOptions } from '../../queries/ai-course'; @@ -205,7 +205,10 @@ export function ContentGenerator() { setSelectedFormat(format.value)} + onClick={() => { + setSelectedFormat(format.value); + setUrlParams({ format: format.value }); + }} icon={format.icon} isSelected={isSelected} /> diff --git a/src/components/Premium/FeatureCard.tsx b/src/components/Premium/FeatureCard.tsx index 0b3c4fbcf..9e7d84a77 100644 --- a/src/components/Premium/FeatureCard.tsx +++ b/src/components/Premium/FeatureCard.tsx @@ -1,4 +1,5 @@ import { Lock, Play } from 'lucide-react'; +import { markdownToHtml } from '../../lib/markdown'; interface FeatureCardProps { title: string; @@ -42,29 +43,32 @@ export function FeatureCard(props: FeatureCardProps) { } return ( - {duration}

{title}

-

{description}

+

- + ); -} \ No newline at end of file +} diff --git a/src/components/Premium/PremiumPage.tsx b/src/components/Premium/PremiumPage.tsx index 554dd6d5b..d789b31db 100644 --- a/src/components/Premium/PremiumPage.tsx +++ b/src/components/Premium/PremiumPage.tsx @@ -3,6 +3,7 @@ import { Bot, CheckCircle, Clock, + MousePointerClick, PartyPopper, Users2, Wand2, @@ -161,10 +162,10 @@ export function PremiumPage() { Generate unlimited courses about any topic, get career guidance and instant answers from AI, test your skills and more

-
+
Upgrade now @@ -179,6 +180,21 @@ export function PremiumPage() { +

diff --git a/src/components/Premium/constants.ts b/src/components/Premium/constants.ts index 5ceef515a..d8df930b7 100644 --- a/src/components/Premium/constants.ts +++ b/src/components/Premium/constants.ts @@ -10,18 +10,10 @@ export const paidFeaturesList = [ ]; export const features = [ - { - title: 'Chat with Roadmaps', - description: - 'Ask questions and get instant answers on any roadmap through AI', - videoId: 'fq0UgNcj3Ek', - thumbnail: 'https://assets.roadmap.sh/guest/chat-with-roadmaps-ew2l9.png', - duration: '2:17', - }, { title: 'Unlimited AI Courses', description: - 'No more paying for expensive courses, create unlimited courses with AI', + 'No more paying for expensive courses, [create unlimited courses](/ai) with AI', videoId: 'uCcQNhdVUVQ', thumbnail: 'https://assets.roadmap.sh/guest/ai-courses-m07ra.png', duration: '3:07', @@ -29,15 +21,32 @@ export const features = [ { title: 'In-depth Guides', description: - 'Create unlimited personalized in-depth learning guides with AI', + 'Create unlimited personalized [in-depth learning guides](/ai?format=guide) with AI', videoId: '5kwYjCg2Lu4', thumbnail: 'https://assets.roadmap.sh/guest/ai-guides-s4bjj.png', duration: '1:33', }, + { + title: 'Learn Roadmap Topics', + description: + 'Learn [roadmap topics directly](/backend) from within the nodes without leaving the roadmap', + videoId: '0jZ1Lse1Y3E', + thumbnail: 'https://assets.roadmap.sh/guest/smarter-roadmaps-f46ku.png', + duration: '3:11', + startTime: '5', + }, + { + title: 'Chat with Roadmaps', + description: + 'Ask questions and [get instant answers](/frontend) on any roadmap through AI', + videoId: 'fq0UgNcj3Ek', + thumbnail: 'https://assets.roadmap.sh/guest/chat-with-roadmaps-ew2l9.png', + duration: '2:17', + }, { title: 'AI as Learning Companion', description: - 'Use AI-powered learning companion to accelerate your roadmap progress', + 'Use [AI-powered learning companion](/ai/roadmap-chat) to accelerate your roadmap progress', videoId: 'Jso_HRviEOE', thumbnail: 'https://assets.roadmap.sh/guest/roadmap-ai-tools-adhqq.png', duration: '2:45', @@ -46,24 +55,16 @@ export const features = [ { title: 'Your Personal Coach', description: - 'Get career guidance, roadmap and personalized growth suggestions', + 'Get career guidance, personalized growth suggestions using [AI Tutor Chat](/ai/chat)', videoId: '77VwAeFmoIw', thumbnail: 'https://assets.roadmap.sh/guest/career-guidance-t2mpu.png', duration: '3:45', startTime: '4', }, - { - title: 'Learn Roadmap Topics', - description: - 'Learn roadmap topics directly from within the nodes without leaving the roadmap', - videoId: '0jZ1Lse1Y3E', - thumbnail: 'https://assets.roadmap.sh/guest/smarter-roadmaps-f46ku.png', - duration: '3:11', - startTime: '5' - }, { title: 'Test Yourself', - description: 'Test your knowledge and prepare for interviews with AI', + description: + 'Let AI help you [test your knowledge](/ai/quiz) and prepare for interviews', videoId: 'ScruGC8uzjo', thumbnail: 'https://assets.roadmap.sh/guest/test-yourself-uwzqo.png', duration: '2:15', @@ -71,7 +72,7 @@ export const features = [ { title: 'Powerful Roadmap Editor', description: - 'Create and edit roadmaps with ease using our powerful roadmap editor', + '[Create and edit roadmaps](/account/roadmaps) with ease using our powerful roadmap editor', videoId: 'L2HZIHIgwOI', thumbnail: 'https://assets.roadmap.sh/guest/ai-based-roadmap-editor-ochm8.png', @@ -83,4 +84,4 @@ export const features = [ 'We have more amazing features coming soon! Be the first to try them out!', isComingSoon: true, }, -]; \ No newline at end of file +];