mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-09-02 05:42:41 +02:00
Purchase banner
This commit is contained in:
@@ -1,33 +1,85 @@
|
|||||||
import { CheckIcon, Star } from 'lucide-react';
|
import { CheckIcon, Star } from 'lucide-react';
|
||||||
import { BuyButton } from './BuyButton';
|
import { BuyButton } from './BuyButton';
|
||||||
import { Rating } from '../Rating/Rating';
|
import { Rating } from '../Rating/Rating';
|
||||||
|
import { cn } from '../../lib/classname';
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
export function PurchaseBanner() {
|
export function PurchaseBanner() {
|
||||||
return (
|
const bannerRef = useRef<HTMLDivElement>(null);
|
||||||
<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">
|
const [isOutOfView, setIsOutOfView] = useState(false);
|
||||||
{[
|
|
||||||
'7-Day Money-Back Guarantee',
|
useEffect(() => {
|
||||||
'Lifetime access & updates'
|
const handleScroll = () => {
|
||||||
].map((text, index) => (
|
if (!bannerRef.current) return;
|
||||||
<span key={index} className="inline-flex items-center gap-1.5 text-yellow-500">
|
|
||||||
<CheckIcon className="size-5 stroke-[2.5]" />
|
const bannerRect = bannerRef.current.getBoundingClientRect();
|
||||||
{text}
|
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>
|
</span>
|
||||||
))}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
<div className="order-2 lg:order-0">
|
};
|
||||||
<BuyButton variant="floating" floatingClassName="translate-x-0 lg:-translate-x-5" />
|
return (
|
||||||
</div>
|
<>
|
||||||
|
<Banner ref={bannerRef} />
|
||||||
<div className="flex flex-col items-center gap-2">
|
<Banner
|
||||||
<Rating rating={4.9} className="hidden lg:flex" />
|
className={cn(
|
||||||
<span className="text-base font-semibold text-yellow-500 flex items-center gap-1">
|
'fixed top-[unset] right-0 bottom-0 left-0 rounded-none lg:hidden',
|
||||||
<Star className="size-4 block lg:hidden fill-current" />
|
isOutOfView ? 'flex' : 'hidden',
|
||||||
4.9 avg. Review
|
)}
|
||||||
</span>
|
/>
|
||||||
</div>
|
</>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
BrainIcon,
|
BrainIcon,
|
||||||
CodeIcon,
|
CodeIcon,
|
||||||
FileQuestionIcon, NotebookTextIcon
|
FileQuestionIcon,
|
||||||
|
NotebookTextIcon,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { Spotlight } from '../SQLCourse/Spotlight';
|
import { Spotlight } from '../SQLCourse/Spotlight';
|
||||||
import { RoadmapLogoIcon } from '../ReactIcons/RoadmapLogo';
|
import { RoadmapLogoIcon } from '../ReactIcons/RoadmapLogo';
|
||||||
@@ -19,105 +20,106 @@ import { sqlCourseChapters } from '../SQLCourse/SQLCoursePage';
|
|||||||
|
|
||||||
export function SQLCourseVariantPage() {
|
export function SQLCourseVariantPage() {
|
||||||
return (
|
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="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="mx-auto mt-7 w-full max-w-5xl md:mt-20">
|
<div className="relative">
|
||||||
<div className="relative">
|
<Spotlight className="top-[-200px] left-[-170px]" fill="#EAB308" />
|
||||||
<Spotlight className="top-[-200px] left-[-170px]" fill="#EAB308" />
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-7 sm:flex-row sm:items-center">
|
<div className="flex flex-col gap-7 sm:flex-row sm:items-center">
|
||||||
<a
|
<a
|
||||||
href="https://roadmap.sh"
|
href="https://roadmap.sh"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="transition-opacity hover:opacity-100"
|
className="transition-opacity hover:opacity-100"
|
||||||
>
|
>
|
||||||
<RoadmapLogoIcon className="size-12 sm:size-22" />
|
<RoadmapLogoIcon className="size-12 sm:size-22" />
|
||||||
</a>
|
</a>
|
||||||
<div className="flex flex-col items-start gap-2.5">
|
<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">
|
<h1 className="text-3xl font-bold tracking-tight text-white sm:text-4xl md:text-6xl">
|
||||||
Master SQL Queries
|
Master SQL Queries
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-left text-balance text-xl text-zinc-300 md:text-2xl">
|
<p className="text-left text-xl text-balance text-zinc-300 md:text-2xl">
|
||||||
Complete course with AI Tutor, real-world challenges and more
|
Complete course with AI Tutor, real-world challenges and more
|
||||||
</p>
|
</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>
|
</div>
|
||||||
</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 />
|
<PlatformDemo />
|
||||||
|
|
||||||
<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>
|
</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>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user