1
0
mirror of https://github.com/kamranahmedse/developer-roadmap.git synced 2025-09-03 14:22:41 +02:00

Add AI guide

This commit is contained in:
Kamran Ahmed
2025-06-18 16:06:47 +01:00
parent 39ae86ef1c
commit c293d38d88
2 changed files with 37 additions and 45 deletions

View File

@@ -1,20 +1,21 @@
import { useMemo, useState } from 'react';
import { AITutorLayout } from '../AITutor/AITutorLayout';
import { AIGuideContent } from './AIGuideContent';
import { useQuery } from '@tanstack/react-query';
import { ExternalLink } from 'lucide-react';
import { useMemo, useState } from 'react';
import { flushSync } from 'react-dom';
import { generateGuide } from '../../helper/generate-ai-guide';
import { shuffle } from '../../helper/shuffle';
import { useToast } from '../../hooks/use-toast';
import { isLoggedIn } from '../../lib/jwt';
import {
aiGuideSuggestionsOptions,
getAiGuideOptions,
} from '../../queries/ai-guide';
import { queryClient } from '../../stores/query-client';
import { GenerateAIGuide } from './GenerateAIGuide';
import { AIGuideChat } from './AIGuideChat';
import { AITutorLayout } from '../AITutor/AITutorLayout';
import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal';
import { isLoggedIn } from '../../lib/jwt';
import { shuffle } from '../../helper/shuffle';
import { generateGuide } from '../../helper/generate-ai-guide';
import { useToast } from '../../hooks/use-toast';
import { flushSync } from 'react-dom';
import { AIGuideChat } from './AIGuideChat';
import { AIGuideContent } from './AIGuideContent';
import { GenerateAIGuide } from './GenerateAIGuide';
type AIGuideProps = {
guideSlug?: string;
@@ -157,8 +158,8 @@ export function ListSuggestions(props: ListSuggestionsProps) {
const { title, suggestions, depth, isLoading, currentGuideTitle } = props;
return (
<div className="group relative overflow-hidden rounded-xl border border-gray-300 bg-linear-to-br from-gray-100 to-gray-50 shadow-xs transition-all duration-200 hover:shadow-sm">
<div className="border-b border-gray-200/80 bg-white/60 px-5 py-4">
<div className="group relative overflow-hidden rounded-xl border border-gray-300 bg-linear-to-br from-gray-100 to-gray-50 shadow-xs transition-all duration-200">
<div className="border-b border-gray-200 bg-white px-5 py-4">
<h2 className="text-lg font-semibold text-gray-900">{title}</h2>
<p className="mt-1 text-sm text-gray-600">
{depth === 'essentials'
@@ -173,7 +174,7 @@ export function ListSuggestions(props: ListSuggestionsProps) {
{[1, 2].map((i) => (
<div
key={i}
className="h-10 w-full animate-pulse rounded-lg bg-gray-200/70"
className="h-10 w-full animate-pulse rounded-lg bg-white"
></div>
))}
</div>
@@ -198,19 +199,7 @@ export function ListSuggestions(props: ListSuggestionsProps) {
<span className="flex-1 truncate group-hover/item:text-gray-900">
{topic}
</span>
<svg
className="ml-2 h-4 w-4 text-gray-400 transition-colors group-hover/item:text-gray-600"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
/>
</svg>
<ExternalLink className="ml-2 size-4 text-gray-400 group-hover/item:text-gray-600" />
</a>
);
})}

View File

@@ -3,10 +3,11 @@ import { useChat, type ChatMessage } from '../../hooks/use-chat';
import { RoadmapAIChatCard } from '../RoadmapAIChat/RoadmapAIChatCard';
import {
ArrowDownIcon,
BotIcon, LockIcon,
BotIcon,
LockIcon,
PauseCircleIcon,
SendIcon,
Trash2Icon
Trash2Icon,
} from 'lucide-react';
import { ChatHeaderButton } from '../FrameRenderer/RoadmapFloatingChat';
import { isLoggedIn } from '../../lib/jwt';
@@ -153,7 +154,7 @@ export function AIGuideChat(props: AIGuideChatProps) {
</div>
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center">
<div className="absolute bg-gray-100 inset-0 flex items-center justify-center">
<LoadingChip message="Loading..." />
</div>
)}
@@ -170,11 +171,11 @@ export function AIGuideChat(props: AIGuideChatProps) {
isIntro
/>
{isQuestionsLoading && (
<div className="flex flex-col gap-1">
<div className="flex flex-col gap-2">
{[1, 2, 3, 4].map((i) => (
<div
key={i}
className="h-[38px] w-full animate-pulse rounded-lg bg-gray-200"
className="h-[48px] w-full animate-pulse rounded-lg bg-gray-200"
></div>
))}
</div>
@@ -183,24 +184,26 @@ export function AIGuideChat(props: AIGuideChatProps) {
randomQuestions &&
randomQuestions.length > 0 &&
messages.length === 0 && (
<>
<ul className="flex flex-col gap-1">
<div className="space-y-2">
<p className="mb-2 text-xs font-normal text-gray-500">
Some questions you might have about this lesson.
</p>
<div className="space-y-1">
{randomQuestions?.map((question) => {
return (
<li key={`chat-${question}`}>
<button
className="w-fit rounded-lg border border-gray-200 bg-white p-2 text-left text-sm text-balance hover:bg-white/40"
onClick={() => {
handleSubmitInput(question);
}}
>
<p className="text-gray-500">{question}</p>
</button>
</li>
<button
key={`chat-${question}`}
className="flex h-full self-start rounded-md bg-yellow-500/10 px-3 py-2 text-left text-sm text-black hover:bg-yellow-500/20"
onClick={() => {
handleSubmitInput(question);
}}
>
{question}
</button>
);
})}
</ul>
</>
</div>
</div>
)}
{messages.map((chat, index) => {