feat: add dedicated pricing page with multiple pricing components

- Create new `/pricing` route with dynamic localization
- Implement three pricing components (Pricing3, Pricing4, Pricing5) from NSUI design system
- Update routes configuration to use dedicated pricing page instead of anchor link
- Add localization support for pricing page title
- Adjust home page margin for consistent layout
This commit is contained in:
javayhu 2025-03-09 00:26:34 +08:00
parent 6160622ccd
commit 129aac2c12
7 changed files with 267 additions and 2 deletions

View File

@ -7,6 +7,9 @@
"HomePage": {
"title": "next-intl example"
},
"PricingPage": {
"title": "Pricing"
},
"NotFoundPage": {
"title": "404",
"message": "Sorry, the page you are looking for does not exist.",

View File

@ -20,7 +20,7 @@ export default async function HomePage(props: HomePageProps) {
return (
<>
<div className="mt-12 flex flex-col gap-16">
<div className="mt-8 flex flex-col gap-16">
<HeroSection />
<LogoCloud />

View File

@ -0,0 +1,26 @@
import Pricing3 from "@/components/nsui/pricing3";
import Pricing4 from "@/components/nsui/pricing4";
import Pricing5 from "@/components/nsui/pricing5";
import { getTranslations } from 'next-intl/server';
interface PricingPageProps {
params: Promise<{ locale: string }>;
};
export default async function PricingPage(props: PricingPageProps) {
const params = await props.params;
const { locale } = params;
const t = await getTranslations('PricingPage');
return (
<>
<div className="mt-8 flex flex-col gap-16 pb-16">
<Pricing5 />
<Pricing4 />
<Pricing3 />
</div>
</>
);
}

View File

@ -0,0 +1,104 @@
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Check } from 'lucide-react'
/**
* https://nsui.irung.me/pricing
*/
export default function Pricing3() {
return (
<section className="py-16">
<div className="mx-auto max-w-6xl px-6">
<div className="mx-auto max-w-2xl space-y-6 text-center">
<h1 className="text-center text-4xl font-semibold lg:text-5xl">Pricing that Scales with You</h1>
<p>Gemini is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="mt-8 grid gap-6 md:mt-20 md:grid-cols-3">
<Card>
<CardHeader>
<CardTitle className="font-medium">Free</CardTitle>
<span className="my-3 block text-2xl font-semibold">$0 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
<Button asChild variant="outline" className="mt-4 w-full">
<Link href="">Get Started</Link>
</Button>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Basic Analytics Dashboard', '5GB Cloud Storage', 'Email and Chat Support'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
</Card>
<Card className="relative">
<span className="bg-linear-to-br/increasing absolute inset-x-0 -top-3 mx-auto flex h-6 w-fit items-center rounded-full from-purple-400 to-amber-300 px-3 py-1 text-xs font-medium text-amber-950 ring-1 ring-inset ring-white/20 ring-offset-1 ring-offset-gray-950/5">Popular</span>
<CardHeader>
<CardTitle className="font-medium">Pro</CardTitle>
<span className="my-3 block text-2xl font-semibold">$19 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
<Button asChild className="mt-4 w-full">
<Link href="">Get Started</Link>
</Button>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Everything in Free Plan', '5GB Cloud Storage', 'Email and Chat Support', 'Access to Community Forum', 'Single User Access', 'Access to Basic Templates', 'Mobile App Access', '1 Custom Report Per Month', 'Monthly Product Updates', 'Standard Security Features'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
</Card>
<Card className="flex flex-col">
<CardHeader>
<CardTitle className="font-medium">Startup</CardTitle>
<span className="my-3 block text-2xl font-semibold">$29 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
<Button asChild variant="outline" className="mt-4 w-full">
<Link href="">Get Started</Link>
</Button>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Everything in Pro Plan', '5GB Cloud Storage', 'Email and Chat Support'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
</Card>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,75 @@
import { Button } from '@/components/ui/button'
import { Check } from 'lucide-react'
import Link from 'next/link'
/**
* https://nsui.irung.me/pricing
*/
export default function Pricing4() {
return (
<section className="py-16">
<div className="mx-auto max-w-5xl px-6">
<div className="mx-auto max-w-2xl space-y-6 text-center">
<h1 className="text-center text-4xl font-semibold lg:text-5xl">Pricing that Scales with You</h1>
<p>Gemini is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="mt-8 grid gap-6 md:mt-20 md:grid-cols-5 md:gap-0">
<div className="rounded-(--radius) flex flex-col justify-between space-y-8 border p-6 md:col-span-2 md:my-2 md:rounded-r-none md:border-r-0 lg:p-10">
<div className="space-y-4">
<div>
<h2 className="font-medium">Free</h2>
<span className="my-3 block text-2xl font-semibold">$0 / mo</span>
<p className="text-muted-foreground text-sm">Per editor</p>
</div>
<Button asChild variant="outline" className="w-full">
<Link href="">Get Started</Link>
</Button>
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Basic Analytics Dashboard', '5GB Cloud Storage', 'Email and Chat Support'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</div>
</div>
<div className="dark:bg-muted rounded-(--radius) border p-6 shadow-lg shadow-gray-950/5 md:col-span-3 lg:p-10 dark:[--color-muted:var(--color-zinc-900)]">
<div className="grid gap-6 sm:grid-cols-2">
<div className="space-y-4">
<div>
<h2 className="font-medium">Pro</h2>
<span className="my-3 block text-2xl font-semibold">$19 / mo</span>
<p className="text-muted-foreground text-sm">Per editor</p>
</div>
<Button asChild className="w-full">
<Link href="">Get Started</Link>
</Button>
</div>
<div>
<div className="text-sm font-medium">Everything in free plus :</div>
<ul className="mt-4 list-outside space-y-3 text-sm">
{['Everything in Free Plan', '5GB Cloud Storage', 'Email and Chat Support', 'Access to Community Forum', 'Single User Access', 'Access to Basic Templates', 'Mobile App Access', '1 Custom Report Per Month', 'Monthly Product Updates', 'Standard Security Features'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</div>
</div>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,57 @@
import { Button } from '@/components/ui/button'
import { Check } from 'lucide-react'
import Link from 'next/link'
/**
* https://nsui.irung.me/pricing
*/
export default function Pricing5() {
return (
<div className="py-16">
<div className="mx-auto max-w-5xl px-6">
<div className="mx-auto max-w-2xl text-center">
<h2 className="text-balance text-3xl font-bold md:text-4xl lg:text-5xl">Start managing your company smarter today</h2>
</div>
<div className="mt-8 md:mt-20">
<div className="bg-card relative rounded-3xl border shadow-2xl shadow-zinc-950/5">
{/* divide-y md:divide-x md:divide-y-0 */}
<div className="grid items-center gap-12 p-12 md:grid-cols-2">
<div className="pb-12 text-center md:pb-0 md:pr-12">
<h3 className="text-2xl font-semibold">Suite Enterprise</h3>
<p className="mt-2 text-lg">For your company of any size</p>
<span className="mb-6 mt-12 inline-block text-6xl font-bold">
<span className="text-4xl">$</span>234
</span>
<div className="flex justify-center">
<Button asChild size="lg">
<Link href="#">Get started</Link>
</Button>
</div>
<p className="text-muted-foreground mt-12 text-sm">Includes : Security, Unlimited Storage, Payment, Search engine, and all features</p>
</div>
<div className="relative">
<ul role="list" className="space-y-4">
{['First premium advantage', 'Second advantage weekly', 'Third advantage donate to project', 'Fourth, access to all components weekly'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
<span>{item}</span>
</li>
))}
</ul>
<p className="text-muted-foreground mt-6 text-sm">Team can be any size, and you can add or switch members as needed. Companies using our platform include:</p>
<div className="mt-12 flex flex-wrap items-center justify-between gap-6">
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nvidia.svg" alt="Nvidia Logo" height="20" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/column.svg" alt="Column Logo" height="16" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/github.svg" alt="GitHub Logo" height="16" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nike.svg" alt="Nike Logo" height="20" width="auto" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}

View File

@ -6,8 +6,8 @@ export enum Routes {
DefaultLoginRedirect = '/dashboard',
Features = '/#features',
Pricing = '/#pricing',
FAQ = '/#faq',
Pricing = '/pricing',
TermsOfService = '/terms-of-service',
PrivacyPolicy = '/privacy-policy',