mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2026-03-12 17:51:53 +08:00
feat: add topic guides
This commit is contained in:
@@ -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>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -9,6 +9,7 @@ export interface RoadmapTreeDocument {
|
||||
nodeId: string;
|
||||
text: string;
|
||||
subjects: string[];
|
||||
guides?: string[];
|
||||
}[];
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
Reference in New Issue
Block a user