mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
feat: Adding nextui pro section on the landing page (#4227)
* feat: adding nextui pro section on the landing page * chore(nits): nits * fix: remove pro image on mobile --------- Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
This commit is contained in:
parent
3dbb0f2136
commit
366056647a
@ -13,6 +13,7 @@ import {Community} from "@/components/marketing/community";
|
||||
import Support from "@/components/marketing/support";
|
||||
import landingContent from "@/content/landing";
|
||||
import {Sponsors} from "@/components/marketing/sponsors";
|
||||
import {NextUIProSection} from "@/components/marketing/nextui-pro-section";
|
||||
|
||||
export default async function Home() {
|
||||
return (
|
||||
@ -25,6 +26,7 @@ export default async function Home() {
|
||||
<A11yOtb />
|
||||
<DarkMode />
|
||||
<Customization />
|
||||
<NextUIProSection />
|
||||
<LastButNotLeast />
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<Support />
|
||||
|
||||
79
apps/docs/components/marketing/marquee.tsx
Normal file
79
apps/docs/components/marketing/marquee.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
"use client";
|
||||
|
||||
import type {ReactNode} from "react";
|
||||
import type {ScrollShadowProps} from "@nextui-org/react";
|
||||
|
||||
import {Children, cloneElement} from "react";
|
||||
import {ScrollShadow} from "@nextui-org/react";
|
||||
import {cn} from "@nextui-org/react";
|
||||
|
||||
interface MarqueeProps {
|
||||
className?: string;
|
||||
reverse?: boolean;
|
||||
shadow?: boolean;
|
||||
duration?: number;
|
||||
pauseOnHover?: boolean;
|
||||
vertical?: boolean;
|
||||
children?: ReactNode;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export const Marquee = ({
|
||||
className,
|
||||
reverse,
|
||||
duration = 40,
|
||||
shadow = false,
|
||||
pauseOnHover = false,
|
||||
vertical = false,
|
||||
children,
|
||||
...props
|
||||
}: MarqueeProps) => {
|
||||
const shadowProps: ScrollShadowProps = {
|
||||
isEnabled: shadow,
|
||||
offset: -20,
|
||||
size: 300,
|
||||
orientation: "vertical",
|
||||
visibility: "both",
|
||||
};
|
||||
|
||||
const Wrapper = shadow ? ScrollShadow : "div";
|
||||
|
||||
const componentProps = shadow ? {...props, ...shadowProps} : props;
|
||||
|
||||
return (
|
||||
<Wrapper
|
||||
{...componentProps}
|
||||
className={cn(
|
||||
"flex [--gap:1rem]",
|
||||
{
|
||||
"w-full": !vertical,
|
||||
"overflow-y-hidden": vertical,
|
||||
"overflow-x-hidden": !vertical,
|
||||
"max-h-[calc(100vh_-_200px)]": vertical,
|
||||
},
|
||||
className,
|
||||
)}
|
||||
style={{
|
||||
// @ts-ignore
|
||||
"--duration": `${duration}s`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={cn("flex w-max items-stretch gap-[--gap]", {
|
||||
"flex-col": vertical,
|
||||
"h-full": vertical,
|
||||
"animate-scrolling-banner": !vertical,
|
||||
"animate-scrolling-banner-vertical": vertical,
|
||||
"[animation-direction:reverse]": reverse,
|
||||
"hover:[animation-play-state:paused]": pauseOnHover,
|
||||
})}
|
||||
>
|
||||
{Children.map(children, (child) =>
|
||||
child && typeof child === "object" && "type" in child ? cloneElement(child) : child,
|
||||
)}
|
||||
</div>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Marquee;
|
||||
182
apps/docs/components/marketing/nextui-pro-section.tsx
Normal file
182
apps/docs/components/marketing/nextui-pro-section.tsx
Normal file
@ -0,0 +1,182 @@
|
||||
"use client";
|
||||
|
||||
import {Button, Chip} from "@nextui-org/react";
|
||||
import {useEffect, useState} from "react";
|
||||
import {useTheme} from "next-themes";
|
||||
|
||||
import {sectionWrapper, title, titleWrapper, subtitle} from "../primitives";
|
||||
|
||||
import Marquee from "./marquee";
|
||||
|
||||
import {useIsMobile} from "@/hooks/use-media-query";
|
||||
|
||||
export const NextUIProSection = () => {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
const {theme} = useTheme();
|
||||
const isDarkMode = theme === "dark";
|
||||
|
||||
let imgSrc: string;
|
||||
|
||||
if (isDarkMode) {
|
||||
imgSrc = isMobile
|
||||
? "/images/nextuipro-section-background@mobile.webp"
|
||||
: "/images/nextuipro-section-background.webp";
|
||||
} else {
|
||||
imgSrc = isMobile
|
||||
? "/images/nextuipro-section-background-light@mobile.webp"
|
||||
: "/images/nextuipro-section-background-light.webp";
|
||||
}
|
||||
|
||||
const mobileClassName: string = isDarkMode
|
||||
? "h-full w-full bg-[radial-gradient(at_40%_80%,_rgba(255,255,255,_0)_5%,_rgba(0,0,0,_0.8)_50%,_rgba(0,0,0,1)_100%)]"
|
||||
: "h-full w-full bg-[radial-gradient(at_40%_80%,_rgba(0,0,0,_0)_5%,_rgba(255,255,255,_0.8)_50%,_rgba(255,255,255,1)_100%)]";
|
||||
|
||||
const webClassName: string = isDarkMode
|
||||
? "h-full w-full bg-[radial-gradient(at_80%_50%,_rgba(255,255,255,_0)_20%,_rgba(0,0,0,_0.8)_40%,_rgba(0,0,0,1)_100%)]"
|
||||
: "h-full w-full bg-[radial-gradient(at_80%_50%,_rgba(0,0,0,_0)_20%,_rgba(255,255,255,_0.9)_40%,_rgba(255,255,255,1)_100%)]";
|
||||
|
||||
if (!mounted) return null;
|
||||
|
||||
const CheckmarkIcon = () => (
|
||||
<svg fill="none" height="11" viewBox="0 0 13 11" width="13" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M1 6.4L4.14286 10L12 1"
|
||||
stroke="#006FEE"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
return (
|
||||
<section className={sectionWrapper({class: "mt-16 lg:mt-44 overflow-hidden"})}>
|
||||
<div className="flex flex-col gap-8 min-h-[480px]">
|
||||
<div className="z-30 flex w-screen h-full flex-col items-start justify-center leading-8 pt-4">
|
||||
<Chip
|
||||
classNames={{
|
||||
base: "ml-0.5 transition-colors bg-gradient-to-br from-cyan-600 to-blue-600",
|
||||
content: "text-tiny font-semibold",
|
||||
}}
|
||||
color="primary"
|
||||
size="sm"
|
||||
>
|
||||
PRO
|
||||
</Chip>
|
||||
<div className={titleWrapper({class: "mt-2 inline md:block"})}>
|
||||
<h1 className={title({size: "lg", class: "[text-shadow:_0_3px_0_rgb(0_0_0_/_10%)]"})}>
|
||||
Ship
|
||||
</h1>
|
||||
<h1
|
||||
className={title({
|
||||
size: "lg",
|
||||
color: "blue",
|
||||
class: "[text-shadow:_0_3px_0_rgb(0_0_0_/_10%)]",
|
||||
})}
|
||||
>
|
||||
faster
|
||||
</h1>
|
||||
<h1 className={title({size: "lg", class: "[text-shadow:_0_3px_0_rgb(0_0_0_/_10%)]"})}>
|
||||
with
|
||||
</h1>
|
||||
<div className="flex flex-col sm:flex-row">
|
||||
<h1 className={title({size: "lg", class: "[text-shadow:_0_3px_0_rgb(0_0_0_/_10%)]"})}>
|
||||
beautiful
|
||||
</h1>
|
||||
<h1 className={title({size: "lg", class: "[text-shadow:_0_3px_0_rgb(0_0_0_/_10%)]"})}>
|
||||
components
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<p className={subtitle({class: "pr-12 text-foreground-500"})}>
|
||||
Premade templates of over 210+ beautiful and responsive components, professionally
|
||||
created by the team behind NextUI.
|
||||
</p>
|
||||
<div className="mt-4 text-foreground-600 font-medium">
|
||||
<div className="flex gap-x-4 items-center">
|
||||
<CheckmarkIcon />
|
||||
210+ Components
|
||||
</div>
|
||||
<div className="flex gap-x-4 items-center">
|
||||
<CheckmarkIcon />
|
||||
Lifetime Access
|
||||
</div>
|
||||
<div className="flex gap-x-4 items-center">
|
||||
<CheckmarkIcon />
|
||||
Free Updates
|
||||
</div>
|
||||
<div className="flex gap-x-4 items-center">
|
||||
<CheckmarkIcon />
|
||||
Figma Files Included
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<Button
|
||||
as={"a"}
|
||||
className="px-6 flex items-center"
|
||||
color="primary"
|
||||
href="https://nextui.pro?utm_source=nextui.org&utm_medium=nextui-homepage-section"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Explore NextUI Pro
|
||||
<svg
|
||||
fill="none"
|
||||
height="21"
|
||||
viewBox="0 0 20 21"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12.0254 5.44189L17.0837 10.5002L12.0254 15.5586"
|
||||
stroke="white"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="10"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
<path
|
||||
d="M2.91602 10.5H16.941"
|
||||
stroke="white"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="10"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
</svg>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="overflow-hidden">
|
||||
<Marquee
|
||||
vertical
|
||||
className="h-78 hidden md:flex w-screen mt-4 md:absolute md:top-0 md:inset-0 isolate md:max-h-dvh"
|
||||
duration={isMobile ? 240 : 60}
|
||||
>
|
||||
<img
|
||||
alt="Hero Background"
|
||||
className="w-full"
|
||||
height={3255}
|
||||
loading="lazy"
|
||||
src={imgSrc}
|
||||
width={1920}
|
||||
/>
|
||||
</Marquee>
|
||||
<div className="absolute md:hidden inset-0 pointer-events-none top-0 z-20">
|
||||
<div className={mobileClassName} />
|
||||
</div>
|
||||
|
||||
<div className="absolute hidden md:block md:inset-0 md:pointer-events-none md:top-0 md:z-20">
|
||||
<div className={webClassName} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
BIN
apps/docs/public/images/nextuipro-section-background-light.webp
Normal file
BIN
apps/docs/public/images/nextuipro-section-background-light.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.0 MiB |
BIN
apps/docs/public/images/nextuipro-section-background.webp
Normal file
BIN
apps/docs/public/images/nextuipro-section-background.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 404 KiB |
BIN
apps/docs/public/images/nextuipro-section-background@mobile.webp
Normal file
BIN
apps/docs/public/images/nextuipro-section-background@mobile.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 197 KiB |
@ -319,6 +319,14 @@ module.exports = {
|
||||
backgroundPosition: "-200% center",
|
||||
},
|
||||
},
|
||||
"scrolling-banner": {
|
||||
from: {transform: "translateX(0)"},
|
||||
to: {transform: "translateX(calc(-50% - var(--gap)/2))"},
|
||||
},
|
||||
"scrolling-banner-vertical": {
|
||||
from: {transform: "translateY(0)"},
|
||||
to: {transform: "translateY(calc(-50% - var(--gap)/2))"},
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
heartbeat: "heartbeat 1s ease-in-out infinite",
|
||||
@ -326,6 +334,8 @@ module.exports = {
|
||||
expand: "expand 6s ease-out infinite both",
|
||||
"expand-opacity": "expand-opacity 6s linear infinite both",
|
||||
"text-gradient": "text-gradient 4s linear 0s infinite normal forwards running",
|
||||
"scrolling-banner": "scrolling-banner var(--duration) linear infinite",
|
||||
"scrolling-banner-vertical": "scrolling-banner-vertical var(--duration) linear infinite",
|
||||
},
|
||||
maxWidth: {
|
||||
"8xl": "90rem", // 1440px
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user