1
0
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:
Kamran Ahmed
2025-07-01 02:25:33 +01:00
parent 7dc01ea8c6
commit 2cb3bf9562
2 changed files with 169 additions and 115 deletions

View File

@@ -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() {
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 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
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">
{['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" />
<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" />
<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>
);
};
return (
<>
<Banner ref={bannerRef} />
<Banner
className={cn(
'fixed top-[unset] right-0 bottom-0 left-0 rounded-none lg:hidden',
isOutOfView ? 'flex' : 'hidden',
)}
/>
</>
);
}

View File

@@ -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,7 +20,6 @@ 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">
@@ -37,30 +37,33 @@ export function SQLCourseVariantPage() {
<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">
<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>
<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.
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="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="flex flex-col gap-2 lg:gap-4 mb-7 lg:mb-0">
<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 lg:text-xl text-zinc-300">
<Icon className="size-5 lg:size-6 text-yellow-400" />
<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>
))}
@@ -118,6 +121,5 @@ export function SQLCourseVariantPage() {
</div>
</div>
</div>
</>
);
}