Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Components/key features and pricing card #16

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions public/basic-price-bg.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 1 addition & 3 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import { Headphone, Layout, Lens, Mail } from "@/components/icons/icon";
export default function Home() {
return (
<>
<h1 className="text-4xl py-6 text-center font-bold">
AI Adgen
</h1>
<h1 className="text-4xl py-6 text-center font-bold">AI Adgen</h1>
</>
);
}
61 changes: 61 additions & 0 deletions src/components/key-features-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from "react";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";

// Define the structure of a feature item
interface Feature {
title: string;
description: string;
}

// Data for the feature cards
const featuresData: Feature[] = [
{
title: "AI-powered Visuals",
description:
"Get automated image and video suggestions that fit your campaign.",
},
{
title: "Analytics Insights",
description: "AI analyzes your past campaigns to enhance future ads.",
},
{
title: "Multi-Platform",
description: "Download Ads in the perfect format for every platform.",
},
];

// FeatureCard component that renders the feature cards
const FeatureCard = () => {
return (
<div className="grid lg:grid-cols-3 grid-cols-1 gap-4 max-w-7xl bg-white mx-auto px-8">
{/* Loop through featuresData to generate cards dynamically */}
{featuresData.map((feature, index) => (
<Card
key={index}
className="px-10 py-8 gap-6 items-start rounded-2xl border border-[#FCFCFC] bg-[#F8E6F8]/50"
>
{/* Card Header containing the feature title */}
<CardHeader className="p-0">
<CardTitle className="text-[#520052] text-[32px] font-semibold leading-[40px] pr-28">
{feature.title}
</CardTitle>
</CardHeader>
{/* Card Content containing the feature description */}
<CardContent className="p-0">
<CardDescription className="text-[#7D7D7D] text-2xl font-normal leading-[32px]">
{feature.description}
</CardDescription>
</CardContent>
</Card>
))}
</div>
);
};

export default FeatureCard;
152 changes: 152 additions & 0 deletions src/components/pricing-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
"use client";
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@/components/ui/card";
import { Tick } from "./icons/icon";
import { Button } from "./ui/button";

// Define the structure of a pricing tier
interface Tier {
name: string;
id: string;
price: number | "Free";
description: string;
features: string[];
mostPopular: boolean; // Indicates if the plan is highlighted
}

// Pricing plans with their details
const tiers: Tier[] = [
{
name: "Starter",
id: "tier-starter",
price: "Free",
description: "Get a few features to start your Adgen-ai journey.",
features: [
"5 ads per month",
"Watermarked exports",
"Limited selection of templates",
"Standard resolution only (720p)",
],
mostPopular: false, // Not the highlighted plan
},
{
name: "Basic",
id: "tier-basic",
price: 30,
description: "Get full usage of the generator.",
features: [
"Unlimited generated ads",
"No watermarked exports",
"Access to premium templates",
"Exports in HD quality (1080p)",
],
mostPopular: true, // This is the highlighted plan
},
{
name: "Teams",
id: "tier-teams",
price: 50,
description: "A full package for a 3-4 membered team.",
features: [
"Unlimited generated ads",
"Share with team members",
"Team brand kit integration",
"4K resolution & custom export options",
],
mostPopular: false, // Not the highlighted plan
},
];

export default function PricingCard() {
return (
<div className="mx-auto max-w-md mt-10 grid grid-cols-1 gap-6 lg:max-w-6xl lg:grid-cols-3">
{tiers.map((tier) => (
<Card
key={tier.id}
className={`relative rounded-2xl border gap-0 border-[#E3E3E3] shadow-[0px_1px_3px_2px_rgba(0,0,0,0.06)] px-[1.65rem] py-10
${tier.mostPopular ? "bg-[#CF54CF]" : "bg-white "}
${
tier.id === "tier-basic"
? "bg-[url('/basic-price-bg.svg')] bg-cover bg-center text-white before:absolute before:inset-0 before:bg-black/0 before:z-0"
: ""
}`}
>
{/* Card Header with Title and Description */}
<CardHeader className="gap-0 py-0 pl-0 pr-4 md:pr-10 xl:pr-19">
<CardTitle
className={`text-[28px] font-semibold leading-[36px] ${
tier.mostPopular ? "text-white" : "text-[#CF54CF]"
}`}
>
{tier.name}
</CardTitle>
<CardDescription
className={`text-sm min-h-10 font-normal leading-5 ${
tier.mostPopular ? "text-white" : "text-[#A1A1A1]"
}`}
>
{tier.description}
</CardDescription>
</CardHeader>

{/* Card Content with Price and Features */}
<CardContent className="mt-4 p-0">
<p
className={`flex items-baseline gap-x-2 ${
tier.mostPopular ? "text-white" : "text-[#CF54CF]"
} text-[36px] font-semibold leading-[44px]`}
>
{/* Display "Free" if price is free, otherwise show price */}
{tier.price === "Free" ? (
"Free"
) : (
<>
${tier.price}
<span className="text-sm font-normal -ml-1 leading-5">
/mo
</span>
</>
)}
</p>
<div className="bg-[#E3E3E3] h-[1px] w-full mt-[1rem] mb-11" />

{/* Features List */}
<ul
role="list"
className="mt-6 gap-4 flex flex-col text-sm text-gray-600"
>
{tier.features.map((feature) => (
<li
key={feature}
className={`flex items-center gap-x-[0.9rem] text-nowrap ${
tier.mostPopular ? "text-white" : "text-black"
} text-base font-normal leading-6`}
>
<Tick /> {/* Checkmark icon */}
{feature}
</li>
))}
</ul>
</CardContent>

{/* Card Footer with Button */}
<CardFooter>
<Button
className="mt-13 mx-auto text-base font-medium leading-[24px]"
variant={tier.mostPopular ? "choosePlanOutline" : "choosePlan"}
size="choosePlan"
>
Choose Plan
</Button>
</CardFooter>
</Card>
))}
</div>
);
}
23 changes: 14 additions & 9 deletions src/components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";

const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
Expand All @@ -17,13 +17,18 @@ const buttonVariants = cva(
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
choosePlan:
"bg-[#B800B8] text-white hover:bg-[#990099] border border-white",
choosePlanOutline:
"border-[#B800B8] bg-white border text-[#B800B8] hover:bg-[#B800B81A] ",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
choosePlan: "rounded-md px-6 py-3",
icon: "size-9",
},
},
Expand All @@ -32,7 +37,7 @@ const buttonVariants = cva(
size: "default",
},
}
)
);

function Button({
className,
Expand All @@ -42,17 +47,17 @@ function Button({
...props
}: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean
asChild?: boolean;
}) {
const Comp = asChild ? Slot : "button"
const Comp = asChild ? Slot : "button";

return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
)
);
}

export { Button, buttonVariants }
export { Button, buttonVariants };
75 changes: 75 additions & 0 deletions src/components/ui/card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import * as React from "react";

import { cn } from "@/lib/utils";

function Card({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card"
className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
className
)}
{...props}
/>
);
}

function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-header"
className={cn("flex flex-col gap-1.5 px-6", className)}
{...props}
/>
);
}

function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-title"
className={cn("leading-none font-semibold", className)}
{...props}
/>
);
}

function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-description"
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
);
}

function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-content"
className={cn("px-6", className)}
{...props}
/>
);
}

function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-footer"
className={cn("flex items-center px-6", className)}
{...props}
/>
);
}

export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
};