From 1087e1a935e03c88d13b15b306ae882788eff926 Mon Sep 17 00:00:00 2001 From: Kamran Ahmed Date: Sat, 3 Aug 2024 01:34:59 +0100 Subject: [PATCH] feat: redesign roadmap page header and add upcoming projects functionality (#6347) * Redesign the header * Responsiveness of the roadmap header * Fix spacing * Redesign roadmap header * Add projects badge * Update badge * Add screen for projects * UI flicker fix * Add question for system design * Code formatting --- src/components/DownloadRoadmapButton.tsx | 40 +++ .../EditorRoadmap/EditorRoadmap.tsx | 5 +- src/components/FeaturedItems/MarkFavorite.tsx | 2 +- .../FrameRenderer/FrameRenderer.astro | 10 +- src/components/Projects/EmptyProjects.tsx | 60 +++++ src/components/ResourceProgressStats.astro | 52 +--- src/components/RoadmapHeader.astro | 228 +++++++----------- src/components/RoadmapHint.astro | 39 +-- src/components/RoadmapTitleQuestion.tsx | 24 +- src/components/ShareRoadmapButton.tsx | 2 +- src/components/TabLink.tsx | 69 ++++++ .../roadmaps/system-design/system-design.md | 8 + src/lib/resource-progress.ts | 6 +- src/pages/[roadmapId]/index.astro | 100 ++++---- src/pages/[roadmapId]/projects.astro | 84 +++++++ src/styles/global.css | 4 + 16 files changed, 447 insertions(+), 286 deletions(-) create mode 100644 src/components/DownloadRoadmapButton.tsx create mode 100644 src/components/Projects/EmptyProjects.tsx create mode 100644 src/components/TabLink.tsx create mode 100644 src/pages/[roadmapId]/projects.astro diff --git a/src/components/DownloadRoadmapButton.tsx b/src/components/DownloadRoadmapButton.tsx new file mode 100644 index 000000000..aab83d4e7 --- /dev/null +++ b/src/components/DownloadRoadmapButton.tsx @@ -0,0 +1,40 @@ +import { Download } from 'lucide-react'; +import { isLoggedIn } from '../lib/jwt.ts'; +import { useEffect, useState } from 'react'; +import { showLoginPopup } from '../lib/popup.ts'; + +type DownloadRoadmapButtonProps = { + roadmapId: string; +}; + +export function DownloadRoadmapButton(props: DownloadRoadmapButtonProps) { + const { roadmapId } = props; + + const [url, setUrl] = useState('#'); + + useEffect(() => { + if (isLoggedIn()) { + setUrl(`/pdfs/roadmaps/${roadmapId}.pdf`); + } + }, []); + + return ( + { + if (isLoggedIn()) { + return; + } + + e.preventDefault(); + showLoginPopup(); + }} + > + + Download + + ); +} diff --git a/src/components/EditorRoadmap/EditorRoadmap.tsx b/src/components/EditorRoadmap/EditorRoadmap.tsx index b74d7af57..babb6b664 100644 --- a/src/components/EditorRoadmap/EditorRoadmap.tsx +++ b/src/components/EditorRoadmap/EditorRoadmap.tsx @@ -68,14 +68,13 @@ export function EditorRoadmap(props: EditorRoadmapProps) { : undefined } className={ - 'flex aspect-[var(--aspect-ratio)] w-full flex-col justify-center' + 'mt-5 flex aspect-[var(--aspect-ratio)] w-full flex-col justify-center' } >
diff --git a/src/components/FeaturedItems/MarkFavorite.tsx b/src/components/FeaturedItems/MarkFavorite.tsx index 504a8ecfd..3d6191c31 100644 --- a/src/components/FeaturedItems/MarkFavorite.tsx +++ b/src/components/FeaturedItems/MarkFavorite.tsx @@ -103,7 +103,7 @@ export function MarkFavorite({ className || 'absolute right-1.5 top-1.5 z-30 focus:outline-0' }`} > - {isLoading ? : } + {isLoading ? : } ); } diff --git a/src/components/FrameRenderer/FrameRenderer.astro b/src/components/FrameRenderer/FrameRenderer.astro index 620143da5..d76411d3c 100644 --- a/src/components/FrameRenderer/FrameRenderer.astro +++ b/src/components/FrameRenderer/FrameRenderer.astro @@ -1,7 +1,8 @@ --- import Loader from '../Loader.astro'; import './FrameRenderer.css'; -import { ProgressNudge } from "./ProgressNudge"; +import { Spinner } from '../ReactIcons/Spinner'; +import { ProgressNudge } from './ProgressNudge'; export interface Props { resourceType: 'roadmap' | 'best-practice'; @@ -16,6 +17,7 @@ const { resourceId, resourceType, dimensions = null } = Astro.props; ---
- + diff --git a/src/components/Projects/EmptyProjects.tsx b/src/components/Projects/EmptyProjects.tsx new file mode 100644 index 000000000..9a28bfc7b --- /dev/null +++ b/src/components/Projects/EmptyProjects.tsx @@ -0,0 +1,60 @@ +import { Bell, Check, FolderKanbanIcon } from 'lucide-react'; +import { useEffect, useState } from 'react'; +import { cn } from '../../lib/classname.ts'; +import { Spinner } from '../ReactIcons/Spinner.tsx'; +import { isLoggedIn } from '../../lib/jwt.ts'; +import { showLoginPopup } from '../../lib/popup.ts'; + +export function EmptyProjects() { + const [isSubscribed, setIsSubscribed] = useState(false); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + setIsSubscribed(isLoggedIn()); + setIsLoading(false); + }, []); + + return ( +
+ +

+ Projects are coming soon! + Coming soon! +

+

+ Sign up to get notified when projects are available. +

+ + +
+ ); +} diff --git a/src/components/ResourceProgressStats.astro b/src/components/ResourceProgressStats.astro index 529f3f776..a594bac5d 100644 --- a/src/components/ResourceProgressStats.astro +++ b/src/components/ResourceProgressStats.astro @@ -5,20 +5,15 @@ import { ProgressShareButton } from './UserProgress/ProgressShareButton'; export interface Props { resourceId: string; resourceType: ResourceType; - hasSecondaryBanner?: boolean; } -const { hasSecondaryBanner = false, resourceId, resourceType } = Astro.props; +const { resourceId, resourceType } = Astro.props; ---

0% Done - - + 0 of 0 Done

@@ -55,11 +38,11 @@ const { hasSecondaryBanner = false, resourceId, resourceType } = Astro.props;
- -
- - 0 of 0 Done - - -
- -
-
diff --git a/src/components/RoadmapHeader.astro b/src/components/RoadmapHeader.astro index afa13f165..76972b53b 100644 --- a/src/components/RoadmapHeader.astro +++ b/src/components/RoadmapHeader.astro @@ -1,17 +1,17 @@ --- -import Icon from './AstroIcon.astro'; +import { + ArrowLeftIcon, + FolderKanbanIcon, + MapIcon, + MessageCircle, +} from 'lucide-react'; +import { TabLink } from './TabLink'; import LoginPopup from './AuthenticationFlow/LoginPopup.astro'; -import RoadmapHint from './RoadmapHint.astro'; -import RoadmapNote from './RoadmapNote.astro'; -import TopicSearch from './TopicSearch/TopicSearch.astro'; -import YouTubeAlert from './YouTubeAlert.astro'; import ProgressHelpPopup from './ProgressHelpPopup.astro'; import { MarkFavorite } from './FeaturedItems/MarkFavorite'; -import { CreateVersion } from './CreateVersion/CreateVersion'; import { type RoadmapFrontmatter } from '../lib/roadmap'; import { ShareRoadmapButton } from './ShareRoadmapButton'; -import { Share2 } from 'lucide-react'; -import ShareIcons from './ShareIcons/ShareIcons.astro'; +import { DownloadRoadmapButton } from './DownloadRoadmapButton'; export interface Props { title: string; @@ -24,6 +24,7 @@ export interface Props { question?: RoadmapFrontmatter['question']; hasTopics?: boolean; isForkable?: boolean; + activeTab?: 'roadmap' | 'projects'; } const { @@ -32,15 +33,12 @@ const { roadmapId, tnsBannerLink, isUpcoming = false, - hasSearch = false, note, hasTopics = false, question, - isForkable = false, + activeTab = 'roadmap', } = Astro.props; -const isRoadmapReady = !isUpcoming; - const roadmapTitle = roadmapId === 'devops' ? 'DevOps' @@ -52,137 +50,11 @@ const hasTnsBanner = !!tnsBannerLink; -
-
-
- { - isForkable && ( -
- -
- ) - } - -

- {title} - - - -

-

{description}

-
- -
-
- { - !hasSearch && ( - <> - - ← - - - - - {isRoadmapReady && ( - <> - - - - - )} - - ) - } - - { - hasSearch && ( - - ← -  Visual Roadmap - - ) - } -
- -
- { - isRoadmapReady && ( - - - - Suggest - - ) - } -
-
- - - { - hasTopics && ( - - ) - } - - {hasSearch && } -
- +
{ tnsBannerLink && ( - -{note && } +
+ +
+

+ {title} +

+

+ {description} +

+
+ +
+
+ + +
+ + +
+
+
diff --git a/src/components/RoadmapHint.astro b/src/components/RoadmapHint.astro index e0964d3bb..8b38bb097 100644 --- a/src/components/RoadmapHint.astro +++ b/src/components/RoadmapHint.astro @@ -1,7 +1,6 @@ --- import AstroIcon from './AstroIcon.astro'; import Icon from './AstroIcon.astro'; -import { RoadmapTitleQuestion } from './RoadmapTitleQuestion.tsx'; import ResourceProgressStats from './ResourceProgressStats.astro'; export interface Props { @@ -11,47 +10,13 @@ export interface Props { titleAnswer?: string; } -const { - roadmapId, - titleQuestion = '', - titleAnswer = '', - tnsBannerLink, -} = Astro.props; -const hasTitleQuestion = titleQuestion && titleAnswer; +const { roadmapId, tnsBannerLink } = Astro.props; const hasTnsBanner = !!tnsBannerLink; --- -
+
- - { - hasTitleQuestion && ( - - ) - }
diff --git a/src/components/RoadmapTitleQuestion.tsx b/src/components/RoadmapTitleQuestion.tsx index 4188ed2d5..fc14bb0e2 100644 --- a/src/components/RoadmapTitleQuestion.tsx +++ b/src/components/RoadmapTitleQuestion.tsx @@ -1,4 +1,10 @@ -import { ChevronDown, ChevronUp, GraduationCap } from 'lucide-react'; +import { + ChevronDown, + ChevronUp, + CircleHelp, + GraduationCap, + Info, +} from 'lucide-react'; import { useRef, useState } from 'react'; import { useOutsideClick } from '../hooks/use-outside-click'; import { markdownToHtml } from '../lib/markdown'; @@ -19,23 +25,23 @@ export function RoadmapTitleQuestion(props: RoadmapTitleQuestionProps) { }); return ( -
+
{isAnswerVisible && (
)}

{ e.preventDefault(); setIsAnswerVisible(!isAnswerVisible); }} > - - + + {question} - +

@@ -48,14 +54,14 @@ export function RoadmapTitleQuestion(props: RoadmapTitleQuestionProps) { > {isAnswerVisible && (

setIsAnswerVisible(false)} > - + {question} - +

diff --git a/src/components/ShareRoadmapButton.tsx b/src/components/ShareRoadmapButton.tsx index f16e11e2d..1df842caf 100644 --- a/src/components/ShareRoadmapButton.tsx +++ b/src/components/ShareRoadmapButton.tsx @@ -70,7 +70,7 @@ export function ShareRoadmapButton(props: ShareRoadmapButtonProps) { {isDropdownOpen && ( -
+