mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-08-31 21:11:44 +02:00
Purchase banner
This commit is contained in:
@@ -1,33 +1,85 @@
|
||||
import { CheckIcon, Star } from 'lucide-react';
|
||||
import { BuyButton } from './BuyButton';
|
||||
import { Rating } from '../Rating/Rating';
|
||||
import { cn } from '../../lib/classname';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
export function PurchaseBanner() {
|
||||
return (
|
||||
<div className="sticky top-4 z-50 mt-16.5 flex w-full flex-col gap-4 rounded-2xl bg-yellow-950 p-5 shadow-lg ring-1 ring-yellow-500/40 lg:flex-row lg:items-center lg:justify-between">
|
||||
<div className="order-3 flex w-full flex-col items-center gap-2 lg:order-0 lg:w-fit lg:items-start">
|
||||
{[
|
||||
'7-Day Money-Back Guarantee',
|
||||
'Lifetime access & updates'
|
||||
].map((text, index) => (
|
||||
<span key={index} className="inline-flex items-center gap-1.5 text-yellow-500">
|
||||
<CheckIcon className="size-5 stroke-[2.5]" />
|
||||
{text}
|
||||
const bannerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [isOutOfView, setIsOutOfView] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
if (!bannerRef.current) return;
|
||||
|
||||
const bannerRect = bannerRef.current.getBoundingClientRect();
|
||||
const bannerBottom = bannerRect.bottom;
|
||||
|
||||
// Banner is out of view when its bottom is above the viewport
|
||||
setIsOutOfView(bannerBottom < 0);
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
handleScroll(); // Check initial state
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const Banner = (props: {
|
||||
className?: string;
|
||||
ref?: React.RefObject<HTMLDivElement | null>;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
ref={props.ref}
|
||||
className={cn(
|
||||
'top-4 z-50 mt-16.5 flex w-full flex-col gap-4 rounded-2xl bg-yellow-950 p-5 shadow-lg ring-1 ring-yellow-500/40 lg:sticky lg:flex-row lg:items-center lg:justify-between',
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
<div className="order-3 flex w-full flex-col items-center gap-2 lg:order-0 lg:w-fit lg:items-start">
|
||||
{['7-Day Money-Back Guarantee', 'Lifetime access & updates'].map(
|
||||
(text, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className="inline-flex items-center gap-1.5 text-yellow-500"
|
||||
>
|
||||
<CheckIcon className="size-5 stroke-[2.5]" />
|
||||
{text}
|
||||
</span>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="order-2 lg:order-0">
|
||||
<BuyButton
|
||||
variant="floating"
|
||||
floatingClassName="translate-x-0 lg:-translate-x-5"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Rating rating={4.9} className="hidden lg:flex" />
|
||||
<span className="flex items-center gap-1 text-base font-semibold text-yellow-500">
|
||||
<Star className="block size-4 fill-current lg:hidden" />
|
||||
4.9 avg. Review
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="order-2 lg:order-0">
|
||||
<BuyButton variant="floating" floatingClassName="translate-x-0 lg:-translate-x-5" />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Rating rating={4.9} className="hidden lg:flex" />
|
||||
<span className="text-base font-semibold text-yellow-500 flex items-center gap-1">
|
||||
<Star className="size-4 block lg:hidden fill-current" />
|
||||
4.9 avg. Review
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Banner ref={bannerRef} />
|
||||
<Banner
|
||||
className={cn(
|
||||
'fixed top-[unset] right-0 bottom-0 left-0 rounded-none lg:hidden',
|
||||
isOutOfView ? 'flex' : 'hidden',
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@@ -1,7 +1,8 @@
|
||||
import {
|
||||
BrainIcon,
|
||||
CodeIcon,
|
||||
FileQuestionIcon, NotebookTextIcon
|
||||
FileQuestionIcon,
|
||||
NotebookTextIcon,
|
||||
} from 'lucide-react';
|
||||
import { Spotlight } from '../SQLCourse/Spotlight';
|
||||
import { RoadmapLogoIcon } from '../ReactIcons/RoadmapLogo';
|
||||
@@ -19,105 +20,106 @@ import { sqlCourseChapters } from '../SQLCourse/SQLCoursePage';
|
||||
|
||||
export function SQLCourseVariantPage() {
|
||||
return (
|
||||
<>
|
||||
<div className="relative flex grow flex-col items-center bg-linear-to-b from-zinc-900 to-zinc-950 px-4 pt-3 pb-52 text-zinc-400 md:px-10 md:pt-8">
|
||||
<div className="mx-auto mt-7 w-full max-w-5xl md:mt-20">
|
||||
<div className="relative">
|
||||
<Spotlight className="top-[-200px] left-[-170px]" fill="#EAB308" />
|
||||
<div className="relative flex grow flex-col items-center bg-linear-to-b from-zinc-900 to-zinc-950 px-4 pt-3 pb-52 text-zinc-400 md:px-10 md:pt-8">
|
||||
<div className="mx-auto mt-7 w-full max-w-5xl md:mt-20">
|
||||
<div className="relative">
|
||||
<Spotlight className="top-[-200px] left-[-170px]" fill="#EAB308" />
|
||||
|
||||
<div className="flex flex-col gap-7 sm:flex-row sm:items-center">
|
||||
<a
|
||||
href="https://roadmap.sh"
|
||||
target="_blank"
|
||||
className="transition-opacity hover:opacity-100"
|
||||
>
|
||||
<RoadmapLogoIcon className="size-12 sm:size-22" />
|
||||
</a>
|
||||
<div className="flex flex-col items-start gap-2.5">
|
||||
<h1 className="text-3xl font-bold tracking-tight text-white sm:text-4xl md:text-6xl">
|
||||
Master SQL Queries
|
||||
</h1>
|
||||
<p className="text-left text-balance text-xl text-zinc-300 md:text-2xl">
|
||||
Complete course with AI Tutor, real-world challenges and more
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="my-5 text-xl leading-relaxed text-zinc-300 md:my-14 lg:text-xl">
|
||||
Get certified for SQL queries and ready to deploy your
|
||||
newly-gained skill in 30 days. Perfect for developers, data
|
||||
analysts, and anyone working with data. Level up risk-free with a
|
||||
7-day money-back guarantee.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col-reverse gap-7 lg:gap-14 lg:flex-row">
|
||||
<div className="w-full shrink-0 flex-row-reverse items-start justify-between gap-3 text-lg md:flex lg:w-auto lg:flex-col">
|
||||
<div className="flex flex-col gap-2 lg:gap-4 mb-7 lg:mb-0">
|
||||
{[
|
||||
{ Icon: NotebookTextIcon, text: '55+ Lessons' },
|
||||
{ Icon: FileQuestionIcon, text: '100+ Challenges' },
|
||||
{ Icon: BrainIcon, text: 'AI Tutor' },
|
||||
{ Icon: CodeIcon, text: 'Integrated IDE' },
|
||||
].map(({ Icon, text }, index) => (
|
||||
<div key={index} className="flex flex-row items-center gap-2 text-base lg:text-xl text-zinc-300">
|
||||
<Icon className="size-5 lg:size-6 text-yellow-400" />
|
||||
<span>{text}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<AuthorCredentials />
|
||||
</div>
|
||||
|
||||
<PlatformDemo />
|
||||
<div className="flex flex-col gap-7 sm:flex-row sm:items-center">
|
||||
<a
|
||||
href="https://roadmap.sh"
|
||||
target="_blank"
|
||||
className="transition-opacity hover:opacity-100"
|
||||
>
|
||||
<RoadmapLogoIcon className="size-12 sm:size-22" />
|
||||
</a>
|
||||
<div className="flex flex-col items-start gap-2.5">
|
||||
<h1 className="text-3xl font-bold tracking-tight text-white sm:text-4xl md:text-6xl">
|
||||
Master SQL Queries
|
||||
</h1>
|
||||
<p className="text-left text-xl text-balance text-zinc-300 md:text-2xl">
|
||||
Complete course with AI Tutor, real-world challenges and more
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<PurchaseBanner />
|
||||
<p className="my-5 text-xl leading-relaxed text-zinc-300 md:my-14 lg:text-xl">
|
||||
Get certified for SQL queries and ready to deploy your newly-gained
|
||||
skill in 30 days. Perfect for developers, data analysts, and anyone
|
||||
working with data. Level up risk-free with a 7-day money-back
|
||||
guarantee.
|
||||
</p>
|
||||
|
||||
<ReviewCarousel />
|
||||
<div className="flex flex-col-reverse gap-7 lg:flex-row lg:gap-14">
|
||||
<div className="w-full shrink-0 flex-row-reverse items-start justify-between gap-3 text-lg md:flex lg:w-auto lg:flex-col">
|
||||
<div className="mb-7 flex flex-col gap-2 lg:mb-0 lg:gap-4">
|
||||
{[
|
||||
{ Icon: NotebookTextIcon, text: '55+ Lessons' },
|
||||
{ Icon: FileQuestionIcon, text: '100+ Challenges' },
|
||||
{ Icon: BrainIcon, text: 'AI Tutor' },
|
||||
{ Icon: CodeIcon, text: 'Integrated IDE' },
|
||||
].map(({ Icon, text }, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex flex-row items-center gap-2 text-base text-zinc-300 lg:text-xl"
|
||||
>
|
||||
<Icon className="size-5 text-yellow-400 lg:size-6" />
|
||||
<span>{text}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<CourseFeatures />
|
||||
<AuthorCredentials />
|
||||
</div>
|
||||
|
||||
<MeetYourInstructor />
|
||||
|
||||
<SectionHeader
|
||||
title="Course Overview"
|
||||
description="This SQL programming class is designed to help you go from beginner to expert through hands-on practice with real-world scenarios, mastering everything from basic to complex queries."
|
||||
className="mt-8 md:mt-24"
|
||||
/>
|
||||
|
||||
<div className="mx-auto mt-8 w-full max-w-3xl space-y-4 md:mt-12">
|
||||
{sqlCourseChapters.map((chapter, index) => (
|
||||
<ChapterRow key={index} counter={index + 1} {...chapter} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<SectionHeader
|
||||
title="Ready to master SQL?"
|
||||
description="Start learning SQL queries risk-free with a 7-day money-back guarantee."
|
||||
className="mt-8 md:mt-24"
|
||||
/>
|
||||
|
||||
<div className="mx-auto mt-8 w-full">
|
||||
<BuyButton variant="floating" />
|
||||
</div>
|
||||
|
||||
<FAQSection />
|
||||
|
||||
<div className="mx-auto mt-12 w-full max-w-3xl text-left md:mt-9">
|
||||
<p className="flex flex-col items-center justify-center gap-2 text-sm md:flex-row md:gap-0">
|
||||
<a href="/terms" target="_blank" className="text-zinc-500">
|
||||
Terms of Use
|
||||
</a>
|
||||
<span className="mx-4 hidden md:block">·</span>
|
||||
<a href="/privacy" target="_blank" className="text-zinc-500">
|
||||
Privacy Policy
|
||||
</a>
|
||||
</p>
|
||||
<PlatformDemo />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<PurchaseBanner />
|
||||
|
||||
<ReviewCarousel />
|
||||
|
||||
<CourseFeatures />
|
||||
|
||||
<MeetYourInstructor />
|
||||
|
||||
<SectionHeader
|
||||
title="Course Overview"
|
||||
description="This SQL programming class is designed to help you go from beginner to expert through hands-on practice with real-world scenarios, mastering everything from basic to complex queries."
|
||||
className="mt-8 md:mt-24"
|
||||
/>
|
||||
|
||||
<div className="mx-auto mt-8 w-full max-w-3xl space-y-4 md:mt-12">
|
||||
{sqlCourseChapters.map((chapter, index) => (
|
||||
<ChapterRow key={index} counter={index + 1} {...chapter} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<SectionHeader
|
||||
title="Ready to master SQL?"
|
||||
description="Start learning SQL queries risk-free with a 7-day money-back guarantee."
|
||||
className="mt-8 md:mt-24"
|
||||
/>
|
||||
|
||||
<div className="mx-auto mt-8 w-full">
|
||||
<BuyButton variant="floating" />
|
||||
</div>
|
||||
|
||||
<FAQSection />
|
||||
|
||||
<div className="mx-auto mt-12 w-full max-w-3xl text-left md:mt-9">
|
||||
<p className="flex flex-col items-center justify-center gap-2 text-sm md:flex-row md:gap-0">
|
||||
<a href="/terms" target="_blank" className="text-zinc-500">
|
||||
Terms of Use
|
||||
</a>
|
||||
<span className="mx-4 hidden md:block">·</span>
|
||||
<a href="/privacy" target="_blank" className="text-zinc-500">
|
||||
Privacy Policy
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user