diff --git a/apps/www/app/(marketing)/page.tsx b/apps/www/app/(marketing)/page.tsx index 79f2943c..def68183 100644 --- a/apps/www/app/(marketing)/page.tsx +++ b/apps/www/app/(marketing)/page.tsx @@ -1,20 +1,28 @@ +import Image from "next/image"; import Link from "next/link"; import { auth } from "@clerk/nextjs"; import Balancer from "react-wrap-balancer"; import { cn } from "@/lib/utils"; import { buttonVariants } from "@/components/ui/button"; +import { + MovingBorderImage, + MovingButton, +} from "@/components/ui/moving-borders"; import { GetStartedButton } from "@/components/buttons/GetStartedButton"; +import BentoGridSection from "@/components/dashboard/bentogrid"; import { BusinessLine } from "@/components/dashboard/businessline"; import CallToActionComponent from "@/components/dashboard/calltoaction"; import Featuressection from "@/components/dashboard/feautressection"; +import { HeroHighlightSection } from "@/components/dashboard/hero-highlight-section"; +import LampSection from "@/components/dashboard/lamp"; import { Icons } from "@/components/shared/icons"; export default async function IndexPage() { const { userId } = auth(); return ( <> -
+
+
+ +
+
+
- -
- -
+ + {/* */} + +
- +
+
{/* */}
+
{/* */}
{/*
*/} diff --git a/apps/www/components/dashboard/bentogrid.tsx b/apps/www/components/dashboard/bentogrid.tsx new file mode 100644 index 00000000..f3b8b760 --- /dev/null +++ b/apps/www/components/dashboard/bentogrid.tsx @@ -0,0 +1,83 @@ +import Image from "next/image"; +import { LockClosedIcon } from "@radix-ui/react-icons"; +import { motion } from "framer-motion"; +import { + ArrowUpIcon, + CloudDownload, + CogIcon, + FingerprintIcon, + ServerIcon, +} from "lucide-react"; +import { Balancer } from "react-wrap-balancer"; + +import { BentoGridTemplate } from "./bentogrid/bentogrid"; + +export default function BentoGridSection() { + return ( +
+
+
+

+ +

+ The new +

+ +

+ Golden Standard +

+ +

+ + Projectx reimagines financial tracking and optimization with + leading-edge AI, offering a new era of precision and ease in + personal finance. + +

+
+
+
+ +
+
+ ); +} + +///////////////////////////// +// If we want to make h1 like framer motion, we can use this code: +// +// The new +// + +// +// Golden Standard +// diff --git a/apps/www/components/dashboard/bentogrid/bento-grid.tsx b/apps/www/components/dashboard/bentogrid/bento-grid.tsx new file mode 100644 index 00000000..881f642e --- /dev/null +++ b/apps/www/components/dashboard/bentogrid/bento-grid.tsx @@ -0,0 +1,54 @@ +import { cn } from "@/lib/utils"; + +export const BentoGrid = ({ + className, + children, +}: { + className?: string; + children?: React.ReactNode; +}) => { + return ( +
+ {children} +
+ ); +}; + +export const BentoGridItem = ({ + className, + title, + description, + header, + icon, +}: { + className?: string; + title?: string | React.ReactNode; + description?: string | React.ReactNode; + header?: React.ReactNode; + icon?: React.ReactNode; +}) => { + return ( +
+ {header} +
+ {icon} +
+ {title} +
+
+ {description} +
+
+
+ ); +}; diff --git a/apps/www/components/dashboard/bentogrid/bentogrid.tsx b/apps/www/components/dashboard/bentogrid/bentogrid.tsx new file mode 100644 index 00000000..74063274 --- /dev/null +++ b/apps/www/components/dashboard/bentogrid/bentogrid.tsx @@ -0,0 +1,341 @@ +"use client"; + +import React from "react"; +import Image from "next/image"; +import { motion } from "framer-motion"; +import { + Brain, + Calculator, + CheckCircle, + Frown, + Goal, + List, + Target, + TrendingUp, + User, + XCircle, +} from "lucide-react"; + +import { cn } from "@/lib/utils"; + +import { BentoGrid, BentoGridItem } from "./bento-grid"; + +export function BentoGridTemplate() { + return ( + + {items.map((item, i) => ( + p:text-lg]", item.className)} + icon={item.icon} + /> + ))} + + ); +} +const Skeleton = () => ( +
+); + +const SkeletonOne = () => { + const variants = { + initial: { + x: 0, + }, + animate: { + x: 10, + rotate: 5, + transition: { + duration: 0.2, + }, + }, + }; + const variantsSecond = { + initial: { + x: 0, + }, + animate: { + x: -10, + rotate: -5, + transition: { + duration: 0.2, + }, + }, + }; + + return ( + + +
+
+ + +
+
+ + +
+
+ + + ); +}; +const SkeletonTwo = () => { + const variants = { + initial: { + width: 0, + }, + animate: { + width: "100%", + transition: { + duration: 0.2, + }, + }, + hover: { + width: ["0%", "100%"], + transition: { + duration: 2, + }, + }, + }; + const arr = new Array(6).fill(0); + return ( + + {arr.map((_, i) => ( + + ))} + + ); +}; +const SkeletonThree = () => { + const variants = { + initial: { + backgroundPosition: "0 50%", + }, + animate: { + backgroundPosition: ["0, 50%", "100% 50%", "0 50%"], + }, + }; + return ( + + + + ); +}; +const SkeletonFour = () => { + const first = { + initial: { + x: 20, + rotate: -5, + }, + hover: { + x: 0, + rotate: 0, + }, + }; + const second = { + initial: { + x: -20, + rotate: 5, + }, + hover: { + x: 0, + rotate: 0, + }, + }; + return ( + + + +

+ Your not going to meet your goal +

+

+ Take action +

+
+ + +

+ On your way to meet your goal +

+

+ On Track +

+
+ + +

+ Your going to miss your goal this month +

+

+ Helpless +

+
+
+ ); +}; +const SkeletonFive = () => { + const variants = { + initial: { + x: 0, + }, + animate: { + x: 10, + rotate: 5, + transition: { + duration: 0.2, + }, + }, + }; + const variantsSecond = { + initial: { + x: 0, + }, + animate: { + x: -10, + rotate: -5, + transition: { + duration: 0.2, + }, + }, + }; + + return ( + + + +

+ What should i do to save more money? +

+
+ +

Use Badget.

+
+ + + ); +}; +const items = [ + { + title: "Predictive Budgeting", + description: ( + + Get AI-powered suggestions based on your purchase history. + + ), + header: , + className: "md:col-span-1", + icon: , + }, + { + title: "All your transactions", + description: ( + + See all your transactions in one place, and get insights. + + ), + header: , + className: "md:col-span-1", + icon: , + }, + { + title: "Investment Simulator", + description: ( + + Simulate your investments and see how they will grow over time. + + ), + header: , + className: "md:col-span-1", + icon: , + }, + { + title: "Goal-Setting and Tracking", + description: ( + + Track your goals and get suggestions on how to achieve them faster. Let + Badget help you stay on track. + + ), + header: , + className: "md:col-span-2", + icon: , + }, + + { + title: "AI helper", + description: ( + + Let Badget help you with your financial decisions. + + ), + header: , + className: "md:col-span-1", + icon: , + }, +]; diff --git a/apps/www/components/dashboard/hero-highlight-section.tsx b/apps/www/components/dashboard/hero-highlight-section.tsx new file mode 100644 index 00000000..2e899a76 --- /dev/null +++ b/apps/www/components/dashboard/hero-highlight-section.tsx @@ -0,0 +1,33 @@ +"use client"; + +import { motion } from "framer-motion"; + +import { HeroHighlightComponent, Highlight } from "../ui/hero-highlight"; + +export function HeroHighlightSection() { + return ( + + + With Badget,you're going to save money. Every{" "} + + day, week, month + + + + ); +} diff --git a/apps/www/components/dashboard/lamp.tsx b/apps/www/components/dashboard/lamp.tsx new file mode 100644 index 00000000..1faf98bd --- /dev/null +++ b/apps/www/components/dashboard/lamp.tsx @@ -0,0 +1,22 @@ +import Image from "next/image"; +import { LockClosedIcon } from "@radix-ui/react-icons"; +import { + ArrowUpIcon, + CloudDownload, + CogIcon, + FingerprintIcon, + ServerIcon, +} from "lucide-react"; +import { Balancer } from "react-wrap-balancer"; + +import { LampTemplate } from "../ui/lamp"; +import { MovingButton } from "../ui/moving-borders"; +import { BentoGridTemplate } from "./bentogrid/bentogrid"; + +export default function LampSection() { + return ( +
+ +
+ ); +} diff --git a/apps/www/components/ui/hero-highlight.tsx b/apps/www/components/ui/hero-highlight.tsx new file mode 100644 index 00000000..5ecdf87c --- /dev/null +++ b/apps/www/components/ui/hero-highlight.tsx @@ -0,0 +1,98 @@ +"use client"; + +import React from "react"; +import { motion, useMotionTemplate, useMotionValue } from "framer-motion"; + +import { cn } from "@/lib/utils"; + +export const HeroHighlightComponent = ({ + children, + className, + containerClassName, +}: { + children: React.ReactNode; + className?: string; + containerClassName?: string; +}) => { + let mouseX = useMotionValue(0); + let mouseY = useMotionValue(0); + + function handleMouseMove({ + currentTarget, + clientX, + clientY, + }: React.MouseEvent) { + if (!currentTarget) return; + let { left, top } = currentTarget.getBoundingClientRect(); + + mouseX.set(clientX - left); + mouseY.set(clientY - top); + } + return ( +
+
+ + +
{children}
+
+ ); +}; + +export const Highlight = ({ + children, + className, +}: { + children: React.ReactNode; + className?: string; +}) => { + return ( + + {children} + + ); +}; diff --git a/apps/www/components/ui/lamp.tsx b/apps/www/components/ui/lamp.tsx new file mode 100644 index 00000000..20bd0443 --- /dev/null +++ b/apps/www/components/ui/lamp.tsx @@ -0,0 +1,106 @@ +"use client"; + +import React from "react"; +import { motion } from "framer-motion"; + +import { cn } from "@/lib/utils"; + +export function LampTemplate() { + return ( + + + Make your
Badget count +
+
+ ); +} + +export const LampContainer = ({ + children, + className, +}: { + children: React.ReactNode; + className?: string; +}) => { + return ( +
+
+ +
+
+ + +
+
+ +
+
+
+ + + +
+
+ +
+ {children} +
+
+ ); +}; diff --git a/apps/www/components/ui/moving-borders.tsx b/apps/www/components/ui/moving-borders.tsx new file mode 100644 index 00000000..1858cd00 --- /dev/null +++ b/apps/www/components/ui/moving-borders.tsx @@ -0,0 +1,187 @@ +"use client"; + +import React, { useRef } from "react"; +import Image from "next/image"; +import { + motion, + useAnimationFrame, + useMotionTemplate, + useMotionValue, + useTransform, +} from "framer-motion"; + +import { cn } from "@/lib/utils"; + +export function MovingButton({ + borderRadius = "1.75rem", + children, + as: Component = "button", + containerClassName, + borderClassName, + duration, + className, + ...otherProps +}: { + borderRadius?: string; + children: React.ReactNode; + as?: any; + containerClassName?: string; + borderClassName?: string; + duration?: number; + className?: string; + [key: string]: any; +}) { + return ( + +
+ +
+ +
+ +
+ {children} +
+ + ); +} + +//TODO: Add a border to the image + +export function MovingBorderImage({ + src, + alt, + imageClassName, + borderClassName, + duration, +}: { + src: string; + alt: string; + imageClassName?: string; + borderClassName?: string; + duration?: number; +}) { + return ( +
+ +
+ + + {alt} +
+ ); +} + +export const MovingBorder = ({ + children, + duration = 2000, + rx, + ry, + ...otherProps +}: { + children: React.ReactNode; + duration?: number; + rx?: string; + ry?: string; + [key: string]: any; +}) => { + const pathRef = useRef(); + const progress = useMotionValue(0); + + useAnimationFrame((time) => { + const length = pathRef.current?.getTotalLength(); + if (length) { + const pxPerMillisecond = length / duration; + progress.set((time * pxPerMillisecond) % length); + } + }); + + const x = useTransform( + progress, + (val) => pathRef.current?.getPointAtLength(val).x, + ); + const y = useTransform( + progress, + (val) => pathRef.current?.getPointAtLength(val).y, + ); + + const transform = useMotionTemplate`translateX(${x}px) translateY(${y}px) translateX(-50%) translateY(-50%)`; + + return ( + <> + + + + + {children} + + + ); +}; diff --git a/apps/www/next.config.js b/apps/www/next.config.js index a12ac6c4..f4ebefd3 100644 --- a/apps/www/next.config.js +++ b/apps/www/next.config.js @@ -45,6 +45,10 @@ const config = { protocol: "https", hostname: "raw.githubusercontent.com", }, + { + protocol: "https", + hostname: "github.com", + }, // TODO: remove code below { protocol: "https", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 882a2018..eff91f08 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,9 +1,5 @@ lockfileVersion: '6.0' -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - importers: .: @@ -677,7 +673,7 @@ importers: version: 1.12.4(eslint@8.57.0) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.1.0)(eslint@8.57.0) + version: 2.29.1(@typescript-eslint/parser@6.19.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: specifier: ^6.8.0 version: 6.8.0(eslint@8.57.0) @@ -730,6 +726,9 @@ importers: autoprefixer: specifier: ^10.4.17 version: 10.4.17(postcss@8.4.35) + mini-svg-data-uri: + specifier: ^1.4.4 + version: 1.4.4 postcss: specifier: 8.4.35 version: 8.4.35 @@ -6573,35 +6572,6 @@ packages: - supports-color dev: false - /eslint-module-utils@2.8.0(@typescript-eslint/parser@7.1.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3) - debug: 3.2.7 - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - dev: false - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.19.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} @@ -6637,41 +6607,6 @@ packages: - supports-color dev: false - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0)(eslint@8.57.0): - resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - dependencies: - '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3) - array-includes: 3.1.7 - array.prototype.findlastindex: 1.2.3 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) - hasown: 2.0.0 - is-core-module: 2.13.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.7 - object.groupby: 1.0.1 - object.values: 1.1.7 - semver: 6.3.1 - tsconfig-paths: 3.15.0 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - dev: false - /eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0): resolution: {integrity: sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==} engines: {node: '>=4.0'} @@ -9212,6 +9147,11 @@ packages: engines: {node: '>=4'} dev: false + /mini-svg-data-uri@1.4.4: + resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} + hasBin: true + dev: false + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -12120,3 +12060,7 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false diff --git a/tooling/tailwind/index.ts b/tooling/tailwind/index.ts index 2920ea25..efc12178 100644 --- a/tooling/tailwind/index.ts +++ b/tooling/tailwind/index.ts @@ -1,6 +1,10 @@ import type { Config } from "tailwindcss"; import { fontFamily } from "tailwindcss/defaultTheme"; +const svgToDataUri = require("mini-svg-data-uri"); + +const colors = require("tailwindcss/colors"); + const { default: flattenColorPalette, } = require("tailwindcss/lib/util/flattenColorPalette"); @@ -141,13 +145,49 @@ const config = { }, }, }, - plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography"), addVariablesForColors], + plugins: [ + require("tailwindcss-animate"), + require("@tailwindcss/typography"), + addVariablesForColors, + function ({ matchUtilities, theme }: any) { + matchUtilities( + { + "bg-grid": (value: any) => ({ + backgroundImage: `url("${svgToDataUri( + ``, + )}")`, + }), + "bg-grid-small": (value: any) => ({ + backgroundImage: `url("${svgToDataUri( + ``, + )}")`, + }), + "bg-dot": (value: any) => ({ + backgroundImage: `url("${svgToDataUri( + ``, + )}")`, + }), + }, + { + "bg-dot-thick": (value: any) => ({ + backgroundImage: `url("${svgToDataUri( + ``, + )}")`, + }), + }, + { + values: flattenColorPalette(theme("backgroundColor")), + type: "color", + }, + ); + }, + ], } satisfies Config; function addVariablesForColors({ addBase, theme }: any) { let allColors = flattenColorPalette(theme("colors")); let newVars = Object.fromEntries( - Object.entries(allColors).map(([key, val]) => [`--${key}`, val]) + Object.entries(allColors).map(([key, val]) => [`--${key}`, val]), ); addBase({ diff --git a/tooling/tailwind/package.json b/tooling/tailwind/package.json index f71a41ec..b44f84aa 100644 --- a/tooling/tailwind/package.json +++ b/tooling/tailwind/package.json @@ -15,6 +15,7 @@ }, "dependencies": { "autoprefixer": "^10.4.17", + "mini-svg-data-uri": "^1.4.4", "postcss": "8.4.35", "tailwindcss": "^3.4.1" },