Skip to content

Commit

Permalink
landing page
Browse files Browse the repository at this point in the history
  • Loading branch information
vishwajeetraj11 committed Jun 11, 2023
1 parent 310577f commit e51b683
Show file tree
Hide file tree
Showing 21 changed files with 352 additions and 14 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"react-dom": "18.2.0",
"react-final-form": "^6.5.9",
"react-icons": "^4.8.0",
"react-intersection-observer": "^9.4.4",
"react-lottie": "^1.2.3",
"react-query": "^3.39.3",
"react-use": "^17.4.0",
Expand Down
Binary file added public/budget.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/budgetGraph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/calender-horizontal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/categories.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/dark-budget.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/darkBudgetGraph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/dashboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/showcase1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions src/components/landing/CTASection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Button } from "@tremor/react"
import Link from "next/link"

const CTASection = () => {
return (
<div className="py-5 md:py-10 bg-blue-600 px-8 w-full">
<div className="py-10 md:py-20 max-w-[1200px] mx-auto w-full flex items-center flex-col">
<p className="mb-4 text-center text-[24px] md:text-[40px] text-white">Unlock Financial Freedom with Expensasaures</p>
<p className="mb-6 text-center text-[18px] md:text-[24px] max-w-[90%] md:max-w-[80%] text-white">Start managing your budget effectively with Expensasaures.<br /> Sign up today and gain control over your financial future.</p>
<Link href='/signup'>
<Button
type="button"
className="mt-2 border-0 w-min px-10 py-4 rounded-xl bg-white md:text-base font-medium text-blue-700 transition duration-200 hover:bg-white active:bg-white"
>
Sign Up Now
</Button>
</Link>
</div>

</div>
)
}

export default CTASection
144 changes: 144 additions & 0 deletions src/components/landing/budgetmanagement/Features.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"use client";

import classNames from "classnames";
import { useInView } from "react-intersection-observer";

type FeaturesProps = {
children: React.ReactNode;
color: string;
colorDark: string;
};

export const Features = ({ children, color, colorDark }: FeaturesProps) => {
const { ref, inView } = useInView({ threshold: 0.2, triggerOnce: false });

return (
<section
id="budget"
ref={ref}
className={classNames(
"w-[100vw]",
"after:bg-[radial-gradient(ellipse_100%_40%_at_50%_60%,rgba(var(--feature-color),0.1),transparent) relative flex flex-col items-center overflow-x-clip",
"before:pointer-events-none before:absolute before:h-[400px] before:w-full",
"before:bg-[conic-gradient(from_90deg_at_80%_50%,#f2f2f2,rgb(var(--feature-color-dark))),conic-gradient(from_270deg_at_20%_50%,rgb(var(--feature-color-dark)),#f2f2f2)]",
"before:bg-no-repeat before:transition-[transform,opacity] before:duration-1000 before:ease-in before:[mask:radial-gradient(100%_50%_at_center_center,_black,_transparent)]",
"before:[background-size:50%_100%,50%_100%] before:[background-position:1%_0%,99%_0%] after:pointer-events-none after:absolute after:inset-0",
inView &&
"is-visible before:opacity-100 before:[transform:rotate(180deg)_scale(2)]",
!inView && "before:rotate-180 before:opacity-40"
)}
style={
{
"--feature-color": color,
"--feature-color-dark": colorDark,
} as React.CSSProperties
}
>
<div className="mt-[128px] w-full md:mt-[252px]">
{children}
</div>
</section>
);
};

type MainFeatureProps = {
image: string;
text: string;
title: React.ReactNode;
imageSize?: "small" | "large";
};

const MainFeature = ({
image,
text,
title,
imageSize = "small",
}: MainFeatureProps) => {
return (
<>
<div className="relative before:absolute before:inset-0 before:bg-[radial-gradient(ellipse_50%_50%_at_center,rgba(var(--feature-color),0.1),transparent)]">
<div
className={classNames(
"text-center mx-auto max-w-[1200px] px-8",
imageSize === "small" ? "lg:w-[780px]" : "lg:w-[1024px]"
)}
>
<h2 className="text-white leading-[1.2] mb-11 translate-y-[40%] pt-[120px] text-center text-[32px] md:text-[72px] [transition:transform_1000ms_cubic-bezier(0.3,_1.17,_0.55,_0.99)_0s] md:pt-0 [.is-visible_&]:translate-y-0">
{title}
</h2>
<div className="relative z-10 rounded-[14px] backdrop-blur-[6px] before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:bg-[linear-gradient(rgba(255,_255,_255,_0.3),_rgba(255,_255,_255,_0)_120%)] before:p-[1px] before:[mask:linear-gradient(black,_black)_content-box_content-box,_linear-gradient(black,_black)] before:[mask-composite:xor] after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:bg-[rgba(255,_255,_255,_0.15)] after:[mask:linear-gradient(black,transparent)]">
<img src={image} className="h-auto w-full p-6 rounded-[10px]" />
</div>
</div>
</div>
<div className="w-full mx-auto max-w-[87%] md:max-w-[78%] text-center">
<p className="mx-auto my-16 text-[20px] md:text-[32px] leading-tight text-slate-600 md:w-[80%]">
{text}
</p>
<hr className="mb-[72px] h-[1px] border-none bg-[linear-gradient(to_right,transparent,#2152ff_50%,transparent)]" />
</div>
</>
);
};

type FeatureGridProps = {
features: {
icon: React.FC;
title: string;
text: string;
}[];
};

const FeatureGrid = ({ features }: FeatureGridProps) => {
return (
<div className="mx-auto max-w-[1200px] px-8">
<div className="mb-16 grid w-full grid-cols-2 place-items-center gap-x-2 md:gap-x-0 gap-y-9 text-sm text-slate-700 md:mb-[140px] md:grid-cols-3 md:text-md">
{features.map(({ title, text, icon: Icon }) => (
<div
className="max-w-[256px] text-slate-700 text-[14px] md:text-[16px] w-full [&_svg]:mb-[4px] [&_svg]:text-slate-800 md:[&_svg]:mr-[6px] md:[&_svg]:mb-[2px] md:[&_svg]:inline"
key={title}
>
<Icon />
<span className="block text-slate-800 font-medium md:inline">{title}</span> {text}
</div>
))}
</div>
</div>
);
};


// type FeatureCardsProps = {
// features: {
// image: string;
// imageClassName: string;
// title: string;
// text: string;
// }[];
// };

// const FeatureCards = ({ features }: FeatureCardsProps) => {
// return (
// <div className="mx-auto max-w-[1200px] px-8">
// <div className="grid w-full grid-cols-1 gap-6 md:grid-cols-2">
// {features.map(({ title, text, image, imageClassName }) => (
// <div
// key={title}
// className="relative aspect-[1.1/1] overflow-hidden rounded-[2.4rem] border border-transparent-white bg-[radial-gradient(ellipse_at_center,rgba(var(--feature-color),0.15),transparent)] py-6 px-8 before:pointer-events-none before:absolute before:inset-0 before:bg-glass-gradient md:rounded-[4.8rem] md:p-14"
// >
// <h3 className="mb-2 text-2xl text-slate-600">{title}</h3>
// <p className="max-w-[31rem] text-md text-primary-text">{text}</p>
// <img
// className={classNames("absolute max-w-none", imageClassName)}
// src={image}
// />
// </div>
// ))}
// </div>
// </div>
// );
// };

Features.Main = MainFeature;
Features.Grid = FeatureGrid;
// Features.Cards = FeatureCards;
62 changes: 62 additions & 0 deletions src/components/landing/budgetmanagement/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"use client";

import { AiOutlineBarChart } from "react-icons/ai";
import { BiCategoryAlt } from "react-icons/bi";
import { GrAnalytics } from "react-icons/gr";
import { MdOutlineMoneyOffCsred } from "react-icons/md";
import { TbHeartRateMonitor } from "react-icons/tb";
import { Features } from "./Features";


export const BudgetManagement = () => {
return (
<Features color="#2152ff" colorDark="33,82,255">
<Features.Main
title={
<>
Seamless Budget
<br />
Control and Analysis
</>
}
image="/budget.png"
imageSize="large"
text="Set personalized budgets for different categories, such as food, transportation, entertainment, and more. Stay on track and monitor your progress to achieve your financial goals."
/>
<Features.Grid
features={[
{
icon: BiCategoryAlt,
title: "Category Overview.",
text: "Overview of categories, transactions, and expenses.",
},
{
icon: GrAnalytics,
title: "Category Analysis.",
text: "Analyze categories with graphical or tabular representation.",
},
{
icon: MdOutlineMoneyOffCsred,
title: "Categories with No Budget.",
text: "Identify spending without defined budgets.",
},
{
icon: TbHeartRateMonitor,
title: "Budget Status",
text: "Monitor budget limits and spending.",
},
{
icon: () => (<svg stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M448 160H320V128H448v32zM48 64C21.5 64 0 85.5 0 112v64c0 26.5 21.5 48 48 48H464c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48H48zM448 352v32H192V352H448zM48 288c-26.5 0-48 21.5-48 48v64c0 26.5 21.5 48 48 48H464c26.5 0 48-21.5 48-48V336c0-26.5-21.5-48-48-48H48z"></path></svg>),
title: "Progress Bar.",
text: "Visualize budget progress and consumption.",
},
{
icon: AiOutlineBarChart,
title: "Spending vs. Budget Graph",
text: "Compare actual spending with allocated budgets.",
},
]}
/>
</Features>
);
};
31 changes: 31 additions & 0 deletions src/components/landing/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Button } from "@tremor/react"
import Image from "next/image"
import Link from "next/link"

const Header = () => {
return (
<header className="flex mt-10 flex-col items-center justify-center">


<h1 className="text-blue-600 mb-4 text-center w-[80%] font-thin text-[40px] md:text-[60px]">
{/* Spending made smarter */}
Welcome to Expensasaures
</h1>
<h3 className="text-center w-[88%] md:w-[70%] text-[18px] md:text-[20px] mb-7 text-slate-700">Take control of your finances with Expensasaures, the ultimate budgeting tool. Our intuitive platform helps you track expenses, manage budgets, and achieve your financial goals. Get started today and experience hassle-free budget management.</h3>
<Link href='/signup'>
<Button
type="button"
className="border-0 w-min px-10 py-4 rounded-xl bg-blue-600 md:text-base font-medium text-white transition duration-200 hover:bg-blue-700 active:bg-blue-700"
>
Sign Up Now
</Button>
</Link>


<Image height={1000} className="mt-10" width={1000} alt="Mac Book and iPhone with expensasaures web application." priority src='/dashboard.png' />

</header>
)
}

export default Header
59 changes: 59 additions & 0 deletions src/components/landing/howitworks/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import Image from "next/image"

const HowItWorks = () => {
return (
<div className="relative w-full">
<div className="w-full pl-4 lg:max-w-[1200px] mx-auto pt-8 md:py-10">
<h4 className="text-[28px] text-center">How it works</h4>
<div className="w-full pt-8 md:py-10 flex flex-col md:flex-row items-center justify-between">
<div className="flex flex-col gap-10">
{howitWorksData.map(step => (
<div key={step.id} className="max-w-[29rem]">
<div className="text-[24px] mb-4 font-thin">{step.title}</div>
<div className="text-slate-700 text-[16px]">{step.description}</div>
</div>
))}
</div>
<div>
<Image alt="How it works." width={700} height={900} className="z-[-1] mt-4 md:mt-0 md:opacity-30 lg:opacity-100 md:absolute md:right-0 md:top-[50%] md:translate-y-[-50%]" src='/showcase1.png' />
</div>
</div>
</div>
</div>
)
}

const howitWorksData = [
{
id: 1,
title: 'Create an account',
description: 'Create your free account on Expensasaures by providing your basic details. It only takes a few minutes to get started.',
},
{
id: 2,
title: 'Set Your Budget',
description: 'Define your budget by allocating spending limits to different categories, such as food, transportation, entertainment, and more. Customize it to match your unique financial goals.',
},
{
id: 3,
title: 'Track Your Expenses and Income',
description: 'Enter your expenses and income with ease. Add transactions, categorize them, and keep a comprehensive record of your financial activities to maintain an accurate overview.',
},
{
id: 4,
title: 'Monitor Your Budget',
description: `Keep a close eye on your budget's progress with real-time updates. Visualize your spending patterns, track category-wise expenses, and receive notifications to stay within your limits.`,
},
{
id: 5,
title: 'Analyze Your Finances',
description: 'Gain valuable insights into your financial habits with our intuitive analysis tools. Explore interactive charts and reports to understand where your money is going and make informed decisions.',
},
{
id: 6,
title: 'Adjust and Optimize',
description: 'Fine-tune your budget as needed based on your financial goals and changing circumstances. Modify spending limits, add new categories, or reallocate funds to optimize your budget.'
}
]

export default HowItWorks
2 changes: 1 addition & 1 deletion src/components/layout/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const MainLayout = (props: Props) => {
if (!user) {
const userAfterFetch = await getUser();
if (!userAfterFetch) {
router.push(router.route === '/signup' ? router.route : '/login')
router.push(router.route === '/signup' || router.route === '/login' || router.route === '/' ? router.route : '/login')
}
} else {
router.push('/dashboard')
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/LeftSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const LeftSidebar = (props: Props) => {
const { showMenu, onCloseMenu, children } = props
const ref = useRef<HTMLDivElement>() as RefObject<HTMLDivElement>;
let classes = clsx(
'absolute lg:static inset-0 lg:pt-0 py-[100px] lg:px-0 overflow-y-auto px-4 transform duration-300 lg:relative lg:translate-x-0 bg-black lg:bg-transparent flex flex-col flex-shrink-0 w-[280px] font-sans text-sm text-gray-700 border-r sm:border-0 border-gray-100 lg:shadow-none justify-items-start',
'absolute lg:static inset-0 lg:pt-0 py-[100px] lg:px-0 overflow-y-auto px-4 transform duration-300 lg:relative lg:translate-x-0 dark:bg-black lg:bg-transparent flex flex-col flex-shrink-0 w-[280px] font-sans text-sm text-gray-700 border-r sm:border-0 border-gray-100 lg:shadow-none justify-items-start',
!showMenu && '-translate-x-full ease-out shadow-none',
showMenu && 'translate-x-0 ease-in shadow-xl',
);
Expand Down
2 changes: 1 addition & 1 deletion src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function App({ Component, pageProps }: AppProps) {
<>
<QueryClientProvider client={queryClient}>
<Hydrate state={pageProps.dehydratedState}>
<Toaster richColors closeButton />
<Toaster duration={3000} richColors closeButton />
<Component {...pageProps} />
<ReactQueryDevtools initialIsOpen={false} />
</Hydrate>
Expand Down
29 changes: 19 additions & 10 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import Navigation from "expensasaures/components/Navigation";
import CTASection from "expensasaures/components/landing/CTASection";
import { BudgetManagement } from "expensasaures/components/landing/budgetmanagement";
import Footer from "expensasaures/components/landing/footer";
import Header from "expensasaures/components/landing/header";
import HowItWorks from "expensasaures/components/landing/howitworks";
import MainLayout from "expensasaures/components/layout/MainLayout";

export default function Home() {
return (
<main
className={`flex min-h-screen flex-col items-center justify-between`}
>
<div className="p-24">
<Navigation landingPage />
</div>

<Footer />

</main>
<MainLayout>
<main
className={`flex min-h-screen flex-col items-center justify-between`}
>
<div className="pt-navigation-height">
<Navigation landingPage />
</div>
<Header />
<HowItWorks />
<BudgetManagement />
<CTASection />
<Footer />
</main>
</MainLayout>
);
}
Loading

1 comment on commit e51b683

@vercel
Copy link

@vercel vercel bot commented on e51b683 Jun 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.