feat: add topic guides

This commit is contained in:
Arik Chakma
2025-09-10 18:47:40 +06:00
parent 080e843a04
commit c9db98f025
3 changed files with 87 additions and 15 deletions

View File

@@ -21,7 +21,17 @@ import type {
RoadmapContentDocument,
} from '../CustomRoadmap/CustomRoadmap';
import { markdownToHtml, sanitizeMarkdown } from '../../lib/markdown';
import { Ban, BookOpen, FileText, HeartHandshake, Star, X } from 'lucide-react';
import {
Ban,
BookOpen,
BookOpenIcon,
BotIcon,
FileText,
FileTextIcon,
HeartHandshake,
Star,
X,
} from 'lucide-react';
import { getUrlParams, parseUrl } from '../../lib/browser';
import { Spinner } from '../ReactIcons/Spinner';
import { GitHubIcon } from '../ReactIcons/GitHubIcon.tsx';
@@ -434,7 +444,9 @@ export function TopicDetail(props: TopicDetailProps) {
const shouldShowAiTab = !isCustomResource && resourceType === 'roadmap';
const subjects = roadmapTreeMapping?.subjects || [];
const guides = roadmapTreeMapping?.guides || [];
const hasSubjects = subjects.length > 0;
const hasGuides = guides.length > 0;
const hasDataCampResources = paidResources.some((resource) =>
resource.title.toLowerCase().includes('datacamp'),
@@ -649,12 +661,12 @@ export function TopicDetail(props: TopicDetailProps) {
</>
)}
{hasSubjects && (
{(hasSubjects || hasGuides) && (
<>
<ResourceListSeparator
text="AI Tutor Courses"
text="AI Tutor"
className="text-blue-600"
icon={BookOpen}
icon={BotIcon}
/>
<ul className="mt-4 ml-3 flex flex-wrap gap-1 text-sm">
{subjects.map((subject) => {
@@ -677,13 +689,42 @@ export function TopicDetail(props: TopicDetailProps) {
}
}}
href={`/ai/course/search?term=${subject}&src=topic`}
className="flex items-center gap-1 rounded-md border border-gray-300 bg-gray-100 px-2 py-1 hover:bg-gray-200 hover:text-black"
className="flex items-center gap-1.5 rounded-md border border-gray-300 bg-gray-100 px-2 py-1 hover:bg-gray-200 hover:text-black"
>
<BookOpenIcon className="size-3.5" />
{subject}
</a>
</li>
);
})}
{guides.map((guide) => {
return (
<li key={guide}>
<a
key={guide}
target="_blank"
onClick={(e) => {
if (!isLoggedIn()) {
e.preventDefault();
showLoginPopup();
return;
}
if (isLimitExceeded && !isPaidUser) {
e.preventDefault();
setShowUpgradeModal(true);
return;
}
}}
href={`/ai/guide/search?term=${guide}&src=topic`}
className="flex items-center gap-1.5 rounded-md border border-gray-300 bg-gray-100 px-2 py-1 hover:bg-gray-200 hover:text-black"
>
<FileTextIcon className="size-3.5" />
{guide}
</a>
</li>
);
})}
</ul>
</>
)}

View File

@@ -2,8 +2,10 @@ import '../ChatMessages/AIChat.css';
import { useQuery } from '@tanstack/react-query';
import {
BookOpenIcon,
BotIcon,
ChevronRightIcon,
FileTextIcon,
Gift,
Loader2Icon,
LockIcon,
@@ -149,10 +151,11 @@ export function TopicDetailAI(props: TopicDetailAIProps) {
);
const hasChatHistory = messages.length > 0;
const nodeTextParts = roadmapTreeMapping?.text?.split('>') || [];
const hasSubjects =
(roadmapTreeMapping?.subjects &&
roadmapTreeMapping?.subjects?.length > 0) ||
nodeTextParts.length > 1;
const subjects = roadmapTreeMapping?.subjects || [];
const guides = roadmapTreeMapping?.guides || [];
const hasGuides = guides.length > 0;
const hasSubjects = subjects.length > 0 || nodeTextParts.length > 1;
return (
<div className="ai-chat relative mt-4 flex grow flex-col overflow-hidden rounded-lg border border-gray-200">
@@ -172,14 +175,14 @@ export function TopicDetailAI(props: TopicDetailAIProps) {
/>
)}
{hasSubjects && (
{(hasSubjects || hasGuides) && (
<div className="border-b border-gray-200 p-3">
<h4 className="flex items-center gap-2 text-sm">
Complete the following AI Tutor courses
Complete the following AI Tutor courses or guides
</h4>
<div className="mt-2.5 flex flex-wrap gap-1 text-sm">
{roadmapTreeMapping?.subjects?.map((subject) => {
{subjects.map((subject) => {
return (
<a
key={subject}
@@ -197,15 +200,42 @@ export function TopicDetailAI(props: TopicDetailAIProps) {
return;
}
}}
href={`/ai/course/search?term=${subject}&difficulty=beginner&src=topic`}
className="flex items-center gap-1 rounded-md border border-gray-300 bg-gray-100 px-2 py-1 hover:bg-gray-200 hover:text-black"
href={`/ai/course/search?term=${subject}&src=topic`}
className="flex items-center gap-1.5 rounded-md border border-gray-300 bg-gray-100 px-2 py-1 hover:bg-gray-200 hover:text-black"
>
<BookOpenIcon className="size-3.5" />
{subject}
</a>
);
})}
{guides.map((guide) => {
return (
<a
key={guide}
target="_blank"
onClick={(e) => {
if (!isLoggedIn()) {
e.preventDefault();
onLogin();
return;
}
{roadmapTreeMapping?.subjects?.length === 0 && (
if (isLimitExceeded) {
e.preventDefault();
onUpgrade();
return;
}
}}
href={`/ai/guide/search?term=${guide}&src=topic`}
className="flex items-center gap-1.5 rounded-md border border-gray-300 bg-gray-100 px-2 py-1 hover:bg-gray-200 hover:text-black"
>
<FileTextIcon className="size-3.5" />
{guide}
</a>
);
})}
{subjects.length === 0 && (
<a
target="_blank"
onClick={(e) => {

View File

@@ -9,6 +9,7 @@ export interface RoadmapTreeDocument {
nodeId: string;
text: string;
subjects: string[];
guides?: string[];
}[];
createdAt: Date;
updatedAt: Date;