add website to repo
Made-with: Cursor
41
apps/website/.gitignore
vendored
Executable file
@@ -0,0 +1,41 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# env files (can opt-in for committing if needed)
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
44
apps/website/README.md
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
This is a [Next.js](https://nextjs.org) project bootstrapped with `[create-next-app](https://github.com/vercel/next.js/tree/canary/packages/create-next-app)`.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
First, run the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# or
|
||||||
|
yarn dev
|
||||||
|
# or
|
||||||
|
pnpm dev
|
||||||
|
# or
|
||||||
|
bun dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
|
|
||||||
|
You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
|
||||||
|
|
||||||
|
This project uses `[next/font](https://nextjs.org/docs/app/building-your-application/optimizing/fonts)` to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
To learn more about Next.js, take a look at the following resources:
|
||||||
|
|
||||||
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
|
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||||
|
|
||||||
|
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||||
|
|
||||||
|
## Deploy on Vercel
|
||||||
|
|
||||||
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||||
|
|
||||||
|
Designed by
|
||||||
|
|
||||||
|
██████ ██ ██ ██ ███████ ██ ██ ██ ██████ ██ █████ ██████ ███████
|
||||||
|
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||||
|
██████ ██ ███ █████ ██ ██ ██ ██████ ██ ███████ ██████ ███████
|
||||||
|
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||||
|
██ ██ ██ ██ ███████ ███████ ██████ ██ ███████ ██ ██ ██████ ███████
|
||||||
1317
apps/website/app/constant.js
Executable file
BIN
apps/website/app/favicon.ico
Executable file
|
After Width: | Height: | Size: 4.2 KiB |
237
apps/website/app/globals.css
Executable file
@@ -0,0 +1,237 @@
|
|||||||
|
/* @import "tailwindcss";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background: #ffffff;
|
||||||
|
--foreground: #171717;
|
||||||
|
}
|
||||||
|
|
||||||
|
@theme inline {
|
||||||
|
--color-background: var(--background);
|
||||||
|
--color-foreground: var(--foreground);
|
||||||
|
--font-sans: var(--font-geist-sans);
|
||||||
|
--font-mono: var(--font-geist-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--background: #0a0a0a;
|
||||||
|
--foreground: #ededed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--background);
|
||||||
|
color: var(--foreground);
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
} */
|
||||||
|
|
||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
RAW TOKENS — single source of truth
|
||||||
|
⚠️ All hex values marked "verify" are best-guesses from the screenshot.
|
||||||
|
Confirm against Figma before shipping.
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* --- Fonts ---------------------------------------------------------------- */
|
||||||
|
--font-geist-sans: "Geist", sans-serif; /* injected by next/font or CDN */
|
||||||
|
--font-geist-mono: "Geist Mono", monospace;
|
||||||
|
|
||||||
|
/* --- Font weights --------------------------------------------------------- */
|
||||||
|
--font-weight-light: 300;
|
||||||
|
--font-weight-regular: 400;
|
||||||
|
--font-weight-medium: 500;
|
||||||
|
--font-weight-semibold: 600;
|
||||||
|
--font-weight-bold: 700;
|
||||||
|
|
||||||
|
/* --- Type scale: Display (desktop) --------------------------------------- */
|
||||||
|
--text-display-1: 4.5rem; /* verify */
|
||||||
|
--leading-display-1: 1.1;
|
||||||
|
--text-display-2: 3.5rem; /* verify */
|
||||||
|
--leading-display-2: 1.1;
|
||||||
|
--text-display-3: 2.5rem; /* verify */
|
||||||
|
--leading-display-3: 1.15;
|
||||||
|
--text-display-4: 2rem; /* verify */
|
||||||
|
--leading-display-4: 1.2;
|
||||||
|
--text-display-5: 1.5rem; /* verify */
|
||||||
|
--leading-display-5: 1.25;
|
||||||
|
|
||||||
|
/* --- Type scale: Body ----------------------------------------------------- */
|
||||||
|
--text-body-18: 1.125rem;
|
||||||
|
--leading-body-18: 1.6;
|
||||||
|
--text-body-16: 1rem;
|
||||||
|
--leading-body-16: 1.6;
|
||||||
|
--text-body-14: 0.875rem;
|
||||||
|
--leading-body-14: 1.5;
|
||||||
|
|
||||||
|
/* --- Type scale: Label (Geist Mono) --------------------------------------- */
|
||||||
|
--text-label-32: 2rem;
|
||||||
|
--text-label-14: 0.875rem;
|
||||||
|
--leading-label: 1.4;
|
||||||
|
|
||||||
|
/* --- Surface / Neutral ---------------------------------------------------- */
|
||||||
|
--color-surface-primary: #7c3aed; /* brand purple — verify */
|
||||||
|
--color-surface-950: #0f0f0f;
|
||||||
|
--color-surface-900: #1c1c1c; /* verify */
|
||||||
|
--color-surface-800: #2c2c2c; /* verify */
|
||||||
|
--color-surface-600: #3f3f3f;
|
||||||
|
--color-surface-200: #d1d1d1; /* verify */
|
||||||
|
--color-surface-100: #ececec; /* verify */
|
||||||
|
|
||||||
|
/* --- Brand: Pink ---------------------------------------------------------- */
|
||||||
|
--color-pink-dark: #ec0267; /* verify */
|
||||||
|
--color-pink-base: #f60060; /* verify */
|
||||||
|
--color-pink-light: #f860c4; /* verify */
|
||||||
|
--color-pink-light-1: #fbc8e0; /* verify */
|
||||||
|
|
||||||
|
/* --- Brand: Blue ---------------------------------------------------------- */
|
||||||
|
--color-blue-dark: #3f0cf3; /* verify */
|
||||||
|
--color-blue-base: #4040f0; /* verify */
|
||||||
|
--color-blue-light: #8080f5; /* verify */
|
||||||
|
--color-blue-light-1: #b8b8ff; /* verify */
|
||||||
|
|
||||||
|
/* --- Brand: Purple -------------------------------------------------------- */
|
||||||
|
--color-purple-dark: #6f0cf8; /* verify */
|
||||||
|
--color-purple-base: #8f3cf8; /* verify */
|
||||||
|
--color-purple-light: #b040f8; /* verify */
|
||||||
|
--color-purple-light-1: #d4b0ff; /* verify */
|
||||||
|
|
||||||
|
/* --- Legacy Next.js scaffold (kept for compatibility) --------------------- */
|
||||||
|
--background: #ffffff;
|
||||||
|
--foreground: #171717;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--background: #0a0a0a;
|
||||||
|
--foreground: #ededed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
:root {
|
||||||
|
--text-display-1: 3.5rem; /* verify */
|
||||||
|
--text-display-2: 2.5rem; /* verify */
|
||||||
|
--text-display-3: 2rem; /* verify */
|
||||||
|
--text-display-4: 1.5rem; /* verify */
|
||||||
|
--text-display-5: 1.25rem; /* verify */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
TAILWIND v4 THEME — maps raw tokens → utility classes
|
||||||
|
Everything in @theme becomes a Tailwind utility automatically:
|
||||||
|
--color-* → bg-*, text-*, border-*, ring-*, fill-*, stroke-*
|
||||||
|
--font-* → font-*
|
||||||
|
--text-* → text-* (when paired with a size value)
|
||||||
|
--leading-* → leading-*
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
@theme inline {
|
||||||
|
/* Background & foreground (Next.js scaffold) */
|
||||||
|
--color-background: var(--background);
|
||||||
|
--color-foreground: var(--foreground);
|
||||||
|
|
||||||
|
/* Fonts */
|
||||||
|
--font-sans: var(--font-geist-sans);
|
||||||
|
--font-mono: var(--font-geist-mono);
|
||||||
|
|
||||||
|
/* Surface / Neutral */
|
||||||
|
--color-surface-primary: var(--color-surface-primary);
|
||||||
|
--color-surface-950: var(--color-surface-950);
|
||||||
|
--color-surface-900: var(--color-surface-900);
|
||||||
|
--color-surface-800: var(--color-surface-800);
|
||||||
|
--color-surface-600: var(--color-surface-600);
|
||||||
|
--color-surface-200: var(--color-surface-200);
|
||||||
|
--color-surface-100: var(--color-surface-100);
|
||||||
|
|
||||||
|
/* Brand: Pink */
|
||||||
|
--color-pink-dark: var(--color-pink-dark);
|
||||||
|
--color-pink-base: var(--color-pink-base);
|
||||||
|
--color-pink-light: var(--color-pink-light);
|
||||||
|
--color-pink-light-1: var(--color-pink-light-1);
|
||||||
|
|
||||||
|
/* Brand: Blue */
|
||||||
|
--color-blue-dark: var(--color-blue-dark);
|
||||||
|
--color-blue-base: var(--color-blue-base);
|
||||||
|
--color-blue-light: var(--color-blue-light);
|
||||||
|
--color-blue-light-1: var(--color-blue-light-1);
|
||||||
|
|
||||||
|
/* Brand: Purple */
|
||||||
|
--color-purple-dark: var(--color-purple-dark);
|
||||||
|
--color-purple-base: var(--color-purple-base);
|
||||||
|
--color-purple-light: var(--color-purple-light);
|
||||||
|
--color-purple-light-1: var(--color-purple-light-1);
|
||||||
|
|
||||||
|
/* Type scale — Display */
|
||||||
|
--text-display-1: var(--text-display-1);
|
||||||
|
--text-display-2: var(--text-display-2);
|
||||||
|
--text-display-3: var(--text-display-3);
|
||||||
|
--text-display-4: var(--text-display-4);
|
||||||
|
--text-display-5: var(--text-display-5);
|
||||||
|
|
||||||
|
/* Type scale — Body */
|
||||||
|
--text-body-18: var(--text-body-18);
|
||||||
|
--text-body-16: var(--text-body-16);
|
||||||
|
--text-body-14: var(--text-body-14);
|
||||||
|
|
||||||
|
/* Type scale — Label */
|
||||||
|
--text-label-32: var(--text-label-32);
|
||||||
|
--text-label-14: var(--text-label-14);
|
||||||
|
|
||||||
|
/* Leading */
|
||||||
|
--leading-display-1: var(--leading-display-1);
|
||||||
|
--leading-display-2: var(--leading-display-2);
|
||||||
|
--leading-display-3: var(--leading-display-3);
|
||||||
|
--leading-display-4: var(--leading-display-4);
|
||||||
|
--leading-display-5: var(--leading-display-5);
|
||||||
|
--leading-body-18: var(--leading-body-18);
|
||||||
|
--leading-body-16: var(--leading-body-16);
|
||||||
|
--leading-body-14: var(--leading-body-14);
|
||||||
|
--leading-label: var(--leading-label);
|
||||||
|
|
||||||
|
/* Font weights */
|
||||||
|
--font-weight-light: var(--font-weight-light);
|
||||||
|
--font-weight-regular: var(--font-weight-regular);
|
||||||
|
--font-weight-medium: var(--font-weight-medium);
|
||||||
|
--font-weight-semibold: var(--font-weight-semibold);
|
||||||
|
--font-weight-bold: var(--font-weight-bold);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
BASE STYLES
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--background);
|
||||||
|
color: var(--foreground);
|
||||||
|
font-family: var(--font-geist-sans);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.grid-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
/* pointer-events: none; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-overlay::before,
|
||||||
|
.grid-overlay::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 1px;
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* left floating line */
|
||||||
|
.grid-overlay::before {
|
||||||
|
left: 3%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* right floating line */
|
||||||
|
.grid-overlay::after {
|
||||||
|
right: 20%;
|
||||||
|
}
|
||||||
81
apps/website/app/layout.js
Executable file
@@ -0,0 +1,81 @@
|
|||||||
|
import { Geist, Geist_Mono } from "next/font/google";
|
||||||
|
import "./globals.css";
|
||||||
|
|
||||||
|
const geistSans = Geist({
|
||||||
|
variable: "--font-geist-sans",
|
||||||
|
subsets: ["latin"],
|
||||||
|
});
|
||||||
|
|
||||||
|
const geistMono = Geist_Mono({
|
||||||
|
variable: "--font-geist-mono",
|
||||||
|
subsets: ["latin"],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: {
|
||||||
|
default: "Autumn — Billing Infrastructure for AI Startups",
|
||||||
|
template: "%s | Autumn",
|
||||||
|
},
|
||||||
|
description:
|
||||||
|
"The drop-in billing layer for AI startups. Stop rebuilding usage limits, credit systems, and subscription logic. Autumn keeps webhooks, payments, and usage perfectly in-sync.",
|
||||||
|
keywords: [
|
||||||
|
"AI billing",
|
||||||
|
"usage-based billing",
|
||||||
|
"subscription management",
|
||||||
|
"AI startups",
|
||||||
|
"billing infrastructure",
|
||||||
|
"payment integration",
|
||||||
|
"usage limits",
|
||||||
|
"credit system",
|
||||||
|
],
|
||||||
|
authors: [{ name: "Autumn" }],
|
||||||
|
creator: "Autumn",
|
||||||
|
metadataBase: new URL("https://useautumn.com/"),
|
||||||
|
openGraph: {
|
||||||
|
type: "website",
|
||||||
|
locale: "en_US",
|
||||||
|
url: "https://useautumn.com/",
|
||||||
|
siteName: "Autumn",
|
||||||
|
title: "Autumn — Billing Infrastructure for AI Startups",
|
||||||
|
description:
|
||||||
|
"The drop-in billing layer for AI startups. Stop rebuilding usage limits, credit systems, and subscription logic.",
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: "/images/og-image.png",
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
alt: "Autumn — Billing Infrastructure for AI Startups",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary_large_image",
|
||||||
|
title: "Autumn — Billing Infrastructure for AI Startups",
|
||||||
|
description:
|
||||||
|
"The drop-in billing layer for AI startups. Stop rebuilding usage limits, credit systems, and subscription logic.",
|
||||||
|
images: ["/images/og-image.png"],
|
||||||
|
},
|
||||||
|
robots: {
|
||||||
|
index: true,
|
||||||
|
follow: true,
|
||||||
|
googleBot: {
|
||||||
|
index: true,
|
||||||
|
follow: true,
|
||||||
|
"max-video-preview": -1,
|
||||||
|
"max-image-preview": "large",
|
||||||
|
"max-snippet": -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RootLayout({ children }) {
|
||||||
|
return (
|
||||||
|
<html
|
||||||
|
lang="en"
|
||||||
|
suppressHydrationWarning
|
||||||
|
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
|
||||||
|
>
|
||||||
|
<body className="min-h-full flex flex-col">{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
111
apps/website/app/not-found.js
Executable file
@@ -0,0 +1,111 @@
|
|||||||
|
"use client";
|
||||||
|
import Navbar from "@/components/navbar";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { IconArrowRightSmall } from "@/app/constant";
|
||||||
|
import { motion } from "motion/react";
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="w-full min-h-screen overflow-x-hidden overflow-y-auto bg-[#0f0f0f] flex flex-col"
|
||||||
|
style={{ "--page-pad": "max(2.5rem, calc((100vw - 1440px) / 2))" }}
|
||||||
|
>
|
||||||
|
<div className="relative w-full px-4 md:px-(--page-pad) pt-5 flex-1 block">
|
||||||
|
<div className="absolute pointer-events-none top-0 bottom-0 left-4 md:left-(--page-pad) border-l border-[#292929] z-50" />
|
||||||
|
<div className="absolute pointer-events-none top-0 bottom-0 right-4 md:right-(--page-pad) border-r border-[#292929] z-50" />
|
||||||
|
|
||||||
|
<Navbar animateIntro={false} />
|
||||||
|
|
||||||
|
<div className="relative flex-1 w-full min-h-[calc(100vh-100px)] flex flex-col items-center justify-center -mt-[1px]">
|
||||||
|
<div className="absolute inset-0 w-full h-full z-0 overflow-hidden">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ duration: 1, ease: "easeOut" }}
|
||||||
|
className="absolute inset-0 w-full h-full"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/images/404.svg"
|
||||||
|
alt="404 Background City Base"
|
||||||
|
fill
|
||||||
|
className="object-cover object-center"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, display: "none" }}
|
||||||
|
animate={{
|
||||||
|
opacity: [0, 1, 0.8, 1, 0.6, 0],
|
||||||
|
display: ["block", "block", "block", "block", "block", "none"],
|
||||||
|
x: [0, -15, 20, -10, 15, 0],
|
||||||
|
y: [0, 8, -15, 5, -5, 0],
|
||||||
|
filter: [
|
||||||
|
"brightness(3) contrast(200%) hue-rotate(90deg)",
|
||||||
|
"brightness(2) contrast(300%) invert(30%)",
|
||||||
|
"brightness(1.5) contrast(150%) hue-rotate(-45deg)",
|
||||||
|
"brightness(3) contrast(200%) hue-rotate(180deg)",
|
||||||
|
"brightness(2) contrast(150%)",
|
||||||
|
"brightness(1)",
|
||||||
|
],
|
||||||
|
clipPath: [
|
||||||
|
"inset(10% 0% 60% 0%)",
|
||||||
|
"inset(20% 0% 30% 0%)",
|
||||||
|
"inset(80% 0% 5% 0%)",
|
||||||
|
"inset(40% 0% 40% 0%)",
|
||||||
|
"inset(5% 0% 80% 0%)",
|
||||||
|
"inset(0% 0% 0% 0%)",
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
transition={{
|
||||||
|
duration: 0.45,
|
||||||
|
ease: "easeInOut",
|
||||||
|
delay: 0.1,
|
||||||
|
times: [0, 0.2, 0.6, 0.75, 0.9, 1],
|
||||||
|
}}
|
||||||
|
className="absolute inset-0 w-full h-full mix-blend-screen pointer-events-none z-10"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/images/404.svg"
|
||||||
|
alt="404 Background City Glitch"
|
||||||
|
fill
|
||||||
|
className="object-cover object-center scale-105"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative z-10 flex flex-col items-center justify-center w-full px-4 text-center mt-[-40px]">
|
||||||
|
<Image
|
||||||
|
src="/images/autumn-notfound.svg"
|
||||||
|
alt="Autumn Logo"
|
||||||
|
width={64}
|
||||||
|
height={64}
|
||||||
|
className="w-[56px] h-[56px] md:w-[64px] md:h-[64px] mb-6"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<h1 className="text-white text-[48px] md:text-[64px] font-normal tracking-[-3%] mb-3 font-sans leading-[1.1]">
|
||||||
|
Page not found
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="text-[#FFFFFF99] font-light text-[15px] md:text-[18px] mb-8 tracking-[-1%] text-center">
|
||||||
|
The page you are looking for doesn't exist or has been moved.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Link href="/">
|
||||||
|
<button className="group relative flex items-stretch justify-between transition-colors duration-300 bg-[#8752FA] hover:bg-[#7641E8] w-[200px] md:w-[210px] h-[48px] md:h-[54px] border border-[#8752FA]">
|
||||||
|
<span className="text-white text-[14px] md:text-[15px] pl-6 flex items-center font-sans tracking-[-1%]">
|
||||||
|
Back to home
|
||||||
|
</span>
|
||||||
|
<div className="flex items-center justify-center w-[36px] md:w-[40px] transition-colors duration-300 bg-white text-[#8752FA] m-1 md:m-1.5 shrink-0">
|
||||||
|
<IconArrowRightSmall className="w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
42
apps/website/app/page.js
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
import ElasticRecoil from "@/components/elastic-footer";
|
||||||
|
import HomeSections from "@/components/home-sections";
|
||||||
|
import Navbar from "@/components/navbar";
|
||||||
|
import Preloader from "@/components/preloader";
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="w-full overflow-x-clip"
|
||||||
|
style={{ "--page-pad": "max(2.5rem, calc((100vw - 1440px) / 2))" }}
|
||||||
|
>
|
||||||
|
<Preloader />
|
||||||
|
<ElasticRecoil>
|
||||||
|
<div className="relative z-10 bg-[#000000] min-h-screen">
|
||||||
|
<div className="relative w-full px-4 md:px-(--page-pad) pt-5">
|
||||||
|
<div className="absolute pointer-events-none top-0 bottom-0 left-4 md:left-(--page-pad) border-l border-[#292929] z-50" />
|
||||||
|
<Navbar />
|
||||||
|
<div className="absolute pointer-events-none top-0 bottom-0 right-4 md:right-(--page-pad) border-r border-[#292929] z-50" />
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-2.5">
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full hidden md:block" />
|
||||||
|
<div className="border-t border-[#292929] w-full hidden md:block" />
|
||||||
|
<div className="border-t border-[#292929] w-full hidden md:block" />
|
||||||
|
<div className="border-t border-[#292929] w-full hidden md:block" />
|
||||||
|
</div>
|
||||||
|
<HomeSections />
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="w-full flex-col gap-2.5 mt-10.5 hidden md:flex">
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ElasticRecoil>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
191
apps/website/app/privacy/page.js
Executable file
@@ -0,0 +1,191 @@
|
|||||||
|
import AnimatedFooterImage from "@/components/animated-footer-image";
|
||||||
|
import Footer from "@/components/footer";
|
||||||
|
import Navbar from "@/components/navbar";
|
||||||
|
|
||||||
|
const privacyTerms = [
|
||||||
|
{
|
||||||
|
title: "1. Acceptance of Terms",
|
||||||
|
content:
|
||||||
|
'By accessing or using the Autumn platform, APIs, SDKs, or any related services (collectively, the "Services") provided by Rebase, Inc., a Delaware corporation ("Autumn," "we," "us," or "our"), you agree to be bound by these Terms of Service ("Terms"). If you do not agree to these Terms, do not use our Services.',
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "2. Description of Services",
|
||||||
|
content:
|
||||||
|
"Autumn provides billing infrastructure, including usage-based billing, credits management, pricing configuration, and entitlements management for software applications. Our Services are designed for developers and businesses building products that require flexible billing and pricing capabilities.",
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "3. Account Registration",
|
||||||
|
content:
|
||||||
|
"To use certain features of our Services, you must create an account. You agree to provide accurate, current, and complete information during registration and to update such information as necessary. You are responsible for maintaining the confidentiality of your account credentials and for all activities that occur under your account.",
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "4. Acceptable Use",
|
||||||
|
content:
|
||||||
|
"You agree not to use the Services for any unlawful purpose or in violation of any applicable laws; (b) interfere with or disrupt the integrity or performance of the Services; (c) attempt to gain unauthorized access to the Services or related systems; (d) use the Services to transmit malicious code or harmful content; or (e) resell or redistribute the Services without our prior written consent.",
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "5. Payment Terms",
|
||||||
|
content:
|
||||||
|
"Fees for the Services are set forth on our pricing page or in a separate agreement. You agree to pay all applicable fees in accordance with the payment terms. All fees are non-refundable except as expressly stated otherwise. We reserve the right to modify our pricing with 30 days' notice.",
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "6. Data and Privacy",
|
||||||
|
content:
|
||||||
|
'Your use of the Services is subject to our Privacy Policy. You retain ownership of any data you submit to the Services ("Customer Data"). You grant us a limited license to process Customer Data solely to provide the Services. We implement reasonable security measures to protect Customer Data, but you acknowledge that no system is completely secure.',
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "7. Intellectual Property",
|
||||||
|
content:
|
||||||
|
"The Services, including all software, APIs, documentation, and related materials, are owned by Autumn and protected by intellectual property laws. We grant you a limited, non-exclusive, non-transferable license to use the Services in accordance with these Terms. You may not copy, modify, or create derivative works of the Services except as expressly permitted.",
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "8. Confidentiality",
|
||||||
|
content:
|
||||||
|
"Each party agrees to maintain the confidentiality of any non-public information disclosed by the other party and to use such information only for the purposes of these Terms. This obligation does not apply to information that is publicly available, independently developed, or rightfully received from a third party.",
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "9. Warranties and Disclaimers",
|
||||||
|
content:
|
||||||
|
'THE SERVICES ARE PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. WE DO NOT WARRANT THAT THE SERVICES WILL BE UNINTERRUPTED OR ERROR-FREE.',
|
||||||
|
isUppercase: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "10. Limitation of Liability",
|
||||||
|
content:
|
||||||
|
"TO THE MAXIMUM EXTENT PERMITTED BY LAW, AUTUMN SHALL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, OR ANY LOSS OF PROFITS OR REVENUES. OUR TOTAL LIABILITY FOR ANY CLAIMS ARISING FROM THESE TERMS SHALL NOT EXCEED THE AMOUNTS PAID BY YOU TO AUTUMN IN THE TWELVE MONTHS PRECEDING THE CLAIM.",
|
||||||
|
isUppercase: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "11. Indemnification",
|
||||||
|
content:
|
||||||
|
"You agree to indemnify, defend, and hold harmless Autumn and its officers, directors, employees, and agents from any claims, liabilities, damages, losses, or expenses arising from your use of the Services, your violation of these Terms, or your infringement of any third-party rights.",
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "12. Term and Termination",
|
||||||
|
content:
|
||||||
|
"These Terms remain in effect until terminated. Either party may terminate for convenience with 30 days' written notice. We may suspend or terminate your access immediately if you breach these Terms. Upon termination, your right to use the Services ceases, and you must pay any outstanding fees.",
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "13. Modifications",
|
||||||
|
content:
|
||||||
|
"We may modify these Terms at any time by posting the revised Terms on our website. Material changes will be communicated with at least 30 days' notice. Your continued use of the Services after such changes constitutes acceptance of the modified Terms.",
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "14. Governing Law and Disputes",
|
||||||
|
content:
|
||||||
|
"These Terms are governed by the laws of the State of Delaware, without regard to conflict of law principles. Any disputes arising from these Terms shall be resolved through binding arbitration in accordance with the rules of the American Arbitration Association, except that either party may seek injunctive relief in any court of competent jurisdiction.",
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "15. General Provisions",
|
||||||
|
content:
|
||||||
|
"These Terms constitute the entire agreement between you and Autumn regarding the Services. If any provision is found unenforceable, the remaining provisions will continue in effect. Our failure to enforce any right or provision does not constitute a waiver. You may not assign these Terms without our prior written consent.",
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "16. Contact Information",
|
||||||
|
content: (
|
||||||
|
<>
|
||||||
|
For questions about these Terms, please contact us at
|
||||||
|
security@useautumn.com or at:
|
||||||
|
<br />
|
||||||
|
Rebase, Inc. (d/b/a Autumn)
|
||||||
|
<br />
|
||||||
|
Email: security@useautumn.com
|
||||||
|
<br />
|
||||||
|
Website: https://useautumn.com
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
isUppercase: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function PrivacyPolicy() {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="w-full overflow-x-hidden overflow-y-auto bg-[#000000]"
|
||||||
|
style={{ "--page-pad": "max(2.5rem, calc((100vw - 1440px) / 2))" }}
|
||||||
|
>
|
||||||
|
<div className="relative z-10 bg-[#000000] min-h-screen">
|
||||||
|
<div className="relative w-full px-4 md:px-(--page-pad) pt-5">
|
||||||
|
<div className="absolute pointer-events-none top-0 bottom-0 left-4 md:left-(--page-pad) border-l border-[#292929] z-50" />
|
||||||
|
<div className="absolute pointer-events-none left-0 border-t border-[#292929] w-full" />
|
||||||
|
<Navbar />
|
||||||
|
<div className="absolute pointer-events-none left-0 border-b border-[#292929] w-full" />
|
||||||
|
<div className="absolute pointer-events-none top-0 bottom-0 right-4 md:right-(--page-pad) border-r border-[#292929] z-50" />
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-2.5">
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full hidden md:block" />
|
||||||
|
<div className="border-t border-[#292929] w-full hidden md:block" />
|
||||||
|
<div className="border-t border-[#292929] w-full hidden md:block" />
|
||||||
|
<div className="border-t border-[#292929] w-full hidden md:block" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex w-full flex-col border-b border-[#292929]">
|
||||||
|
<div className="flex w-full border-b border-[#292929]">
|
||||||
|
<div className="hidden md:block w-1/8 lg:w-1/6 border-r bg-[#0F0F0F] border-[#292929]" />
|
||||||
|
<div className="flex-1 bg-[#0F0F0F] px-4 sm:px-8 py-10 md:py-16">
|
||||||
|
<h1 className="text-white text-[40px] font-sans tracking-[-2%] uppercase">
|
||||||
|
Terms of Service
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div className="hidden md:block w-1/8 lg:w-1/6 border-l bg-[#0F0F0F] border-[#292929]" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex w-full">
|
||||||
|
<div className="hidden md:block w-1/8 lg:w-1/6 border-r border-[#292929]" />
|
||||||
|
<div className="flex-1 px-4 sm:px-8 py-12 md:py-16 text-white text-[16px] font-light leading-[1.6] tracking-[-2%] font-sans pb-32">
|
||||||
|
<p className="mb-10">
|
||||||
|
Autumn (Rebase, Inc.)
|
||||||
|
<br />
|
||||||
|
Effective Date: February 1, 2025
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{privacyTerms.map((term, index) => (
|
||||||
|
<div key={index}>
|
||||||
|
<h3
|
||||||
|
className={`text-white font-normal text-[24px] leading-[30px] tracking-[-2%] mb-2 mt-8`}
|
||||||
|
>
|
||||||
|
{term.title}
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
className={`mb-6 font-light text-[16px] tracking-[-2%] leading-[20px] md:leading-[24px] ${term.isUppercase ? "uppercase" : ""}`}
|
||||||
|
>
|
||||||
|
{term.content}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="hidden md:block w-1/8 lg:w-1/6 border-l border-[#292929]" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-full flex-col gap-2.5 mt-10.5 hidden md:flex mb-4">
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-full aspect-390/313 sm:aspect-1440/619" />
|
||||||
|
<AnimatedFooterImage />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
31
apps/website/components/animated-footer-image.jsx
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
export default function AnimatedFooterImage() {
|
||||||
|
return (
|
||||||
|
<div className="fixed bottom-0 left-0 w-full z-0 pointer-events-none">
|
||||||
|
{/* Mobile */}
|
||||||
|
<Image
|
||||||
|
src="/images/footer/maskedmobile.webp"
|
||||||
|
alt="footer background"
|
||||||
|
loading="lazy"
|
||||||
|
width={0}
|
||||||
|
height={0}
|
||||||
|
sizes="100vw"
|
||||||
|
className="block sm:hidden w-full h-auto"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Desktop */}
|
||||||
|
<Image
|
||||||
|
src="/images/footer/maskedimage.webp"
|
||||||
|
alt="footer background"
|
||||||
|
width={0}
|
||||||
|
height={0}
|
||||||
|
sizes="100vw"
|
||||||
|
loading="lazy"
|
||||||
|
className="hidden sm:block w-full h-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
247
apps/website/components/autumn-config.jsx
Executable file
@@ -0,0 +1,247 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import Image from "next/image";
|
||||||
|
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
||||||
|
import { Light as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||||
|
import js from "react-syntax-highlighter/dist/esm/languages/hljs/javascript";
|
||||||
|
|
||||||
|
// useLayoutEffect runs synchronously before browser paint on the client,
|
||||||
|
// eliminating the container-query font-size race that causes CLS on reload.
|
||||||
|
const useIsomorphicLayoutEffect =
|
||||||
|
typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
||||||
|
|
||||||
|
SyntaxHighlighter.registerLanguage("javascript", js);
|
||||||
|
|
||||||
|
const autumnTheme = {
|
||||||
|
hljs: {
|
||||||
|
display: "block",
|
||||||
|
background: "transparent",
|
||||||
|
color: "#BFBFBF",
|
||||||
|
padding: "0",
|
||||||
|
margin: "0",
|
||||||
|
},
|
||||||
|
"hljs-comment": { color: "#6B6B6B" },
|
||||||
|
"hljs-keyword": { color: "#9564ff" },
|
||||||
|
"hljs-built_in": { color: "#BFBFBF" },
|
||||||
|
"hljs-string": { color: "#2B8C3F" },
|
||||||
|
"hljs-number": { color: "#9564ff" },
|
||||||
|
"hljs-literal": { color: "#2B8C3F" },
|
||||||
|
"hljs-attr": { color: "#FF1F12" },
|
||||||
|
"hljs-property": { color: "#FF1F12" },
|
||||||
|
"hljs-variable": { color: "#0161B5" },
|
||||||
|
"hljs-title": { color: "#BFBFBF" },
|
||||||
|
"hljs-params": { color: "#0161B5" },
|
||||||
|
"hljs-punctuation": { color: "#BFBFBF" },
|
||||||
|
};
|
||||||
|
|
||||||
|
const TOTAL_LINES = 21;
|
||||||
|
const LINE_HEIGHT = 24;
|
||||||
|
|
||||||
|
const codeContent = `// Your entire billing integration
|
||||||
|
const { allowed, remaining } = await
|
||||||
|
autumn.check({
|
||||||
|
featureId: "ai_tokens"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (allowed) {
|
||||||
|
await autumn.track({
|
||||||
|
featureId: "ai_tokens",
|
||||||
|
value: 1024
|
||||||
|
});
|
||||||
|
}`;
|
||||||
|
|
||||||
|
const TYPING_SPEED = 10;
|
||||||
|
|
||||||
|
export default function AutumnConfig({
|
||||||
|
lines = TOTAL_LINES,
|
||||||
|
initialDelay = 0,
|
||||||
|
awaitEvent = null,
|
||||||
|
}) {
|
||||||
|
const fullCode = (() => {
|
||||||
|
const lineCount = codeContent.split("\n").length;
|
||||||
|
return codeContent + "\n".repeat(Math.max(0, lines - lineCount));
|
||||||
|
})();
|
||||||
|
const containerRef = useRef(null);
|
||||||
|
const [fontSize, setFontSize] = useState(16);
|
||||||
|
const [displayed, setDisplayed] = useState("");
|
||||||
|
const [cursorVisible, setCursorVisible] = useState(true);
|
||||||
|
const [awaitDone, setAwaitDone] = useState(!awaitEvent);
|
||||||
|
const [started, setStarted] = useState(initialDelay === 0 && !awaitEvent);
|
||||||
|
const done = displayed.length >= fullCode.length;
|
||||||
|
|
||||||
|
// Wait for the signal event before starting the delay countdown
|
||||||
|
useEffect(() => {
|
||||||
|
if (!awaitEvent) return;
|
||||||
|
const handler = () => setAwaitDone(true);
|
||||||
|
window.addEventListener(awaitEvent, handler, { once: true });
|
||||||
|
return () => window.removeEventListener(awaitEvent, handler);
|
||||||
|
}, [awaitEvent]);
|
||||||
|
|
||||||
|
// Start typing after awaitDone, respecting initialDelay
|
||||||
|
useEffect(() => {
|
||||||
|
if (!awaitDone) return;
|
||||||
|
const t = setTimeout(() => setStarted(true), initialDelay);
|
||||||
|
return () => clearTimeout(t);
|
||||||
|
}, [awaitDone, initialDelay]);
|
||||||
|
|
||||||
|
useIsomorphicLayoutEffect(() => {
|
||||||
|
const el = containerRef.current;
|
||||||
|
if (!el) return;
|
||||||
|
const measure = () =>
|
||||||
|
setFontSize(Math.min(Math.max(el.offsetWidth * 0.0385, 10), 20));
|
||||||
|
measure();
|
||||||
|
const ro = new ResizeObserver(measure);
|
||||||
|
ro.observe(el);
|
||||||
|
return () => ro.disconnect();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const displayedPadded =
|
||||||
|
displayed + "\n".repeat(Math.max(0, lines - displayed.split("\n").length));
|
||||||
|
useEffect(() => {
|
||||||
|
if (!started || done) return;
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
setDisplayed(fullCode.slice(0, displayed.length + 1));
|
||||||
|
}, TYPING_SPEED);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [displayed, done, started]);
|
||||||
|
|
||||||
|
// Blinking cursor after done
|
||||||
|
useEffect(() => {
|
||||||
|
if (!done) return;
|
||||||
|
const interval = setInterval(() => setCursorVisible((v) => !v), 530);
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, [done]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
className="@container w-full max-w-[520px] border border-[#2A2A2A] bg-[#000000]/90"
|
||||||
|
>
|
||||||
|
{/* Title bar */}
|
||||||
|
{/* <div className="flex items-center justify-between border-b border-[#2A2A2A] px-4 py-0.5 gap-3 w-full">
|
||||||
|
<div className="flex-1 min-w-0 overflow-hidden flex justify-end items-center h-[21px]">
|
||||||
|
<Image
|
||||||
|
src="/images/hero/box.svg"
|
||||||
|
width={186}
|
||||||
|
height={21}
|
||||||
|
alt="Box"
|
||||||
|
style={{ width: "auto", height: "auto" }}
|
||||||
|
className="max-w-none w-[186px] h-[21px] object-none object-right shrink-0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className="font-mono text-[17.5px] text-[#FFFFFF99] whitespace-nowrap pt-0.5 shrink-0 mx-1">
|
||||||
|
autumn.config.ts
|
||||||
|
</span>
|
||||||
|
<div className="flex-1 min-w-0 overflow-hidden flex justify-start items-center h-[21px]">
|
||||||
|
<Image
|
||||||
|
src="/images/hero/box.svg"
|
||||||
|
width={186}
|
||||||
|
height={21}
|
||||||
|
alt="Box"
|
||||||
|
style={{ width: "auto", height: "auto" }}
|
||||||
|
className="w-[186px] h-[21px] object-none object-left"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className="ml-1 border border-[#292929] cursor-pointer select-none flex items-center justify-center shrink-0 p-1.5">
|
||||||
|
<img
|
||||||
|
src="/images/hero/cross.svg"
|
||||||
|
width={11}
|
||||||
|
height={11}
|
||||||
|
alt="cross"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div> */}
|
||||||
|
<div className="flex items-center justify-between border-b border-[#292929] px-2 py-1.5 w-full bg-[#000000]">
|
||||||
|
{/* Left Vent: flex-1 makes it stretch, min-w-0 allows it to shrink below its content if needed */}
|
||||||
|
<div className="flex-1 min-w-[10px] h-[22px] border border-[#292929] flex flex-col justify-evenly px-[2px]">
|
||||||
|
<div className="h-[1px] w-full bg-[#2A2A2A]/60" />
|
||||||
|
<div className="h-[1px] w-full bg-[#2A2A2A]/60" />
|
||||||
|
<div className="h-[1px] w-full bg-[#2A2A2A]/60" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Filename: shrink-0 ensures the text never gets squashed */}
|
||||||
|
<span className="font-mono text-[18px] text-[#FFFFFF99] whitespace-nowrap shrink-0 px-1">
|
||||||
|
autumn.config.ts
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{/* Right Vent: Matches the left one */}
|
||||||
|
<div className="flex-1 min-w-[10px] h-[22px] border border-[#2A2A2A] flex flex-col justify-evenly px-[2px]">
|
||||||
|
<div className="h-[1px] w-full bg-[#2A2A2A]/60" />
|
||||||
|
<div className="h-[1px] w-full bg-[#2A2A2A]/60" />
|
||||||
|
<div className="h-[1px] w-full bg-[#2A2A2A]/60" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Close Button Container */}
|
||||||
|
<div className="w-[24px] ml-2 h-[24px] border border-[#2A2A2A] flex items-center justify-center shrink-0 cursor-pointer hover:bg-white/5 transition-colors">
|
||||||
|
<Image
|
||||||
|
src="/images/hero/cross.svg"
|
||||||
|
width={11}
|
||||||
|
height={11}
|
||||||
|
alt="Box"
|
||||||
|
style={{ width: "auto", height: "auto" }}
|
||||||
|
className="w-full h-[11px] object-fill object-left"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Code area — fluidly driven by container query relative font sizes so height never distorts */}
|
||||||
|
<div className="relative px-4 py-3 font-mono text-sm overflow-hidden">
|
||||||
|
{/* Dynamic-height inner box: 20 lines × 1.25em */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: `${lines * LINE_HEIGHT}px`,
|
||||||
|
overflow: "hidden",
|
||||||
|
fontSize: `${fontSize}px`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SyntaxHighlighter
|
||||||
|
language="javascript"
|
||||||
|
style={autumnTheme}
|
||||||
|
showLineNumbers
|
||||||
|
lineNumberStyle={{
|
||||||
|
color: "#fff",
|
||||||
|
minWidth: "2rem",
|
||||||
|
paddingRight: "1rem",
|
||||||
|
userSelect: "none",
|
||||||
|
}}
|
||||||
|
customStyle={{
|
||||||
|
background: "transparent",
|
||||||
|
padding: 0,
|
||||||
|
margin: 0,
|
||||||
|
fontSize: "inherit",
|
||||||
|
lineHeight: `${LINE_HEIGHT}px`,
|
||||||
|
fontWeight: "300",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{displayedPadded}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ height: 0, overflow: "visible", position: "relative" }}>
|
||||||
|
<span
|
||||||
|
className="absolute -top-3.5 left-14 w-0.5 h-3.5 bg-[#9564ff]"
|
||||||
|
style={{
|
||||||
|
opacity: cursorVisible ? 1 : 0,
|
||||||
|
transition: "opacity 0.1s",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="pointer-events-none absolute bottom-0 left-0 right-0 h-28 bg-linear-to-t from-[#000000] via-[#000000]/70 to-transparent z-10" />
|
||||||
|
|
||||||
|
<div className="px-1 sm:px-2">
|
||||||
|
<div className="absolute left-2 right-2 sm:left-3 sm:right-3 bottom-[10px] flex items-center justify-between border border-[#9564ff] bg-[#20143C] px-2 sm:px-4 py-2 sm:py-2.5 font-mono text-[10px] sm:text-sm shadow-[0_4px_20px_rgba(149,100,255,0.1)] z-20">
|
||||||
|
<div className="flex items-center gap-1 sm:gap-2">
|
||||||
|
<span className="text-[#959494]">allowed:</span>
|
||||||
|
<span className="text-[#2B8C3F]">true</span>
|
||||||
|
<span className="text-[#959494] ml-0.5 sm:ml-0">remaining:</span>
|
||||||
|
<span className="text-[#9564ff]">8976</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-[#9564ff] ml-1">92ms</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
71
apps/website/components/dashboard-icon-pixel.jsx
Executable file
@@ -0,0 +1,71 @@
|
|||||||
|
"use client";
|
||||||
|
import { forwardRef, useImperativeHandle, useRef, useEffect } from "react";
|
||||||
|
import gsap from "gsap";
|
||||||
|
|
||||||
|
export const DashboardIconPixel = forwardRef(function DashboardIconPixel(
|
||||||
|
{ Icon },
|
||||||
|
ref,
|
||||||
|
) {
|
||||||
|
const iconRef = useRef(null);
|
||||||
|
const pulseRef = useRef(null);
|
||||||
|
const tlRef = useRef(null);
|
||||||
|
const frames = [
|
||||||
|
"\u2800\u2836\u2800",
|
||||||
|
"\u2830\u28FF\u2806",
|
||||||
|
"\u28BE\u28C9\u2877",
|
||||||
|
"\u28CF\u2800\u28F9",
|
||||||
|
"\u2841\u2800\u2888",
|
||||||
|
];
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
restart: () => tlRef.current?.play(),
|
||||||
|
reverse: () => tlRef.current?.reverse(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const pixels = iconRef.current?.querySelectorAll(".icon-pixel-path");
|
||||||
|
const pulseEl = pulseRef.current;
|
||||||
|
if (!pixels || !pulseEl) return;
|
||||||
|
|
||||||
|
gsap.set(pixels, {
|
||||||
|
opacity: 0.25,
|
||||||
|
scale: 0.8,
|
||||||
|
transformOrigin: "left bottom",
|
||||||
|
});
|
||||||
|
gsap.set(pulseEl, { opacity: 0 });
|
||||||
|
|
||||||
|
tlRef.current = gsap
|
||||||
|
.timeline({ paused: true })
|
||||||
|
.to(pixels, { opacity: 0, duration: 0.05 })
|
||||||
|
.to(pulseEl, { opacity: 1, duration: 0.05 }, "<")
|
||||||
|
.to(pulseEl, {
|
||||||
|
duration: 0.2,
|
||||||
|
onUpdate: function () {
|
||||||
|
pulseEl.innerText =
|
||||||
|
frames[Math.floor(this.progress() * (frames.length - 1))];
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.to(pulseEl, { opacity: 0, duration: 0.1 })
|
||||||
|
.to(
|
||||||
|
pixels,
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
scale: 1,
|
||||||
|
duration: 0.2,
|
||||||
|
stagger: { grid: [5, 5], from: [0, 4], amount: 0.2 },
|
||||||
|
},
|
||||||
|
"-=0.1",
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
// Height and Width match your original icon (14px)
|
||||||
|
<span className="relative inline-flex items-center justify-center w-[14px] h-[14px]">
|
||||||
|
<div
|
||||||
|
ref={pulseRef}
|
||||||
|
className="absolute z-20 font-mono text-[14px] text-white opacity-0"
|
||||||
|
/>
|
||||||
|
<Icon ref={iconRef} className="w-full h-full text-white" />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
});
|
||||||
107
apps/website/components/elastic-footer.jsx
Executable file
@@ -0,0 +1,107 @@
|
|||||||
|
"use client";
|
||||||
|
import { motion, useSpring, useTransform, useMotionValue } from "framer-motion";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import AnimatedFooterImage from "./animated-footer-image";
|
||||||
|
|
||||||
|
export default function ElasticRecoil({ children }) {
|
||||||
|
const liftAmount = useMotionValue(0);
|
||||||
|
|
||||||
|
const springConfig = { stiffness: 600, damping: 35, mass: 1 };
|
||||||
|
const animatedLift = useSpring(liftAmount, springConfig);
|
||||||
|
const y = useTransform(animatedLift, [0, 400], [0, -280]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let timeout;
|
||||||
|
let recoilFired = false;
|
||||||
|
let isTouching = false; // Track if finger is on screen
|
||||||
|
|
||||||
|
const triggerRebound = () => {
|
||||||
|
liftAmount.set(0);
|
||||||
|
if (!recoilFired) {
|
||||||
|
recoilFired = true;
|
||||||
|
window.dispatchEvent(new CustomEvent("elastic-recoil"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleWheel = (e) => {
|
||||||
|
const isAtBottom =
|
||||||
|
window.innerHeight + window.pageYOffset >=
|
||||||
|
document.documentElement.scrollHeight - 5;
|
||||||
|
|
||||||
|
if (isAtBottom && e.deltaY > 0) {
|
||||||
|
liftAmount.set(liftAmount.get() + e.deltaY * 0.5);
|
||||||
|
recoilFired = false;
|
||||||
|
|
||||||
|
// Reset timeout on every wheel event
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
if (!isTouching) {
|
||||||
|
triggerRebound();
|
||||||
|
}
|
||||||
|
}, 1500); // Rebounds 1.5 seconds after wheel stops
|
||||||
|
} else if (e.deltaY < 0) {
|
||||||
|
if (!isTouching) {
|
||||||
|
liftAmount.set(0);
|
||||||
|
recoilFired = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let touchStart = 0;
|
||||||
|
const handleTouchStart = (e) => {
|
||||||
|
isTouching = true;
|
||||||
|
touchStart = e.touches[0].clientY;
|
||||||
|
recoilFired = false;
|
||||||
|
clearTimeout(timeout);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTouchMove = (e) => {
|
||||||
|
const isAtBottom =
|
||||||
|
window.innerHeight + window.pageYOffset >=
|
||||||
|
document.documentElement.scrollHeight - 5;
|
||||||
|
|
||||||
|
if (isAtBottom) {
|
||||||
|
const touchDelta = touchStart - e.touches[0].clientY;
|
||||||
|
if (touchDelta > 0) {
|
||||||
|
liftAmount.set(touchDelta * 1.5);
|
||||||
|
recoilFired = false;
|
||||||
|
// Notice: We don't set a timeout here, so it never snaps back while touching
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTouchEnd = () => {
|
||||||
|
isTouching = false;
|
||||||
|
if (liftAmount.get() > 0) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
triggerRebound();
|
||||||
|
}, 1500); // Rebounds 1.5 seconds after lifting finger
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("wheel", handleWheel, { passive: true });
|
||||||
|
window.addEventListener("touchstart", handleTouchStart, { passive: true });
|
||||||
|
window.addEventListener("touchmove", handleTouchMove, { passive: true });
|
||||||
|
window.addEventListener("touchend", handleTouchEnd, { passive: true });
|
||||||
|
window.addEventListener("touchcancel", handleTouchEnd, { passive: true });
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
window.removeEventListener("wheel", handleWheel);
|
||||||
|
window.removeEventListener("touchstart", handleTouchStart);
|
||||||
|
window.removeEventListener("touchmove", handleTouchMove);
|
||||||
|
window.removeEventListener("touchend", handleTouchEnd);
|
||||||
|
window.removeEventListener("touchcancel", handleTouchEnd);
|
||||||
|
};
|
||||||
|
}, [liftAmount]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative w-full overflow-hidden">
|
||||||
|
<AnimatedFooterImage />
|
||||||
|
<motion.div style={{ y }} className="relative z-10 bg-black">
|
||||||
|
{children}
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
147
apps/website/components/faq.jsx
Executable file
@@ -0,0 +1,147 @@
|
|||||||
|
"use client";
|
||||||
|
import { faqData, AnimatedPlusMinus } from "@/app/constant";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
|
|
||||||
|
export default function FAQ() {
|
||||||
|
const [openId, setOpenId] = useState(3);
|
||||||
|
|
||||||
|
const springConfig = {
|
||||||
|
type: "spring",
|
||||||
|
stiffness: 280,
|
||||||
|
damping: 32,
|
||||||
|
mass: 1,
|
||||||
|
restDelta: 0.01,
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleAccordion = (id) => {
|
||||||
|
setOpenId(openId === id ? null : id);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
className="bg-[#000000] text-white overflow-hidden relative border-b border-[#292929]"
|
||||||
|
style={{
|
||||||
|
width: "calc(100% + var(--page-pad) * 2)",
|
||||||
|
marginLeft: "calc(var(--page-pad) * -1)",
|
||||||
|
paddingLeft: "var(--page-pad)",
|
||||||
|
paddingRight: "var(--page-pad)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 w-full min-h-[500px]">
|
||||||
|
<div className="md:border-r border-b border-[#292929] pl-4 md:pl-4 xl:pl-[90px] pr-6 lg:pr-12 py-12 md:py-[60px] flex flex-col justify-center">
|
||||||
|
<h2 className="text-[30px] md:text-[40px] font-normal tracking-[-2%] leading-[1.1]">
|
||||||
|
<span className="text-[#FFFFFF99] font-light">
|
||||||
|
Frequently Asked
|
||||||
|
</span>
|
||||||
|
<br />
|
||||||
|
<span className="text-white font-normal">Questions</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="hidden md:block border-b border-[#292929] h-full w-full"></div>
|
||||||
|
|
||||||
|
<div className="hidden md:block md:border-r border-[#292929] h-full w-full relative z-0">
|
||||||
|
<div className="absolute bottom-0 w-full h-full pb-32"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col h-full w-full relative z-10 ">
|
||||||
|
{faqData.map((faq) => {
|
||||||
|
const isOpen = openId === faq.id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={faq.id}
|
||||||
|
onClick={() => toggleAccordion(faq.id)}
|
||||||
|
className={`group relative border-b last:border-b-0 border-[#292929] cursor-pointer w-full flex flex-col justify-center transition-colors duration-300 ${isOpen ? "" : "hover:bg-[#080808]"}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`absolute inset-0 z-0 overflow-hidden pointer-events-none transition-opacity duration-500 ${
|
||||||
|
isOpen ? "opacity-100" : "opacity-0"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="absolute inset-0 bg-white/[0.03] md:group-hover:block hidden" />
|
||||||
|
|
||||||
|
<img
|
||||||
|
src="/images/pricing/FAQ/faqbg.svg"
|
||||||
|
alt="faq background"
|
||||||
|
loading="lazy"
|
||||||
|
className="absolute right-0 top-0 w-full h-[400px] md:h-full object-contain object-top-right md:object-cover md:object-right border-none opacity-60"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-linear-to-r from-[#351B6D]/90 via-[#351B6D]/80 to-black/75 mix-blend-normal" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative z-10 px-4.5 md:px-8 lg:px-[20px] py-[30px]">
|
||||||
|
<div className="flex items-center justify-between gap-4">
|
||||||
|
<h3
|
||||||
|
className={`text-base lg:text-[18px] tracking-[-2%] transition-all duration-400 ${
|
||||||
|
isOpen
|
||||||
|
? "text-white font-normal"
|
||||||
|
: "text-[#FFFFFF66] font-light md:group-hover:text-white"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{faq.question}
|
||||||
|
</h3>
|
||||||
|
<div className="shrink-0 overflow-hidden">
|
||||||
|
<AnimatedPlusMinus
|
||||||
|
isOpen={isOpen}
|
||||||
|
className={`w-5 h-5 transition-colors duration-400 ${
|
||||||
|
isOpen
|
||||||
|
? "text-white"
|
||||||
|
: "text-[#FFFFFF66] md:group-hover:text-white"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`grid transition-all duration-500 ease-[cubic-bezier(0.16,1,0.3,1)] ${
|
||||||
|
isOpen
|
||||||
|
? "grid-rows-[1fr] opacity-100"
|
||||||
|
: "grid-rows-[0fr] opacity-0"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="overflow-hidden">
|
||||||
|
<AnimatePresence initial={false}>
|
||||||
|
{isOpen && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ y: -15, opacity: 0 }}
|
||||||
|
animate={{ y: 0, opacity: 1 }}
|
||||||
|
exit={{ y: -10, opacity: 0 }}
|
||||||
|
transition={{
|
||||||
|
height: springConfig,
|
||||||
|
opacity: { duration: 0.25 },
|
||||||
|
y: springConfig,
|
||||||
|
}}
|
||||||
|
className="pt-5 text-[#ffffff] leading-[16px] md:leading-[20px] font-light text-[12px] md:text-[14px] max-w-[85%] flex flex-col gap-3.5 tracking-[-0.5%]"
|
||||||
|
>
|
||||||
|
{faq.answer.split("\n\n").map((paragraph, idx) => (
|
||||||
|
<p key={idx}>{paragraph}</p>
|
||||||
|
))}
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="relative z-0 px-8 lg:px-[20px] py-[30px] pointer-events-none opacity-0 select-none"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between gap-4">
|
||||||
|
<h3 className="text-base lg:text-[18px] tracking-[-2%] text-transparent select-none">
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
<div className="shrink-0 w-5 h-5"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
106
apps/website/components/feature-icon-animation.jsx
Executable file
@@ -0,0 +1,106 @@
|
|||||||
|
"use client";
|
||||||
|
import { forwardRef, useImperativeHandle, useRef, useEffect } from "react";
|
||||||
|
import gsap from "gsap";
|
||||||
|
|
||||||
|
export const FeatureIconAnimation = forwardRef(({ Icon }, ref) => {
|
||||||
|
const iconRef = useRef(null);
|
||||||
|
const pulseRef = useRef(null);
|
||||||
|
const tlRef = useRef(null);
|
||||||
|
|
||||||
|
const frames = [
|
||||||
|
"\u2800\u2836\u2800",
|
||||||
|
"\u2830\u28FF\u2806",
|
||||||
|
"\u28BE\u28C9\u2877",
|
||||||
|
"\u28CF\u2800\u28F9",
|
||||||
|
"\u2841\u2800\u2888",
|
||||||
|
];
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
play: () => tlRef.current?.play(),
|
||||||
|
reverse: () => tlRef.current?.reverse(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const pixels = iconRef.current?.querySelectorAll("path");
|
||||||
|
const pulseEl = pulseRef.current;
|
||||||
|
if (!pixels || !pulseEl) return;
|
||||||
|
|
||||||
|
// IDLE: Subjugated/Ghost state
|
||||||
|
gsap.set(pixels, {
|
||||||
|
opacity: 0.15,
|
||||||
|
scale: 0.8,
|
||||||
|
transformOrigin: "left bottom",
|
||||||
|
});
|
||||||
|
gsap.set(pulseEl, { opacity: 0 });
|
||||||
|
|
||||||
|
tlRef.current = gsap.timeline({ paused: true });
|
||||||
|
|
||||||
|
tlRef.current
|
||||||
|
// SCRAMBLE
|
||||||
|
.to(pixels, { opacity: 0, duration: 0.05 })
|
||||||
|
.to(pulseEl, { opacity: 1, duration: 0.05 }, "<")
|
||||||
|
.to(pulseEl, {
|
||||||
|
duration: 0.3,
|
||||||
|
onUpdate: function () {
|
||||||
|
const frameIndex = Math.floor(this.progress() * (frames.length - 1));
|
||||||
|
pulseEl.innerText = frames[frameIndex];
|
||||||
|
},
|
||||||
|
ease: "none",
|
||||||
|
})
|
||||||
|
// REVEAL
|
||||||
|
.to(pulseEl, { opacity: 0, duration: 0.1, scale: 1.2 })
|
||||||
|
.to(
|
||||||
|
pixels,
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
scale: 1.15,
|
||||||
|
fill: "#9564ff", // Autumn Purple highlight for features
|
||||||
|
duration: 0.2,
|
||||||
|
stagger: {
|
||||||
|
grid: [5, 5],
|
||||||
|
from: [0, 4], // Bottom-Left Sweep
|
||||||
|
amount: 0.25,
|
||||||
|
},
|
||||||
|
ease: "power2.out",
|
||||||
|
},
|
||||||
|
"-=0.1",
|
||||||
|
)
|
||||||
|
.to(pixels, {
|
||||||
|
scale: 1,
|
||||||
|
duration: 0.15,
|
||||||
|
ease: "back.out(3)",
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => tlRef.current?.kill();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative flex items-center justify-center w-12 h-12 group/icon">
|
||||||
|
{/* 5x5 Grid Mask */}
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
|
||||||
|
<div className="grid grid-cols-5 grid-rows-5 gap-[3px]">
|
||||||
|
{Array.from({ length: 25 }).map((_, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="bg-white/[0.08] w-[2.5px] h-[2.5px] rounded-[0.5px]"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Pulse Shuffle Layer */}
|
||||||
|
<div
|
||||||
|
ref={pulseRef}
|
||||||
|
className="absolute z-20 font-mono text-[20px] text-[#9564ff] pointer-events-none select-none"
|
||||||
|
>
|
||||||
|
{"\u2800\u2836\u2800"}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Feature Icon Layer */}
|
||||||
|
<div className="relative z-10 w-[24px] h-[24px] flex items-center justify-center">
|
||||||
|
<Icon ref={iconRef} className="w-full h-full text-white" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
FeatureIconAnimation.displayName = "FeatureIconAnimation";
|
||||||
70
apps/website/components/features.jsx
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
"use client";
|
||||||
|
import { featuresData } from "@/app/constant";
|
||||||
|
import { useRef } from "react";
|
||||||
|
import { FeatureIconAnimation } from "./feature-icon-animation";
|
||||||
|
|
||||||
|
function FeatureCard({ feature }) {
|
||||||
|
const iconRef = useRef(null);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onMouseEnter={() => iconRef.current?.play()}
|
||||||
|
onMouseLeave={() => iconRef.current?.reverse()}
|
||||||
|
className="group relative flex px-4 md:px-6 flex-col justify-between p-6 bg-[#0F0F0F] min-h-[200px] md:min-h-[280px] border-r border-b border-[#292929] overflow-hidden cursor-pointer"
|
||||||
|
>
|
||||||
|
<div className="absolute inset-0 opacity-0 translate-y-6 group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-500 ease-out pointer-events-none z-0 hidden md:block">
|
||||||
|
<video
|
||||||
|
src="/images/features/pixel effect.webm"
|
||||||
|
autoPlay
|
||||||
|
loop
|
||||||
|
muted
|
||||||
|
playsInline
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* Hover Gradient Overlay */}
|
||||||
|
<div className="absolute inset-x-0 bottom-0 h-[70%] bg-[linear-gradient(to_bottom,rgba(10,10,10,0)_0%,rgba(135,82,250,0.15)_40%,rgba(135,82,250,0.45)_70%,rgba(135,82,250,0.85)_90%)] opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none" />
|
||||||
|
|
||||||
|
<div className="relative z-10 flex flex-col h-full gap-[42px] md:gap-24.5">
|
||||||
|
<feature.Icon className="w-6 h-6 text-white md:hidden" />
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<FeatureIconAnimation Icon={feature.Icon} ref={iconRef} />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-2 md:gap-4.5">
|
||||||
|
<h3 className="text-white font-normal tracking-[-5%] leading-6 text-[20px] md:text-[24px] font-sans">
|
||||||
|
{feature.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-[#FFFFFF99] w-full font-light tracking-[-2%] text-[14px] md:text-[16px] font-sans leading-[18px] md:leading-[20px] pr-2 md:pr-4 text-pretty">
|
||||||
|
{feature.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Features() {
|
||||||
|
return (
|
||||||
|
<section className="bg-[#000000] w-full">
|
||||||
|
<div className="flex flex-col px-4 md:px-4 sm:px-8 py-12 md:py-16 xl:px-22.75 items-start">
|
||||||
|
<h2 className="text-[30px] md:text-[40px] leading-[32px] md:leading-[44px] font-sans tracking-[-4%]">
|
||||||
|
<div className="text-[#FFFFFF99]">Everything you need.</div>
|
||||||
|
<div className="text-white">Nothing you have to build.</div>
|
||||||
|
</h2>
|
||||||
|
<div className="mt-4 text-[16px] tracking-[-2%] font-sans font-light text-[#FFFFFF99] leading-[20px] max-w-[420px]">
|
||||||
|
Eight features that eliminate your entire{" "}
|
||||||
|
<span className="text-white">
|
||||||
|
billing infrastructure, fully managed.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="grid grid-cols-1 gap-[-3px] md:grid-cols-2 lg:grid-cols-3 xl:px-22.75 border-[#292929] [&>*:last-child]:border-b-0 [&>*:nth-last-child(2)]:border-b-0 md:[&>*:nth-last-child(-n+2)]:border-b-0 lg:[&>*:nth-last-child(-n+3)]:border-b-0 *:border-l md:[&>*:nth-child(2n)]:border-l-0 lg:[&>*:nth-child(3n+1)]:border-l lg:[&>*:nth-child(3n+2)]:border-l-0 lg:[&>*:nth-child(3n)]:border-l-0">
|
||||||
|
{featuresData.map((feature, i) => (
|
||||||
|
<FeatureCard key={i} feature={feature} />
|
||||||
|
))}
|
||||||
|
<div className="bg-[#0f0f0f] w-full h-full min-h-[280px] hidden lg:block border-r border-b border-[#292929]" />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
181
apps/website/components/footer.jsx
Executable file
@@ -0,0 +1,181 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
const footerColumns = [
|
||||||
|
{
|
||||||
|
title: "PRODUCT",
|
||||||
|
links: [
|
||||||
|
{ label: "FEATURES", href: "#" },
|
||||||
|
{ label: "INTEGRATIONS", href: "#" },
|
||||||
|
{ label: "PRICING", href: "#" },
|
||||||
|
{ label: "CHANGELOG", href: "#" },
|
||||||
|
{ label: "ROADMAP", href: "#" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "COMPANY",
|
||||||
|
links: [
|
||||||
|
{ label: "OUR TEAM", href: "#" },
|
||||||
|
{ label: "OUR VALUES", href: "/privacy" },
|
||||||
|
{ label: "BLOG", href: "https://useautumn.com/blog" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "RESOURCES",
|
||||||
|
links: [
|
||||||
|
{ label: "DOWNLOADS", href: "https://useautumn.com/" },
|
||||||
|
{ label: "DOCUMENTATION", href: "https://docs.useautumn.com/welcome" },
|
||||||
|
{ label: "CONTACT", href: "https://cal.com/ayrod/a?user=ayrod" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Footer() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<footer
|
||||||
|
style={{
|
||||||
|
width: "calc(100% + var(--page-pad) * 2)",
|
||||||
|
marginLeft: "calc(var(--page-pad) * -1)",
|
||||||
|
paddingLeft: "var(--page-pad)",
|
||||||
|
paddingRight: "var(--page-pad)",
|
||||||
|
}}
|
||||||
|
className="mt-[50px] relative bg-[#000000] border-t border-[#292929] overflow-hidden text-[#FFFFFF99] grid"
|
||||||
|
>
|
||||||
|
<div className="col-start-1 row-start-1 flex flex-col z-10 w-full relative">
|
||||||
|
<div className="relative w-full flex flex-col justify-between min-h-[400px]">
|
||||||
|
<div className="absolute bottom-0 left-0 right-0 h-[300px] sm:h-[550px] lg:h-[400px] pointer-events-none opacity-70 bg-[url('/images/footer/footerbg.svg')] bg-cover sm:bg-contain bg-bottom bg-no-repeat z-0" />
|
||||||
|
|
||||||
|
<div className="flex flex-col lg:flex-row justify-between pt-[32px] md:pt-24 pb-32 md:pb-16 pl-4.5 xl:pl-[90px] pr-4 sm:pr-8 lg:pr-12 gap-10 md:gap-16 lg:gap-8 relative z-10">
|
||||||
|
{/* Left Side: Logo and Description */}
|
||||||
|
<div className="flex flex-col max-w-sm">
|
||||||
|
<Link href="/" className="mb-3 md:mb-6 inline-block">
|
||||||
|
<Image
|
||||||
|
src="/images/navbar/autumnlogo.svg"
|
||||||
|
width={195}
|
||||||
|
height={48}
|
||||||
|
alt="Autumn"
|
||||||
|
className="brightness-0 invert w-[130px] h-[32px] md:w-[195px] md:h-[48px]"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
<p className="text-[14px] md:text-[16px] leading-[18px] md:leading-[20px] tracking-[-2%] text-[#FFFFFF99] font-light">
|
||||||
|
Autumn is built on top of Stripe Billing (for now), so their
|
||||||
|
fees (0.7%, and 2.9% + 30c) still apply.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right Side: Columns */}
|
||||||
|
<div className="grid grid-cols-2 sm:grid-cols-3 gap-12 sm:gap-16 lg:gap-24">
|
||||||
|
{footerColumns.map((col, index) => (
|
||||||
|
<div key={index} className="flex flex-col">
|
||||||
|
<h3 className="flex items-center gap-2 text-white font-mono text-[14px] uppercase tracking-[-1%] mb-6">
|
||||||
|
<div className="w-[8px] h-[8px] bg-[#FFFFFF99]"></div>
|
||||||
|
{col.title}
|
||||||
|
</h3>
|
||||||
|
<ul className="flex flex-col gap-1">
|
||||||
|
{col.links.map((link, i) => (
|
||||||
|
<li key={i} className="group/strip">
|
||||||
|
<Link
|
||||||
|
href={link.href}
|
||||||
|
target="_blank"
|
||||||
|
className="group/strip flex items-center gap-3 text-[14px] font-mono uppercase tracking-[-1%] transition-colors duration-300"
|
||||||
|
>
|
||||||
|
<span className="w-1 h-1 bg-[#FFFFFF99] group-hover/strip:bg-white group-active/strip:bg-white transition-colors duration-300 shrink-0"></span>
|
||||||
|
|
||||||
|
<span className="relative">
|
||||||
|
<span className="text-[#FFFFFF99]">
|
||||||
|
{link.label}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="absolute inset-y-0 left-0 w-0 group-hover/strip:w-full group-active/strip:w-full overflow-hidden transition-all duration-300 ease-in-out bg-white text-black font-normal pointer-events-none flex items-center"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<span className="whitespace-nowrap">
|
||||||
|
{link.label}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="relative block z-10 bg-black/40 backdrop-blur-md border-y border-[#292929]"
|
||||||
|
style={{
|
||||||
|
width: "calc(100% + var(--page-pad) * 2)",
|
||||||
|
marginLeft: "calc(var(--page-pad) * -1)",
|
||||||
|
paddingLeft: "var(--page-pad)",
|
||||||
|
paddingRight: "var(--page-pad)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="max-w-[1400px] mx-auto flex flex-col md:flex-row justify-between items-stretch h-auto md:h-14 font-mono text-[10px] sm:text-[11px] tracking-[0.2em]">
|
||||||
|
{/* Social Left Box */}
|
||||||
|
<div className="flex flex-row md:flex-row border-b md:border-b-0 border-[#292929] w-full md:w-auto">
|
||||||
|
<div className="px-4 sm:px-8 py-4.5 md:py-0 border-r border-[#292929] tracking-[-2%] flex items-center justify-center md:justify-start text-[12px] md:text-[14px]">
|
||||||
|
SOCIAL
|
||||||
|
</div>
|
||||||
|
<div className="px-6 sm:px-8 py-4 md:py-0 flex items-center justify-center md:justify-start gap-3 sm:gap-4 md:border-r border-[#292929]">
|
||||||
|
<Link
|
||||||
|
href="https://www.linkedin.com/company/useautumn"
|
||||||
|
className="group/strip flex items-center text-[14px] tracking-[-2%] transition-colors duration-300"
|
||||||
|
>
|
||||||
|
<span className="relative">
|
||||||
|
<span className="text-[#FFFFFF99] group-hover/strip:text-[#ffffff] text-[12px] md:text-[14px] transition-colors duration-300">
|
||||||
|
LINKEDIN
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="absolute inset-y-0 left-0 w-0 group-hover/strip:w-full group-active/strip:w-full overflow-hidden transition-all duration-300 ease-in-out bg-white text-black font-normal pointer-events-none flex items-center"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<span className="whitespace-nowrap">LINKEDIN</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
<div className="w-[5px] h-[5px] bg-[#FFFFFF]"></div>
|
||||||
|
<Link
|
||||||
|
href="https://x.com/autumnpricing"
|
||||||
|
className="group/strip flex items-center text-[14px] tracking-[-2%] transition-colors duration-300"
|
||||||
|
>
|
||||||
|
<span className="relative">
|
||||||
|
<span className="text-[#FFFFFF99] group-hover/strip:text-[#ffffff] transition-colors duration-300 text-[12px] md:text-[14px]">
|
||||||
|
TWITTER
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="absolute inset-y-0 left-0 w-0 group-hover/strip:w-full group-active/strip:w-full overflow-hidden transition-all duration-300 ease-in-out bg-white text-black font-normal pointer-events-none flex items-center"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<span className="whitespace-nowrap">TWITTER</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="px-4.5 py-4 md:py-0 flex items-center justify-start md:justify-end text-center md:text-right text-[#FFFFFF99] text-[12px] md:text-[14px] tracking-[-2%] border-b md:border-b-0 border-[#292929] w-full md:w-auto">
|
||||||
|
Copyright © 2026 Autumn All rights reserved
|
||||||
|
<div className="hidden lg:flex gap-3 ml-[15px] h-[54px]">
|
||||||
|
<div className="border-r border-[#292929]" />
|
||||||
|
<div className="border-r border-[#292929]" />
|
||||||
|
<div className="border-r border-[#292929]" />
|
||||||
|
<div className="border-r border-[#292929]" />
|
||||||
|
<div className="border-r border-[#292929]" />
|
||||||
|
<div className="border-r border-[#292929]" />
|
||||||
|
<div className="border-r border-[#292929]" />
|
||||||
|
<div className="border-r border-[#292929]" />
|
||||||
|
<div className="border-r border-[#292929]" />
|
||||||
|
<div className="border-r border-[#292929]" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
282
apps/website/components/hero.jsx
Executable file
@@ -0,0 +1,282 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { CTALines, IconCTADocs, IconCTAStart } from "@/app/constant";
|
||||||
|
import { useGSAP } from "@gsap/react";
|
||||||
|
import gsap from "gsap";
|
||||||
|
import { motion } from "motion/react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import AutumnConfig from "./autumn-config";
|
||||||
|
// import dynamic from "next/dynamic";
|
||||||
|
|
||||||
|
// const AutumnConfig = dynamic(() => import("./autumn-config"), { ssr: false });
|
||||||
|
|
||||||
|
const BADGE_TEXT = "// billing infrastructure for ai";
|
||||||
|
|
||||||
|
export default function Hero() {
|
||||||
|
const containerRef = useRef(null);
|
||||||
|
const heroTlRef = useRef(null);
|
||||||
|
const [displayedText, setDisplayedText] = useState("");
|
||||||
|
|
||||||
|
// Badge typewriter
|
||||||
|
useEffect(() => {
|
||||||
|
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*0123456789";
|
||||||
|
let intervalId;
|
||||||
|
let timeoutId;
|
||||||
|
|
||||||
|
const startTypewriter = () => {
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
let iteration = 0;
|
||||||
|
intervalId = setInterval(() => {
|
||||||
|
setDisplayedText(
|
||||||
|
BADGE_TEXT.split("")
|
||||||
|
.map((char, index) => {
|
||||||
|
if (char === " ") return " ";
|
||||||
|
if (index < Math.floor(iteration)) return char;
|
||||||
|
if (index === Math.floor(iteration))
|
||||||
|
return chars[Math.floor(Math.random() * chars.length)];
|
||||||
|
return "";
|
||||||
|
})
|
||||||
|
.join(""),
|
||||||
|
);
|
||||||
|
|
||||||
|
iteration += 0.4;
|
||||||
|
|
||||||
|
if (iteration >= BADGE_TEXT.length) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
setDisplayedText(BADGE_TEXT);
|
||||||
|
}
|
||||||
|
}, 30);
|
||||||
|
}, 150);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("preloader:complete", startTypewriter, {
|
||||||
|
once: true,
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("preloader:complete", startTypewriter);
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
clearInterval(intervalId);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = () => heroTlRef.current?.play();
|
||||||
|
window.addEventListener("preloader:complete", handler, { once: true });
|
||||||
|
return () => window.removeEventListener("preloader:complete", handler);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useGSAP(
|
||||||
|
() => {
|
||||||
|
gsap.set(".hero-root", { opacity: 0 });
|
||||||
|
|
||||||
|
gsap.set(".hero-bg", {
|
||||||
|
opacity: 0,
|
||||||
|
filter: "blur(6px) brightness(1)",
|
||||||
|
scale: 0.97,
|
||||||
|
transformOrigin: "center top",
|
||||||
|
});
|
||||||
|
|
||||||
|
gsap.set(".hero-reveal", {
|
||||||
|
opacity: 0,
|
||||||
|
y: 25,
|
||||||
|
filter: "blur(12px)",
|
||||||
|
scale: 0.96,
|
||||||
|
transformOrigin: "center bottom",
|
||||||
|
});
|
||||||
|
|
||||||
|
gsap.set(".hero-cta", { opacity: 0, scale: 0.95 });
|
||||||
|
|
||||||
|
const tl = gsap.timeline({
|
||||||
|
paused: true,
|
||||||
|
defaults: { overwrite: "auto" },
|
||||||
|
});
|
||||||
|
heroTlRef.current = tl;
|
||||||
|
|
||||||
|
tl.to(".hero-root", { opacity: 1, duration: 0.3, ease: "none" })
|
||||||
|
|
||||||
|
.to(".hero-bg", {
|
||||||
|
opacity: 1,
|
||||||
|
filter: "blur(0px) brightness(1)",
|
||||||
|
scale: 1,
|
||||||
|
duration: 0.4,
|
||||||
|
ease: "power2.out",
|
||||||
|
})
|
||||||
|
|
||||||
|
.to(".hero-bg", {
|
||||||
|
filter: "blur(0px) brightness(1.6)",
|
||||||
|
duration: 0.125,
|
||||||
|
ease: "power2.in",
|
||||||
|
})
|
||||||
|
|
||||||
|
.to(".hero-bg", {
|
||||||
|
filter: "blur(0px) brightness(1)",
|
||||||
|
duration: 0.125,
|
||||||
|
ease: "power2.out",
|
||||||
|
})
|
||||||
|
|
||||||
|
.to(
|
||||||
|
".hero-reveal",
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
filter: "blur(0px)",
|
||||||
|
scale: 1,
|
||||||
|
duration: 1.1,
|
||||||
|
stagger: 0.1,
|
||||||
|
ease: "power3.out",
|
||||||
|
},
|
||||||
|
"-=0.2",
|
||||||
|
)
|
||||||
|
|
||||||
|
.to(
|
||||||
|
".hero-cta",
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
scale: 1,
|
||||||
|
duration: 0.3,
|
||||||
|
stagger: 0.06,
|
||||||
|
ease: "back.out(1.5)",
|
||||||
|
},
|
||||||
|
"-=0.1",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ scope: containerRef },
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={containerRef}>
|
||||||
|
<div className="relative hero-root opacity-0 flex flex-col items-stretch pb-0 xl:pb-2.5 mb-0 lg:mb-[33px] bg-[#0F0F0F]">
|
||||||
|
<div className="relative hidden xl:block">
|
||||||
|
<Image
|
||||||
|
className="hero-bg w-full hidden md:block"
|
||||||
|
src={"/images/hero/hero_img.webp"}
|
||||||
|
width={1359}
|
||||||
|
height={343}
|
||||||
|
sizes="100vw"
|
||||||
|
style={{ width: "100%", height: "auto" }}
|
||||||
|
alt="hero-bg"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
<div className="hero-reveal absolute right-4 xl:right-8.5 top-38 w-[36vw] max-w-[520px]">
|
||||||
|
<AutumnConfig initialDelay={200} awaitEvent="preloader:complete" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-6 px-4 xl:px-22.75 py-8 bg-[#0F0F0F]">
|
||||||
|
<h4 className="hero-reveal relative uppercase font-mono tracking-[-2%] text-[12px] md:text-sm leading-sm text-white md:text-[#FFFFFF99] bg-[#2c2c2d] w-fit p-2 min-h-[30px] md:min-h-[36px] flex items-center">
|
||||||
|
<span className="invisible select-none" aria-hidden="true">
|
||||||
|
{BADGE_TEXT}
|
||||||
|
</span>
|
||||||
|
<span className="absolute inset-0 flex items-center p-2">
|
||||||
|
{displayedText}
|
||||||
|
</span>
|
||||||
|
</h4>
|
||||||
|
<div className="flex flex-col gap-6 w-full px-0 lg:px-0">
|
||||||
|
<h1 className="hero-reveal text-[44px] md:text-[56px] w-full max-w-sm sm:max-w-[480px] md:max-w-xl leading-[44px] tracking-[-5%] md:leading-14 font-sans">
|
||||||
|
<span className="text-[#FFFFFF99] font-normal">
|
||||||
|
The drop-in billing layer for
|
||||||
|
</span>{" "}
|
||||||
|
<span className="text-white block md:inline">AI startups</span>
|
||||||
|
</h1>
|
||||||
|
<p className="hero-reveal tracking-[-2%] w-full max-w-xs sm:max-w-[480px] md:max-w-xl text-[#FFFFFF99] md:text-[16px] text-[14px] font-light leading-5 font-sans">
|
||||||
|
Stop rebuilding usage limits, credit systems, and subscription
|
||||||
|
logic.{" "}
|
||||||
|
<span className="text-white font-light">
|
||||||
|
Autumn is the source of truth
|
||||||
|
</span>{" "}
|
||||||
|
that keeps webhooks, payments and usage perfectly in-sync.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-t border-[#292929]" />
|
||||||
|
<div className="flex flex-nowrap items-center xl:px-22.75 px-4 bg-[#0F0F0F] w-full overflow-hidden">
|
||||||
|
{/* Primary CTA */}
|
||||||
|
<div className="hero-cta w-full md:w-fit md:flex-shrink-0">
|
||||||
|
<Link href={"https://app.useautumn.com/sign-in"}>
|
||||||
|
<motion.div
|
||||||
|
initial="initial"
|
||||||
|
whileHover="hover"
|
||||||
|
whileTap="hover"
|
||||||
|
className="relative"
|
||||||
|
>
|
||||||
|
{/* Adjusted px-3 for mobile, md:px-4 for desktop */}
|
||||||
|
<div className="relative overflow-hidden flex items-center gap-1.5 md:gap-2.5 cursor-pointer justify-between py-2 px-3 md:px-4 md:py-3.5 md:w-50 font-sans bg-[#9564ff] hover:bg-[#7D46F4] transition-colors duration-300">
|
||||||
|
<CTALines />
|
||||||
|
<span className="relative z-10 tracking-tight text-white font-medium text-[13px] md:text-base whitespace-nowrap">
|
||||||
|
Start for free
|
||||||
|
</span>
|
||||||
|
<span className="relative z-10 scale-75 md:scale-100">
|
||||||
|
<IconCTAStart />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Secondary CTA */}
|
||||||
|
<div className="hero-cta w-full md:w-fit md:flex-shrink-0">
|
||||||
|
<Link href={"https://docs.useautumn.com/welcome"}>
|
||||||
|
<motion.div
|
||||||
|
initial="initial"
|
||||||
|
whileHover="hover"
|
||||||
|
whileTap="hover"
|
||||||
|
className="relative"
|
||||||
|
>
|
||||||
|
<div className="relative overflow-hidden flex items-center gap-1.5 md:gap-2.5 border-r border-[#292929] text-white cursor-pointer justify-between py-2 px-3 md:px-4 md:py-3.5 md:w-50 font-sans bg-[#0F0F0F] hover:bg-[#FFFFFF1F] transition-colors duration-300">
|
||||||
|
<CTALines />
|
||||||
|
<span className="relative z-10 tracking-tight text-[12px] md:text-[16px] whitespace-nowrap">
|
||||||
|
Read docs
|
||||||
|
</span>
|
||||||
|
<span className="relative z-10 scale-75 md:scale-100">
|
||||||
|
<IconCTADocs />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="hero-cta flex flex-nowrap gap-2 md:gap-3 ml-2 md:ml-3 h-10.5 md:h-12.5 flex-1">
|
||||||
|
<div className="border-r border-[#292929] h-full hidden md:block" />
|
||||||
|
<div className="border-r border-[#292929] h-full hidden md:block" />
|
||||||
|
<div className="border-r border-[#292929] h-full hidden md:block" />
|
||||||
|
|
||||||
|
<div className="border-r border-[#292929] h-full hidden min-[400px]:block" />
|
||||||
|
<div className="border-r border-[#292929] h-full hidden md:block" />
|
||||||
|
<div className="border-r border-[#292929] h-full hidden md:block" />
|
||||||
|
<div className="border-r border-[#292929] h-full hidden md:block" />
|
||||||
|
<div className="border-r border-[#292929] h-full hidden md:block" />
|
||||||
|
<div className="border-r border-[#292929] h-full hidden md:block" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="border-b border-[#292929]" />
|
||||||
|
{/* MOBILE VIEW*/}
|
||||||
|
<div className="relative block xl:hidden w-full overflow-hidden bg-[#0F0F0F] mt-12">
|
||||||
|
<div className="relative overflow-hidden w-full p-7 flex items-center justify-center">
|
||||||
|
<Image
|
||||||
|
className="hero-bg absolute inset-0 w-full h-full object-cover"
|
||||||
|
src="/images/hero/hero_mobile.webp"
|
||||||
|
width={900}
|
||||||
|
height={800}
|
||||||
|
alt="hero-bg-mobile"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="hero-reveal relative z-10 w-[96%] sm:w-[90%] max-w-[520px] flex justify-center items-center">
|
||||||
|
{/* <AutumnConfig lines={16} initialDelay={1000} awaitEvent="preloader:complete" /> */}
|
||||||
|
<Image
|
||||||
|
src={"/images/hero/autumn_mobile.svg"}
|
||||||
|
width={1600}
|
||||||
|
height={1600}
|
||||||
|
alt="xyz"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
46
apps/website/components/home-sections.jsx
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import dynamic from "next/dynamic";
|
||||||
|
import Hero from "./hero";
|
||||||
|
import SectionDivider from "./section-divider";
|
||||||
|
|
||||||
|
const ProductionScale = dynamic(() => import("@/components/production-scale"), {
|
||||||
|
ssr: false,
|
||||||
|
});
|
||||||
|
const Problem = dynamic(() => import("@/components/problem"), { ssr: false });
|
||||||
|
const Solution = dynamic(() => import("@/components/solution"), { ssr: false });
|
||||||
|
const Features = dynamic(() => import("@/components/features"), { ssr: false });
|
||||||
|
const PricingModels = dynamic(() => import("@/components/pricing-models"), {
|
||||||
|
ssr: false,
|
||||||
|
});
|
||||||
|
const Testimonials = dynamic(() => import("@/components/testimonials"), {
|
||||||
|
ssr: false,
|
||||||
|
});
|
||||||
|
const Pricing = dynamic(() => import("@/components/pricing"), { ssr: false });
|
||||||
|
const FAQ = dynamic(() => import("@/components/faq"), { ssr: false });
|
||||||
|
const Footer = dynamic(() => import("@/components/footer"), { ssr: false });
|
||||||
|
|
||||||
|
export default function HomeSections() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Hero />
|
||||||
|
<SectionDivider title="PRODUCTION SCALE" />
|
||||||
|
<ProductionScale />
|
||||||
|
<SectionDivider title="THE PROBLEM" />
|
||||||
|
<Problem />
|
||||||
|
<SectionDivider title="THE SOLUTION" />
|
||||||
|
<Solution />
|
||||||
|
<SectionDivider title="FEATURES" />
|
||||||
|
<Features />
|
||||||
|
<SectionDivider title="PRICING MODELS" />
|
||||||
|
<PricingModels />
|
||||||
|
<SectionDivider title="TESTIMONIALS" />
|
||||||
|
<Testimonials />
|
||||||
|
<SectionDivider title="PRICING" />
|
||||||
|
<Pricing />
|
||||||
|
<SectionDivider title="FAQ" />
|
||||||
|
<FAQ />
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
442
apps/website/components/navbar.jsx
Executable file
@@ -0,0 +1,442 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CTALines,
|
||||||
|
IconBlog,
|
||||||
|
IconCTAStart,
|
||||||
|
IconDashboard,
|
||||||
|
IconDiscord,
|
||||||
|
IconDocs,
|
||||||
|
IconPricing,
|
||||||
|
MenuGridIcon,
|
||||||
|
} from "@/app/constant";
|
||||||
|
import { useGSAP } from "@gsap/react";
|
||||||
|
import gsap from "gsap";
|
||||||
|
import { motion } from "motion/react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
import {
|
||||||
|
forwardRef,
|
||||||
|
useEffect,
|
||||||
|
useImperativeHandle,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
import { DashboardIconPixel } from "./dashboard-icon-pixel";
|
||||||
|
|
||||||
|
const NAV_LINKS = [
|
||||||
|
{
|
||||||
|
label: "Discord",
|
||||||
|
href: "https://discord.com/invite/STqxY92zuS",
|
||||||
|
Icon: IconDiscord,
|
||||||
|
},
|
||||||
|
{ label: "Blog", href: "https://useautumn.com/blog", Icon: IconBlog },
|
||||||
|
{ label: "Docs", href: "https://docs.useautumn.com/welcome", Icon: IconDocs },
|
||||||
|
{ label: "Pricing", href: "#", Icon: IconPricing },
|
||||||
|
];
|
||||||
|
|
||||||
|
const NavIconPixel = forwardRef(function NavIconPixel({ Icon }, ref) {
|
||||||
|
const iconRef = useRef(null);
|
||||||
|
const pulseRef = useRef(null);
|
||||||
|
const tlRef = useRef(null);
|
||||||
|
|
||||||
|
const frames = [
|
||||||
|
"\u2800\u2836\u2800",
|
||||||
|
"\u2830\u28FF\u2806",
|
||||||
|
"\u28BE\u28C9\u2877",
|
||||||
|
"\u28CF\u2800\u28F9",
|
||||||
|
"\u2841\u2800\u2888",
|
||||||
|
];
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
restart: () => {
|
||||||
|
tlRef.current?.play();
|
||||||
|
},
|
||||||
|
reverse: () => {
|
||||||
|
tlRef.current?.reverse();
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const pixels = iconRef.current?.querySelectorAll(".icon-pixel-path");
|
||||||
|
const pulseEl = pulseRef.current;
|
||||||
|
if (!pixels || !pulseEl) return;
|
||||||
|
|
||||||
|
gsap.set(pixels, {
|
||||||
|
opacity: 0.15,
|
||||||
|
scale: 0.8,
|
||||||
|
transformOrigin: "left bottom",
|
||||||
|
fill: "currentColor",
|
||||||
|
});
|
||||||
|
gsap.set(pulseEl, { opacity: 0 });
|
||||||
|
|
||||||
|
tlRef.current = gsap.timeline({ paused: true });
|
||||||
|
|
||||||
|
tlRef.current
|
||||||
|
.to(pixels, { opacity: 0, duration: 0.05 })
|
||||||
|
.to(pulseEl, { opacity: 1, duration: 0.05 }, "<")
|
||||||
|
.to(pulseEl, {
|
||||||
|
duration: 0.3,
|
||||||
|
onUpdate: function () {
|
||||||
|
const frameIndex = Math.floor(this.progress() * (frames.length - 1));
|
||||||
|
pulseEl.innerText = frames[frameIndex];
|
||||||
|
},
|
||||||
|
ease: "none",
|
||||||
|
})
|
||||||
|
// 3. REVEAL: Pulse fades, SVG Icon sweeps in from bottom-left
|
||||||
|
.to(pulseEl, { opacity: 0, duration: 0.1, scale: 1.2 })
|
||||||
|
.to(
|
||||||
|
pixels,
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
scale: 1.15,
|
||||||
|
fill: "#FFFFFF",
|
||||||
|
duration: 0.2,
|
||||||
|
stagger: {
|
||||||
|
grid: [5, 5],
|
||||||
|
from: [0, 4], // Bottom-Left scan
|
||||||
|
amount: 0.25,
|
||||||
|
},
|
||||||
|
ease: "power2.out",
|
||||||
|
},
|
||||||
|
"-=0.1",
|
||||||
|
)
|
||||||
|
.to(pixels, {
|
||||||
|
scale: 1,
|
||||||
|
duration: 0.15,
|
||||||
|
ease: "back.out(3)",
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => tlRef.current?.kill();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className="relative inline-flex items-center justify-center w-8 h-8 group/icon">
|
||||||
|
{/* BACKGROUND MASK: Static field dots */}
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
|
||||||
|
<div className="grid grid-cols-5 grid-rows-5 gap-[3px]">
|
||||||
|
{Array.from({ length: 25 }).map((_, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="bg-white/[0.08] w-[1px] h-[1px] rounded-[0.5px]"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* BRAILLE PULSE LAYER */}
|
||||||
|
<div
|
||||||
|
ref={pulseRef}
|
||||||
|
className="absolute z-20 font-mono text-[16px] text-white pointer-events-none select-none"
|
||||||
|
>
|
||||||
|
{"\u2800\u2836\u2800"}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* SVG ICON LAYER (Idle: Faded / Hover: Solid) */}
|
||||||
|
<div className="relative z-10 w-[16px] h-[16px] flex items-center justify-center">
|
||||||
|
<Icon ref={iconRef} className="w-full h-full text-white" />
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
function NavLinkItem({ item }) {
|
||||||
|
const iconRef = useRef(null);
|
||||||
|
return (
|
||||||
|
<div className="nav-link">
|
||||||
|
<Link
|
||||||
|
href={item.href}
|
||||||
|
className="group inline-flex items-center py-2 text-[#FFFFFF99] hover:text-white transition-colors"
|
||||||
|
onMouseEnter={() => iconRef.current?.restart()}
|
||||||
|
onMouseLeave={() => iconRef.current?.reverse()}
|
||||||
|
>
|
||||||
|
<NavIconPixel Icon={item.Icon} ref={iconRef} />
|
||||||
|
<span className="font-mono text-[14px] uppercase tracking-widest transition-colors group-hover:text-white">
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Navbar() {
|
||||||
|
const containerRef = useRef(null);
|
||||||
|
const dashboardIconRef = useRef(null);
|
||||||
|
const RECOIL_DELAY = 1000;
|
||||||
|
const [recoilHidden, setRecoilHidden] = useState(false);
|
||||||
|
const recoilTimerRef = useRef(null);
|
||||||
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
|
const [scrolled, setScrolled] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => setScrolled(window.scrollY > 10);
|
||||||
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
||||||
|
return () => window.removeEventListener("scroll", handleScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const onRecoil = () => {
|
||||||
|
setRecoilHidden(true);
|
||||||
|
clearTimeout(recoilTimerRef.current);
|
||||||
|
recoilTimerRef.current = setTimeout(
|
||||||
|
() => setRecoilHidden(false),
|
||||||
|
RECOIL_DELAY,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
window.addEventListener("elastic-recoil", onRecoil);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("elastic-recoil", onRecoil);
|
||||||
|
clearTimeout(recoilTimerRef.current);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Lock body scroll while mobile menu is open
|
||||||
|
useEffect(() => {
|
||||||
|
document.documentElement.style.overflow = menuOpen ? "hidden" : "";
|
||||||
|
document.body.style.overflow = menuOpen ? "hidden" : "";
|
||||||
|
return () => {
|
||||||
|
document.documentElement.style.overflow = "";
|
||||||
|
document.body.style.overflow = "";
|
||||||
|
};
|
||||||
|
}, [menuOpen]);
|
||||||
|
|
||||||
|
useGSAP(
|
||||||
|
() => {
|
||||||
|
gsap.set(".nav-root", { opacity: 0 });
|
||||||
|
gsap.set(".nav-logo", {
|
||||||
|
opacity: 0,
|
||||||
|
filter: "blur(6px) brightness(1)",
|
||||||
|
scale: 0.92,
|
||||||
|
transformOrigin: "left center",
|
||||||
|
});
|
||||||
|
gsap.set(".nav-link", { opacity: 0, y: -8 });
|
||||||
|
gsap.set(".nav-dashboard", { opacity: 0, scale: 0.95 });
|
||||||
|
|
||||||
|
const tl = gsap.timeline({ defaults: { overwrite: "auto" } });
|
||||||
|
|
||||||
|
tl.to(".nav-root", { opacity: 1, duration: 0.3, ease: "none" })
|
||||||
|
.to(".nav-logo", {
|
||||||
|
opacity: 1,
|
||||||
|
filter: "blur(0px) brightness(1)",
|
||||||
|
scale: 1,
|
||||||
|
duration: 0.7,
|
||||||
|
ease: "power2.out",
|
||||||
|
})
|
||||||
|
.to(".nav-logo", {
|
||||||
|
filter: "blur(0px) brightness(1.6)",
|
||||||
|
duration: 0.225,
|
||||||
|
ease: "power2.in",
|
||||||
|
})
|
||||||
|
.to(".nav-logo", {
|
||||||
|
filter: "blur(0px) brightness(1)",
|
||||||
|
duration: 0.125,
|
||||||
|
ease: "power2.out",
|
||||||
|
})
|
||||||
|
.to(
|
||||||
|
".nav-link",
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
duration: 0.25,
|
||||||
|
stagger: 0.06,
|
||||||
|
ease: "power2.out",
|
||||||
|
},
|
||||||
|
"-=0.05",
|
||||||
|
)
|
||||||
|
.to(
|
||||||
|
".nav-dashboard",
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
scale: 1,
|
||||||
|
duration: 0.3,
|
||||||
|
ease: "back.out(1.5)",
|
||||||
|
},
|
||||||
|
"-=0.1",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ scope: containerRef },
|
||||||
|
);
|
||||||
|
|
||||||
|
const mobileTl = useRef(null);
|
||||||
|
|
||||||
|
useGSAP(
|
||||||
|
() => {
|
||||||
|
gsap.set(".nav-mobile", {
|
||||||
|
opacity: 0,
|
||||||
|
clipPath: "inset(0% 0 100% 0)",
|
||||||
|
pointerEvents: "none",
|
||||||
|
});
|
||||||
|
|
||||||
|
gsap.set(
|
||||||
|
".nav-mobile a, .nav-mobile img, .nav-mobile button, .nav-mobile .border-b",
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
filter: "blur(8px)",
|
||||||
|
scale: 0.95,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
mobileTl.current = gsap.timeline({
|
||||||
|
paused: true,
|
||||||
|
defaults: { overwrite: "auto" },
|
||||||
|
});
|
||||||
|
|
||||||
|
mobileTl.current
|
||||||
|
.to(".nav-mobile", {
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
pointerEvents: "auto",
|
||||||
|
clipPath: "inset(0% 0 0% 0)",
|
||||||
|
duration: 0.65,
|
||||||
|
ease: "power3.inOut",
|
||||||
|
})
|
||||||
|
.to(
|
||||||
|
".nav-mobile a, .nav-mobile img, .nav-mobile button, .nav-mobile .border-b",
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
filter: "blur(0px)",
|
||||||
|
scale: 1,
|
||||||
|
duration: 0.4,
|
||||||
|
stagger: 0.02,
|
||||||
|
ease: "power2.out",
|
||||||
|
},
|
||||||
|
"-=0.35",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ scope: containerRef },
|
||||||
|
);
|
||||||
|
|
||||||
|
useGSAP(
|
||||||
|
() => {
|
||||||
|
if (mobileTl.current) {
|
||||||
|
if (menuOpen) {
|
||||||
|
mobileTl.current.timeScale(1).play();
|
||||||
|
} else {
|
||||||
|
mobileTl.current.timeScale(1.8).reverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ scope: containerRef, dependencies: [menuOpen] },
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{ "--page-pad": "max(2.5rem, calc((100vw - 1440px) / 2))" }}
|
||||||
|
ref={containerRef}
|
||||||
|
>
|
||||||
|
<div className="absolute pointer-events-none left-0 border-t border-[#292929] w-screen z-50" />
|
||||||
|
{scrolled && !recoilHidden && (
|
||||||
|
<div className="h-[56px] md:h-[44px] w-fit" />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`${scrolled && !recoilHidden
|
||||||
|
? "fixed top-0 left-0 z-80 w-full px-4 md:px-(--page-pad) bg-[#0F0F0F] backdrop-blur-md border-b border-t pt-4 border-[#292929]"
|
||||||
|
: "relative"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{scrolled && !recoilHidden && (
|
||||||
|
<>
|
||||||
|
<div className="absolute pointer-events-none top-4 left-0 w-full border-t border-[#292929]" />
|
||||||
|
<div className="absolute pointer-events-none left-4 md:left-(--page-pad) top-0 bottom-0 border-l border-[#292929]" />
|
||||||
|
<div className="absolute pointer-events-none right-4 md:right-(--page-pad) top-0 bottom-0 border-r border-[#292929]" />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<nav className="nav-root bg-[#0F0F0F] flex items-center justify-between font-mono uppercase text-xs pl-2 pt-2.5 lg:py-0 xl:py-0 pb-2.5 lg:pb-0 xl:pb-0">
|
||||||
|
<Link href={"/"}>
|
||||||
|
<Image
|
||||||
|
src="/images/navbar/autumnlogo.svg"
|
||||||
|
width={114}
|
||||||
|
height={28}
|
||||||
|
alt="Autumn"
|
||||||
|
loading="lazy"
|
||||||
|
className="nav-logo ml-2 block w-[90px] sm:w-[110px] lg:w-[114px] h-auto"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<div className="hidden md:flex items-center gap-6">
|
||||||
|
{NAV_LINKS.map((item) => (
|
||||||
|
<NavLinkItem key={item.label} item={item} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="nav-dashboard hidden md:block">
|
||||||
|
<motion.div
|
||||||
|
initial="initial"
|
||||||
|
whileHover="hover"
|
||||||
|
whileTap={{ scale: 0.97 }}
|
||||||
|
className="relative"
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href="https://useautumn.com"
|
||||||
|
target="_blank"
|
||||||
|
className="relative overflow-hidden inline-flex items-center gap-2 bg-[#9564ff] hover:bg-[#7D46F4] active:bg-[#7D46F4] transition-colors duration-300 px-4 py-3.5 text-white cursor-pointer whitespace-nowrap"
|
||||||
|
onMouseEnter={() => dashboardIconRef.current?.restart()}
|
||||||
|
onMouseLeave={() => dashboardIconRef.current?.reverse()}
|
||||||
|
>
|
||||||
|
<CTALines />
|
||||||
|
<div className="relative z-10 flex items-center gap-2">
|
||||||
|
<DashboardIconPixel
|
||||||
|
Icon={IconDashboard}
|
||||||
|
ref={dashboardIconRef}
|
||||||
|
/>
|
||||||
|
<span className="font-sans font-medium tracking-tight">
|
||||||
|
Dashboard
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<motion.button
|
||||||
|
className="md:hidden mr-2 p-1.5 text-[#FFFFFF99] cursor-pointer"
|
||||||
|
onClick={() => setMenuOpen(!menuOpen)}
|
||||||
|
whileTap={{ scale: 0.9 }}
|
||||||
|
aria-label="Toggle menu"
|
||||||
|
>
|
||||||
|
<MenuGridIcon isOpen={menuOpen} />
|
||||||
|
</motion.button>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`fixed w-full nav-mobile left-0 overflow-y-auto bg-[#000000] flex flex-col font-mono uppercase ${scrolled && !recoilHidden ? "top-[62px] sm:top-[60px]" : "top-[66px] sm:top-[62px]"} md:top-5 h-[calc(100dvh-58px)] z-40 px-4 pb-8 transition-all duration-300`}
|
||||||
|
style={{ opacity: 0, pointerEvents: "none", clipPath: "inset(0% 0 100% 0)" }}
|
||||||
|
>
|
||||||
|
{/* Nav items */}
|
||||||
|
<div className="flex flex-col">
|
||||||
|
{NAV_LINKS.map((item) => (
|
||||||
|
<Link
|
||||||
|
key={item.label}
|
||||||
|
href={item.href}
|
||||||
|
target="_blank"
|
||||||
|
className="flex items-center gap-4 px-4 py-3.5 border-b border-[#292929] active:bg-[#141414ea] text-[#ffffff99] hover:text-white active:text-white transition-colors text-sm tracking-[-1%]"
|
||||||
|
>
|
||||||
|
<item.Icon className="h-3.5 w-3.5 shrink-0" />
|
||||||
|
<span>{item.label}</span>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col mt-auto -mb-2.5">
|
||||||
|
<div className="border-t border-[#292929] py-1.5" />
|
||||||
|
<div className="px-4">
|
||||||
|
<Link
|
||||||
|
href="https://useautumn.com"
|
||||||
|
target="_blank"
|
||||||
|
onClick={() => setMenuOpen(false)}
|
||||||
|
className="flex items-center justify-between gap-4 px-2 py-2.5 bg-[#9564ff] active:bg-[#7D46F4] transition-colors duration-300 text-white text-sm tracking-widest"
|
||||||
|
>
|
||||||
|
<span className="tracking-[-2%] text-sm">Start for free</span>
|
||||||
|
<IconCTAStart className="h-3.5 w-3.5" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
{Array.from({ length: 3 }).map((_, i) => (
|
||||||
|
<div key={i} className="border-b border-[#292929] py-1.5" />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{!scrolled && (
|
||||||
|
<div className="absolute pointer-events-none left-0 border-b border-[#292929] w-full z-50" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
238
apps/website/components/preloader.jsx
Executable file
@@ -0,0 +1,238 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import gsap from "gsap";
|
||||||
|
import {
|
||||||
|
PRELOADER_LOGO_PATH,
|
||||||
|
PRELOADER_LOGO_VIEWBOX,
|
||||||
|
PreloaderLogo,
|
||||||
|
} from "@/app/constant";
|
||||||
|
|
||||||
|
export default function Preloader() {
|
||||||
|
const wrapperRef = useRef(null);
|
||||||
|
const logoWrapRef = useRef(null);
|
||||||
|
const gridWrapRef = useRef(null);
|
||||||
|
const blackCoverRef = useRef(null);
|
||||||
|
const fallbackRef = useRef(null);
|
||||||
|
const [done, setDone] = useState(false);
|
||||||
|
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
window.history.scrollRestoration = "manual";
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
document.documentElement.scrollTop = 0;
|
||||||
|
document.body.scrollTop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
document.documentElement.scrollTop = 0;
|
||||||
|
document.body.scrollTop = 0;
|
||||||
|
|
||||||
|
if (fallbackRef.current) {
|
||||||
|
fallbackRef.current.style.opacity = "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
const preventScroll = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("wheel", preventScroll, {
|
||||||
|
passive: false,
|
||||||
|
capture: true,
|
||||||
|
});
|
||||||
|
window.addEventListener("touchmove", preventScroll, {
|
||||||
|
passive: false,
|
||||||
|
capture: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const wrapper = wrapperRef.current;
|
||||||
|
const logoWrap = logoWrapRef.current;
|
||||||
|
const gridWrap = gridWrapRef.current;
|
||||||
|
const blackCover = blackCoverRef.current;
|
||||||
|
|
||||||
|
gsap.set(gridWrap, {
|
||||||
|
clipPath: "inset(0 100% 0 0)",
|
||||||
|
willChange: "clip-path",
|
||||||
|
force3D: true,
|
||||||
|
});
|
||||||
|
gsap.set(blackCover, { opacity: 0, willChange: "opacity" });
|
||||||
|
|
||||||
|
const logoSvg = logoWrap.querySelector("svg");
|
||||||
|
gsap.set(logoSvg, { opacity: 0 });
|
||||||
|
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
Object.assign(canvas.style, {
|
||||||
|
position: "absolute",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
pointerEvents: "none",
|
||||||
|
});
|
||||||
|
wrapper.appendChild(canvas);
|
||||||
|
|
||||||
|
const cleanup = () => {
|
||||||
|
document.documentElement.style.overflow = "";
|
||||||
|
document.body.style.overflow = "";
|
||||||
|
document.body.style.paddingRight = "";
|
||||||
|
window.removeEventListener("wheel", preventScroll, { capture: true });
|
||||||
|
window.removeEventListener("touchmove", preventScroll, {
|
||||||
|
capture: true,
|
||||||
|
});
|
||||||
|
if (canvas.parentNode) canvas.parentNode.removeChild(canvas);
|
||||||
|
};
|
||||||
|
|
||||||
|
const runExitSequence = () => {
|
||||||
|
const tl = gsap.timeline({ defaults: { overwrite: "auto" } });
|
||||||
|
|
||||||
|
tl.to(canvas, { opacity: 0, duration: 0.35, ease: "power2.out" })
|
||||||
|
.to(
|
||||||
|
gridWrap,
|
||||||
|
{
|
||||||
|
clipPath: "inset(0 0% 0 0)",
|
||||||
|
duration: 0.35,
|
||||||
|
ease: "power2.out",
|
||||||
|
force3D: true,
|
||||||
|
},
|
||||||
|
"<",
|
||||||
|
)
|
||||||
|
.to(blackCover, {
|
||||||
|
opacity: 1,
|
||||||
|
duration: 0.45,
|
||||||
|
ease: "power2.inOut",
|
||||||
|
})
|
||||||
|
.to(wrapper, {
|
||||||
|
opacity: 0,
|
||||||
|
duration: 0.45,
|
||||||
|
ease: "power2.inOut",
|
||||||
|
onStart: () => {
|
||||||
|
window.dispatchEvent(new CustomEvent("preloader:complete"));
|
||||||
|
},
|
||||||
|
onComplete: () => {
|
||||||
|
cleanup();
|
||||||
|
setDone(true);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
gsap.to(gridWrap, {
|
||||||
|
clipPath: "inset(0 12% 0 0)",
|
||||||
|
duration: 0.8,
|
||||||
|
ease: "power2.in",
|
||||||
|
force3D: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const W = PRELOADER_LOGO_VIEWBOX.width;
|
||||||
|
const H = PRELOADER_LOGO_VIEWBOX.height;
|
||||||
|
|
||||||
|
const offscreen = document.createElement("canvas");
|
||||||
|
offscreen.width = W;
|
||||||
|
offscreen.height = H;
|
||||||
|
const octx = offscreen.getContext("2d");
|
||||||
|
const path2d = new Path2D(PRELOADER_LOGO_PATH);
|
||||||
|
octx.fillStyle = "white";
|
||||||
|
octx.fill(path2d);
|
||||||
|
const { data } = octx.getImageData(0, 0, W, H);
|
||||||
|
|
||||||
|
const dpr = window.devicePixelRatio || 1;
|
||||||
|
const displayW =
|
||||||
|
logoSvg.offsetWidth || logoSvg.getBoundingClientRect().width || 54;
|
||||||
|
const displayH = Math.round((displayW / W) * H);
|
||||||
|
const isMobile = displayW < 70;
|
||||||
|
|
||||||
|
const STEP = isMobile ? 6 : 4;
|
||||||
|
const DOT_R = isMobile
|
||||||
|
? Math.max(0.6, (displayW / W) * STEP * 0.3)
|
||||||
|
: Math.max(1, (displayW / W) * STEP * 0.45);
|
||||||
|
|
||||||
|
const dots = [];
|
||||||
|
for (let y = 0; y < H; y += STEP) {
|
||||||
|
for (let x = 0; x < W; x += STEP) {
|
||||||
|
const i = (y * W + x) * 4;
|
||||||
|
if (data[i + 3] > 40) {
|
||||||
|
dots.push({ nx: x / W, ny: y / H });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = dots.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
|
[dots[i], dots[j]] = [dots[j], dots[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.width = displayW * dpr;
|
||||||
|
canvas.height = displayH * dpr;
|
||||||
|
canvas.style.width = `${displayW}px`;
|
||||||
|
canvas.style.height = `${displayH}px`;
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
ctx.scale(dpr, dpr);
|
||||||
|
|
||||||
|
let painted = 0;
|
||||||
|
const total = dots.length;
|
||||||
|
const progress = { value: 0 };
|
||||||
|
|
||||||
|
gsap.to(progress, {
|
||||||
|
value: 1,
|
||||||
|
duration: 1.05,
|
||||||
|
ease: "power1.inOut",
|
||||||
|
onUpdate() {
|
||||||
|
const target = Math.floor(progress.value * total);
|
||||||
|
while (painted < target) {
|
||||||
|
const d = dots[painted];
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(d.nx * displayW, d.ny * displayH, DOT_R, 0, Math.PI * 2);
|
||||||
|
ctx.fillStyle = "#9564FF";
|
||||||
|
ctx.fill();
|
||||||
|
painted++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onComplete() {
|
||||||
|
gsap.delayedCall(0.2, runExitSequence);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, 120);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cleanup();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (done) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={wrapperRef}
|
||||||
|
className="fixed inset-0 z-[9999] bg-black"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
ref={fallbackRef}
|
||||||
|
className="absolute inset-0 flex items-center justify-center z-10 pointer-events-none transition-opacity duration-300"
|
||||||
|
>
|
||||||
|
<PreloaderLogo className="w-[53.57px] md:w-[97.94px] h-auto opacity-20" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center">
|
||||||
|
<div ref={logoWrapRef}>
|
||||||
|
<PreloaderLogo className="w-[53.57px] md:w-[97.94px] h-auto" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ref={gridWrapRef} className="absolute bottom-0 left-0 w-full">
|
||||||
|
<img
|
||||||
|
src="/images/preloader/grid.png"
|
||||||
|
width={1440}
|
||||||
|
height={217}
|
||||||
|
alt=""
|
||||||
|
className="w-full h-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
ref={blackCoverRef}
|
||||||
|
className="absolute inset-0 bg-black pointer-events-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
258
apps/website/components/pricing-models.jsx
Executable file
@@ -0,0 +1,258 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { CTALines, IconCTAStart } from "@/app/constant";
|
||||||
|
import { AnimatePresence, motion } from "motion/react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
const sidebarItems = [
|
||||||
|
{
|
||||||
|
id: "subscriptions",
|
||||||
|
label: "Subscriptions",
|
||||||
|
model: 0,
|
||||||
|
desc: "Monthly or yearly plans with feature gating. Upgrades and downgrades handled automatically. Proration included.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "free-trials",
|
||||||
|
label: "Free Trials",
|
||||||
|
model: 2,
|
||||||
|
desc: "Card-required or card-optional trials. Auto-convert to paid. Configurable trial lengths per plan.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "credits",
|
||||||
|
label: "Credits & Top-ups",
|
||||||
|
model: 1,
|
||||||
|
desc: "Prepaid credits that features draw from. One-time purchases or auto-refill. Set minimum thresholds.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "usage",
|
||||||
|
label: "Usage-Based",
|
||||||
|
model: 4,
|
||||||
|
desc: "Pay for what you use. Real-time metering, overage handling, usage resets. Combine with base\u00a0subscriptions.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "seat",
|
||||||
|
label: "Seat-Based",
|
||||||
|
model: 6,
|
||||||
|
desc: "Per-user pricing with seat limits. Add or remove seats dynamically. Automatic proration.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "hybrid",
|
||||||
|
label: "Hybrid Models",
|
||||||
|
model: 5,
|
||||||
|
desc: "Mix subscriptions, usage, credits, and seats in one plan. Example: $50/month + $0.02/token + 5 seats included.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "rollovers",
|
||||||
|
label: "Rollovers & Expirations",
|
||||||
|
model: 7,
|
||||||
|
desc: "Roll credits to next period or expire after X days. Configure per plan or per feature.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "enterprise",
|
||||||
|
label: "Custom Enterprise",
|
||||||
|
model: 3,
|
||||||
|
desc: "One-off pricing for large customers. Unique limits, custom billing cycles, manual overrides—all in the dashboard.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function PricingModels() {
|
||||||
|
const [activeTab, setActiveTab] = useState(sidebarItems[0]);
|
||||||
|
|
||||||
|
const images = {
|
||||||
|
0: "/images/pricing-models/Subscriptions.webp",
|
||||||
|
1: "/images/pricing-models/Subscriptions (1).webp",
|
||||||
|
2: "/images/pricing-models/Trial Configuration.webp",
|
||||||
|
3: "/images/pricing-models/Hybrid Plan Builder.webp",
|
||||||
|
4: "/images/pricing-models/Usage Metering.webp",
|
||||||
|
5: "/images/pricing-models/Hybrid Plan Builder (1).webp",
|
||||||
|
6: "/images/pricing-models/Subscriptions (2).webp",
|
||||||
|
7: "/images/pricing-models/Subscriptions (3).webp",
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="bg-[#000000] w-full overflow-hidden flex flex-col">
|
||||||
|
<div className="hidden lg:flex w-full items-center justify-between py-24 relative z-10 px-4 xl:px-22.75">
|
||||||
|
<div className="flex w-full">
|
||||||
|
<div className="">
|
||||||
|
<h2 className="text-[40px] leading-[1.1] font-sans tracking-[-2%] font-normal">
|
||||||
|
<span className="text-[#FFFFFF99]">Any pricing model.</span>{" "}
|
||||||
|
<span className="text-white">Seriously.</span>
|
||||||
|
</h2>
|
||||||
|
<div className="mt-4 text-[16px] font-sans leading-relaxed tracking-[-1%] font-light">
|
||||||
|
<span className="text-[#FFFFFF99]">
|
||||||
|
Configure in the dashboard.
|
||||||
|
</span>{" "}
|
||||||
|
<span className="text-white">Change without code deploys.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="hero-cta">
|
||||||
|
<Link href={"https://useautumn.com/"} target="_blank">
|
||||||
|
<motion.div
|
||||||
|
initial="initial"
|
||||||
|
whileHover="hover"
|
||||||
|
whileTap="tap"
|
||||||
|
className="relative"
|
||||||
|
>
|
||||||
|
<div className="relative overflow-hidden flex items-center cursor-pointer justify-between px-4 py-3.5 md:w-50 font-sans bg-[#9564ff] hover:bg-[#7D46F4] active:bg-[#7D46F4] transition-colors duration-300 whitespace-nowrap">
|
||||||
|
<CTALines />
|
||||||
|
<span className="relative z-10 tracking-tight text-white font-medium">
|
||||||
|
View templates
|
||||||
|
</span>
|
||||||
|
<span className="relative z-10">
|
||||||
|
<IconCTAStart />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-t-0 lg:border-t border-[#292929] w-full relative grid grid-cols-1 lg:grid-cols-[60px_220px_220px_1fr] xl:grid-cols-[90px_291px_300px_1fr] auto-rows-auto lg:grid-rows-[260px_340px]">
|
||||||
|
<div className="absolute top-0 bottom-0 right-0 lg:w-[calc(100%-500px)] xl:w-[calc(100%-680px)] z-0 overflow-hidden hidden lg:block pointer-events-none">
|
||||||
|
<video
|
||||||
|
src="/images/pricing-models/pricingbg.webm"
|
||||||
|
autoPlay
|
||||||
|
loop
|
||||||
|
muted
|
||||||
|
playsInline
|
||||||
|
className="absolute inset-0 w-full h-full object-cover object-left 2xl:object-center mix-blend-screen opacity-100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="hidden lg:block border-l border-r border-b border-[#292929] min-h-[120px] lg:min-h-[260px]"></div>
|
||||||
|
<div className="hidden lg:block border-r border-b border-[#292929]"></div>
|
||||||
|
<div className="hidden z-20 lg:block border-r border-b bg-[#0F0F0F] border-[#292929]"></div>
|
||||||
|
<div className="hidden lg:flex lg:row-span-2 items-end justify-center lg:pl-4 lg:pr-4 relative z-10 w-full lg:h-full order-first lg:order-0 mt-0 xl:mt-10.5">
|
||||||
|
<div className="relative z-10 w-full lg:max-w-120 xl:max-w-150 h-auto overflow-hidden">
|
||||||
|
<div className="relative w-full aspect-square">
|
||||||
|
{Object.entries(images).map(([key, src]) => {
|
||||||
|
const isActive = activeTab.model === Number(key);
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
key={key}
|
||||||
|
initial={false}
|
||||||
|
animate={{
|
||||||
|
opacity: isActive ? 1 : 0,
|
||||||
|
scale: isActive ? 1 : 0.98,
|
||||||
|
}}
|
||||||
|
transition={{ duration: 0.25 }}
|
||||||
|
className="absolute inset-0"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={src}
|
||||||
|
alt="Pricing Model"
|
||||||
|
fill
|
||||||
|
sizes="(max-width: 768px) 100vw, 50vw"
|
||||||
|
className="object-contain"
|
||||||
|
priority={key === "0"}
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="hidden lg:block border-l border-r border-[#292929]"></div>
|
||||||
|
<div
|
||||||
|
className={`border-r border-[#292929] flex flex-col py-0 lg:py-[32px] z-10 relative bg-[#000000]`}
|
||||||
|
>
|
||||||
|
<ul className="flex flex-col">
|
||||||
|
{sidebarItems.map((item) => {
|
||||||
|
const isActive = activeTab.id === item.id;
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={item.id}
|
||||||
|
onClick={() => setActiveTab(item)}
|
||||||
|
className={`flex flex-col cursor-pointer transition-colors border-b last:border-b-0 lg:border-none border-[#292929] ${
|
||||||
|
isActive ? "lg:bg-transparent bg-[#0f0f0f]" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{/* Mobile Accordion Image */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{isActive && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ height: 0, opacity: 0 }}
|
||||||
|
animate={{ height: "auto", opacity: 1 }}
|
||||||
|
exit={{ height: 0, opacity: 0 }}
|
||||||
|
className="block lg:hidden w-full relative overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="relative w-full aspect-3/2.5 sm:aspect-square">
|
||||||
|
<div className="absolute inset-0 z-0 pointer-events-none">
|
||||||
|
<video
|
||||||
|
src="/images/pricing-models/pricingbg.webm"
|
||||||
|
autoPlay
|
||||||
|
loop
|
||||||
|
muted
|
||||||
|
playsInline
|
||||||
|
className="absolute inset-0 w-full h-full object-cover object-left mix-blend-screen opacity-100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="absolute bottom-0 left-0 right-0 z-10 flex items-center justify-center px-2.5 pt-2">
|
||||||
|
<img
|
||||||
|
src={images[item.model]}
|
||||||
|
alt="Pricing Model"
|
||||||
|
className="w-full h-auto max-h-full object-contain object-bottom"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`text-[20px] lg:text-[20px] tracking-[-5%] leading-none lg:leading-[20px] flex items-center gap-2 font-sans px-6 lg:px-[14px] py-5 lg:py-1.5 ${
|
||||||
|
isActive
|
||||||
|
? "text-white lg:text-[#FFFFFF99]"
|
||||||
|
: "text-[#FFFFFF99] lg:text-[#FFFFFF99] lg:opacity-50"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="w-[3px] h-[24px] hidden lg:block">
|
||||||
|
{isActive && (
|
||||||
|
<motion.div
|
||||||
|
layoutId="activeTabIndicator"
|
||||||
|
className="w-[3px] h-[24px] bg-[#9564FF]"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{item.label}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile Accordion Description */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{isActive && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ height: 0, opacity: 0 }}
|
||||||
|
animate={{ height: "auto", opacity: 1 }}
|
||||||
|
exit={{ height: 0, opacity: 0 }}
|
||||||
|
className="lg:hidden px-6 border-b border-[#8752FA] overflow-hidden text-[#FFFFFF99] text-[14px] md:text-[16px] lg:text-[14px] leading-[1.4] tracking-[-2%] font-light text-pretty"
|
||||||
|
>
|
||||||
|
<div className="pb-6">{item.desc}</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div className="hidden lg:flex border-b border-r lg:border-b-0 bg-[#0F0F0F] border-[#292929] flex-col justify-end p-6 z-10 relative">
|
||||||
|
<div className="text-[#FFFFFF99] text-[16px] font-sans leading-relaxed tracking-[-2%] font-light text-pretty">
|
||||||
|
<AnimatePresence mode="wait">
|
||||||
|
<motion.div
|
||||||
|
key={activeTab.id}
|
||||||
|
initial={{ opacity: 0, y: 5 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: -5 }}
|
||||||
|
transition={{ duration: 0.2 }}
|
||||||
|
>
|
||||||
|
{activeTab.desc}
|
||||||
|
</motion.div>
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
183
apps/website/components/pricing.jsx
Executable file
@@ -0,0 +1,183 @@
|
|||||||
|
"use client";
|
||||||
|
import { IconArrowRightSmall, IconTick } from "@/app/constant";
|
||||||
|
import { motion } from "motion/react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
const plans = [
|
||||||
|
{
|
||||||
|
name: "FREE",
|
||||||
|
price: "0",
|
||||||
|
description: "Perfect while finding PMF. Everything you need to start.",
|
||||||
|
features: [
|
||||||
|
"Up to 100 active customers",
|
||||||
|
"All core features",
|
||||||
|
"Community support",
|
||||||
|
"Unlimited API calls",
|
||||||
|
],
|
||||||
|
buttonText: "Get started",
|
||||||
|
href: "https://app.useautumn.com/sign-in",
|
||||||
|
isPro: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PRO",
|
||||||
|
price: "299",
|
||||||
|
description: "For teams scaling with real usage-based pricing.",
|
||||||
|
features: [
|
||||||
|
"Unlimited customers",
|
||||||
|
"Priority support",
|
||||||
|
"Custom plans",
|
||||||
|
"Usage analytics",
|
||||||
|
"SLA guarantees",
|
||||||
|
],
|
||||||
|
buttonText: "Start with Pro",
|
||||||
|
href: "https://app.useautumn.com/sign-in",
|
||||||
|
isPro: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ENTERPRISE",
|
||||||
|
price: "Custom",
|
||||||
|
description: "For compliance, scale, or custom requirements.",
|
||||||
|
features: [
|
||||||
|
"Self-hosted option",
|
||||||
|
"Dedicated support",
|
||||||
|
"Custom SLAs",
|
||||||
|
"Multi-region",
|
||||||
|
"Compliance assistance",
|
||||||
|
],
|
||||||
|
buttonText: "Book a call",
|
||||||
|
href: "https://cal.com/ayrod/a?user=ayrod",
|
||||||
|
isPro: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Pricing() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="min-h-screen relative flex w-full lg:w-[calc(100%+calc(var(--page-pad)*2))] lg:-ml-(--page-pad) items-center justify-center lg:py-24 pb-3">
|
||||||
|
{/* Desktop Background */}
|
||||||
|
<Image
|
||||||
|
src="/images/pricing/pricingbg.webp"
|
||||||
|
alt="pricing background desktop"
|
||||||
|
fill
|
||||||
|
className="object-cover absolute z-10 lg:z-50 hidden md:block"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
{/* Mobile Background */}
|
||||||
|
<Image
|
||||||
|
src="/images/pricing/pricing_mobile.webp"
|
||||||
|
alt="pricing background mobile"
|
||||||
|
fill
|
||||||
|
className="object-cover absolute z-10 lg:z-50 block md:hidden"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
<div className="relative z-20 lg:z-60 w-full pt-0 lg:pt-8 pl-4 lg:pl-[calc(var(--page-pad)+22px)] xl:pl-[calc(var(--page-pad)+90px)] pr-4 lg:pr-[calc(var(--page-pad)+22px)] xl:pr-[calc(var(--page-pad)+90px)]">
|
||||||
|
<div className="lg:bg-black text-white lg:border lg:border-[#292929] flex flex-col gap-6 lg:gap-0 border-none">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="bg-black lg:bg-transparent -mx-4 px-4 lg:mx-0 lg:px-8 py-10 lg:py-8 border-b-0 lg:border-b border-[#292929]">
|
||||||
|
<h1 className="text-[30px] leading-[32px] md:leading-[40px] md:text-3xl lg:text-[40px] tracking-[-4%] text-white font-normal w-[85%] md:w-full font-sans">
|
||||||
|
Start free. Scale with confidence.
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Pricing Columns */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 relative z-60 gap-8 lg:gap-0">
|
||||||
|
{plans.map((plan, index) => (
|
||||||
|
<div
|
||||||
|
key={plan.name}
|
||||||
|
className={`relative flex flex-col bg-black lg:bg-transparent border lg:border-0 border-[#292929] ${
|
||||||
|
index === 0 ? "lg:border-r" : ""
|
||||||
|
} ${
|
||||||
|
index === 1 ? "lg:border-r" : ""
|
||||||
|
} ${index === 2 ? "md:col-span-2 lg:col-span-1 md:w-[calc(50%-16px)] md:justify-self-center lg:w-full lg:justify-self-auto" : ""}`}
|
||||||
|
>
|
||||||
|
{plan.isPro && (
|
||||||
|
<div className="hidden lg:block absolute -inset-px z-20 pointer-events-none border border-transparent [border-image:linear-gradient(to_bottom,#A175FF,#000000)_1]"></div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{plan.isPro && (
|
||||||
|
<div className="absolute top-0 left-1/2 -translate-x-1/2 -translate-y-1/2 z-30 bg-black text-[14px] font-mono tracking-[-1%] text-white px-3 py-1.5 md:p-2.5 border border-[#A175FF]">
|
||||||
|
RECOMMENDED
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"flex flex-col h-full px-4 md:px-5 lg:px-8 pt-10 md:pt-10 lg:pt-15 pb-6 md:pb-0 relative z-10 w-full overflow-hidden"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="mb-6">
|
||||||
|
<span className="inline-block px-3 py-1 bg-[#8752FA]/20 text-[#9564FF] text-[12px] md:text-[13px] lg:text-[16px] font-mono tracking-[-2%] uppercase mb-3 md:mb-2">
|
||||||
|
{plan.name}
|
||||||
|
</span>
|
||||||
|
<div className="flex items-start gap-1 mb-2">
|
||||||
|
{plan.price !== "Custom" && (
|
||||||
|
<span className="text-sm md:text-base lg:text-xl text-white mt-1.5 md:mt-0">
|
||||||
|
$
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span className="text-[30px] md:text-[40px] leading-[44px] lg:text-5xl text-white font-normal tracking-[-2%] font-sans">
|
||||||
|
{plan.price}
|
||||||
|
</span>
|
||||||
|
{plan.price !== "Custom" && (
|
||||||
|
<span className="text-[#FFFFFF99] font-light self-end text-[13px] md:text-sm lg:text-base tracking-[-2%] mb-1.5 md:mb-0">
|
||||||
|
/month
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<p className="md:text-white font-light md:font-extralight text-[13px] md:text-[16px] tracking-[-2%] leading-[18px] md:leading-5 w-full md:w-[95%] text-pretty">
|
||||||
|
{plan.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-t border-[#27272A] w-full mb-6"></div>
|
||||||
|
|
||||||
|
<ul className="flex flex-col gap-3 md:gap-4 grow mb-10 md:mb-16.5">
|
||||||
|
{plan.features.map((feature, i) => (
|
||||||
|
<li key={i} className="flex items-start gap-3">
|
||||||
|
<IconTick className="w-4 h-4 mt-[3px] shrink-0" />
|
||||||
|
<span className="md:text-white font-light text-[14px] md:text-[16px]">
|
||||||
|
{feature}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div className="flex w-full mb-0 md:mb-8 mt-auto mx-auto pt-4 md:pt-0">
|
||||||
|
<motion.div
|
||||||
|
initial="initial"
|
||||||
|
whileHover="hover"
|
||||||
|
whileTap="hover"
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={plan.href || "#"}
|
||||||
|
target="_blank"
|
||||||
|
className="group cursor-pointer w-full flex items-center md:items-stretch justify-between transition-colors duration-300 border bg-transparent py-1 md:py-0 hover:bg-[#7641E8] active:bg-[#7641E8] border-[#292929]"
|
||||||
|
>
|
||||||
|
<span className="text-white text-[16px] md:text-[18px] pl-4 flex items-center tracking-[-1%] font-sans">
|
||||||
|
{plan.buttonText}
|
||||||
|
</span>
|
||||||
|
<div className="flex items-center justify-center w-8 h-8 md:h-auto md:w-[26px] aspect-square transition-colors duration-300 m-1.5 md:m-2.5 bg-[#514D5A] text-white group-hover:bg-white group-hover:text-[#8752FA] group-active:bg-white group-active:text-[#8752FA]">
|
||||||
|
<IconArrowRightSmall className="w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="px-6 md:px-8 py-5 md:py-6 lg:mt-[32px] border border-[#292929] lg:border-x-0 lg:border-b-0 text-left md:text-center bg-black lg:bg-transparent">
|
||||||
|
<p className="text-white text-pretty font-light leading-[18px] tracking-[-2%] md:font-extralight text-[16px] md:leading-[1.6] text-wrap-balance">
|
||||||
|
All plans include unlimited API calls · Pricing based on active
|
||||||
|
customers, not events
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
211
apps/website/components/problem-animation.jsx
Executable file
@@ -0,0 +1,211 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import gsap from "gsap";
|
||||||
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||||
|
import Matter from "matter-js";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
gsap.registerPlugin(ScrollTrigger);
|
||||||
|
|
||||||
|
const IMAGE_SOURCES = [
|
||||||
|
"/images/issues/Slack.svg",
|
||||||
|
"/images/issues/Frame%202147243001.svg",
|
||||||
|
"/images/issues/Frame%202147242729.svg",
|
||||||
|
"/images/issues/Slack-1.svg",
|
||||||
|
"/images/issues/Frame%202147243134.svg",
|
||||||
|
"/images/issues/Slack-2.svg",
|
||||||
|
"/images/issues/Frame%202147243146.svg",
|
||||||
|
"/images/issues/Stripe.svg",
|
||||||
|
];
|
||||||
|
|
||||||
|
const CATEGORY_DEFAULT = 0x0001;
|
||||||
|
const CATEGORY_CEILING = 0x0002;
|
||||||
|
|
||||||
|
export default function ProblemAnimation() {
|
||||||
|
const containerRef = useRef(null);
|
||||||
|
const engineRef = useRef(Matter.Engine.create());
|
||||||
|
const runnerRef = useRef(null);
|
||||||
|
|
||||||
|
const itemsMap = useRef(new Map());
|
||||||
|
const grabbedBodies = useRef(new Set());
|
||||||
|
const [loadedImages, setLoadedImages] = useState({});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const container = containerRef.current;
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
const { width, height } = container.getBoundingClientRect();
|
||||||
|
const engine = engineRef.current;
|
||||||
|
engine.gravity.y = 1.2;
|
||||||
|
|
||||||
|
const wallThickness = 100;
|
||||||
|
|
||||||
|
const ground = Matter.Bodies.rectangle(
|
||||||
|
width / 2,
|
||||||
|
height + wallThickness / 2,
|
||||||
|
width,
|
||||||
|
wallThickness,
|
||||||
|
{ isStatic: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
const leftWall = Matter.Bodies.rectangle(
|
||||||
|
-wallThickness / 2,
|
||||||
|
height / 2,
|
||||||
|
wallThickness,
|
||||||
|
height * 2,
|
||||||
|
{ isStatic: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
const rightWall = Matter.Bodies.rectangle(
|
||||||
|
width + wallThickness / 2,
|
||||||
|
height / 2,
|
||||||
|
wallThickness,
|
||||||
|
height * 2,
|
||||||
|
{ isStatic: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ceiling — only collides with bodies that have been grabbed
|
||||||
|
const ceiling = Matter.Bodies.rectangle(
|
||||||
|
width / 2,
|
||||||
|
-wallThickness / 2,
|
||||||
|
width,
|
||||||
|
wallThickness,
|
||||||
|
{
|
||||||
|
isStatic: true,
|
||||||
|
collisionFilter: {
|
||||||
|
category: CATEGORY_CEILING,
|
||||||
|
mask: CATEGORY_CEILING,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Matter.World.add(engine.world, [ground, leftWall, rightWall, ceiling]);
|
||||||
|
|
||||||
|
const isMobile = window.innerWidth < 768;
|
||||||
|
|
||||||
|
// Mouse Interaction (Desktop Only)
|
||||||
|
if (!isMobile) {
|
||||||
|
const mouse = Matter.Mouse.create(container);
|
||||||
|
const mouseConstraint = Matter.MouseConstraint.create(engine, {
|
||||||
|
mouse: mouse,
|
||||||
|
constraint: { stiffness: 0.15, render: { visible: false } },
|
||||||
|
});
|
||||||
|
Matter.World.add(engine.world, mouseConstraint);
|
||||||
|
mouse.element.removeEventListener("mousewheel", mouse.mousewheel);
|
||||||
|
|
||||||
|
// On grab: mark body as grabbed + enable ceiling collision
|
||||||
|
Matter.Events.on(mouseConstraint, "startdrag", (event) => {
|
||||||
|
grabbedBodies.current.add(event.body.id);
|
||||||
|
|
||||||
|
Matter.Body.set(event.body, {
|
||||||
|
collisionFilter: {
|
||||||
|
category: CATEGORY_DEFAULT,
|
||||||
|
mask: CATEGORY_DEFAULT | CATEGORY_CEILING,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync Loop
|
||||||
|
const update = () => {
|
||||||
|
itemsMap.current.forEach(({ body, element, w, h }) => {
|
||||||
|
// Freeze rotation until the user grabs the body
|
||||||
|
if (!grabbedBodies.current.has(body.id)) {
|
||||||
|
Matter.Body.setAngle(body, 0);
|
||||||
|
Matter.Body.setAngularVelocity(body, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element) {
|
||||||
|
gsap.set(element, {
|
||||||
|
x: body.position.x - w / 2,
|
||||||
|
y: body.position.y - h / 2,
|
||||||
|
rotation: body.angle * (180 / Math.PI),
|
||||||
|
opacity: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Trigger Engine on Scroll
|
||||||
|
const st = ScrollTrigger.create({
|
||||||
|
trigger: container,
|
||||||
|
start: "top 85%",
|
||||||
|
onEnter: () => {
|
||||||
|
runnerRef.current = Matter.Runner.create();
|
||||||
|
Matter.Runner.run(runnerRef.current, engine);
|
||||||
|
gsap.ticker.add(update);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
st.kill();
|
||||||
|
gsap.ticker.remove(update);
|
||||||
|
if (runnerRef.current) Matter.Runner.stop(runnerRef.current);
|
||||||
|
Matter.World.clear(engine.world);
|
||||||
|
Matter.Engine.clear(engine);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleImageLoad = (index, event) => {
|
||||||
|
const img = event.target;
|
||||||
|
const isMobile = window.innerWidth < 768;
|
||||||
|
const scale = isMobile ? 0.6 : 1;
|
||||||
|
|
||||||
|
const w = img.naturalWidth * scale;
|
||||||
|
const h = img.naturalHeight * scale;
|
||||||
|
|
||||||
|
const container = containerRef.current;
|
||||||
|
const spawnX =
|
||||||
|
container.offsetWidth / 2 +
|
||||||
|
(Math.random() - 0.5) * (container.offsetWidth * 0.4);
|
||||||
|
const spawnY = -100 - index * 50;
|
||||||
|
|
||||||
|
const body = Matter.Bodies.rectangle(spawnX, spawnY, w, h, {
|
||||||
|
chamfer: { radius: h / 4 },
|
||||||
|
restitution: 0.4,
|
||||||
|
friction: 0.1,
|
||||||
|
angle: 0,
|
||||||
|
// Spawns ignoring the ceiling — falls in freely from above
|
||||||
|
collisionFilter: {
|
||||||
|
category: CATEGORY_DEFAULT,
|
||||||
|
mask: CATEGORY_DEFAULT,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Matter.World.add(engineRef.current.world, body);
|
||||||
|
|
||||||
|
itemsMap.current.set(index, {
|
||||||
|
body,
|
||||||
|
element: img.parentElement,
|
||||||
|
w,
|
||||||
|
h,
|
||||||
|
});
|
||||||
|
|
||||||
|
setLoadedImages((prev) => ({ ...prev, [index]: true }));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
className="relative w-full h-[450px] lg:h-full bg-[#080808] overflow-hidden touch-none"
|
||||||
|
>
|
||||||
|
{IMAGE_SOURCES.map((src, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="absolute top-0 left-0 opacity-0 will-change-transform"
|
||||||
|
style={{ visibility: loadedImages[i] ? "visible" : "hidden" }}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={src}
|
||||||
|
alt=""
|
||||||
|
loading="lazy"
|
||||||
|
onLoad={(e) => handleImageLoad(i, e)}
|
||||||
|
className="block cursor-grab active:cursor-grabbing"
|
||||||
|
style={{ width: "auto", height: "auto" }}
|
||||||
|
draggable={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
98
apps/website/components/problem.jsx
Executable file
@@ -0,0 +1,98 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import dynamic from "next/dynamic";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { ProblemBgSvg } from "../app/constant";
|
||||||
|
|
||||||
|
const ProblemAnimation = dynamic(() => import("./problem-animation"), {
|
||||||
|
ssr: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function Problem() {
|
||||||
|
return (
|
||||||
|
<section className="bg-[#000000]">
|
||||||
|
<div
|
||||||
|
className="w-full py-5 border-l border-r border-[#292929]"
|
||||||
|
style={{ backgroundColor: "rgba(229, 46, 185, 0.12)" }}
|
||||||
|
>
|
||||||
|
<div className="flex items-start md:items-center gap-2 pl-4 xl:pl-[90px]">
|
||||||
|
<Image
|
||||||
|
src="/images/problems/warning.svg"
|
||||||
|
width={18}
|
||||||
|
height={16}
|
||||||
|
alt="warning"
|
||||||
|
className="shrink-0 mt-1 md:mt-0"
|
||||||
|
style={{ width: "auto", height: "auto" }}
|
||||||
|
/>
|
||||||
|
<p className="text-[#D942B5] font-light tracking-[-2%] text-[14px] md:text-[16px] lg:text-[16px] leading-[18px] md:leading-[20px]">
|
||||||
|
<span className="font-light mr-1">The hidden complexity:</span>
|
||||||
|
Payment processors move money. They don't handle the state
|
||||||
|
management that happens between payments.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="grid lg:grid-cols-2 gap-0 lg:h-[800px]">
|
||||||
|
{/* LEFT COLUMN */}
|
||||||
|
<div className="bg-[#0D0D0D] flex flex-col border-r border-[#292929] border-l border-l-[#292929] pb-[20px] md:pb-0">
|
||||||
|
<div className="flex flex-col mb-2 gap-3 pl-[28px] xl:pl-[90px] pr-6 lg:pr-8 pt-14 sm:pt-16 lg:pt-16 items-center lg:items-start">
|
||||||
|
<h2 className="font-normal tracking-[-4%] leading-[32px] lg:leading-[40px] mb-2 lg:mb-4 text-center lg:text-left">
|
||||||
|
<span className="block text-white text-[30px] md:text-[36px] lg:text-[40px]">
|
||||||
|
AI made billing
|
||||||
|
</span>
|
||||||
|
<span className="block text-[#686868] text-[30px] md:text-[36px] lg:text-[40px]">
|
||||||
|
way harder
|
||||||
|
</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p className="text-[#888888] font-light text-[16px] md:text-[18px] lg:text-[16px] tracking-[-2%] leading-[20px] mb-8 lg:mb-10 max-w-sm md:max-w-lg lg:max-w-sm text-center lg:text-left">
|
||||||
|
You're not charging for access anymore. You're metering
|
||||||
|
tokens, tracking credits, resetting quotas —{" "}
|
||||||
|
<span className="text-white">
|
||||||
|
all before you process a single payment.
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-auto">
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-[max-content_max-content_max-content_auto] border-t border-b border-[#1E1E1E]">
|
||||||
|
{[
|
||||||
|
{ value: "3–6", label: "Uptime SLA target" },
|
||||||
|
{ value: "40+ lines", label: "to gate one feature" },
|
||||||
|
{ value: "Infinite cases", label: "To handle billing" },
|
||||||
|
].map((stat, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className={`py-6 pr-9 border-[#292929] border-r
|
||||||
|
${i === 2 ? "col-span-2 md:col-span-1 border-t md:border-t-0 border-r-0 md:border-r" : ""}
|
||||||
|
${/* Mobile: Infinite cases (i=2) now matches the 28px padding of the first item (i=0) */ ""}
|
||||||
|
${i === 0 || i === 2 ? "pl-[28px]" : "pl-4"}
|
||||||
|
md:pl-6 ${i === 0 ? "xl:pl-[90px]" : ""}`}
|
||||||
|
>
|
||||||
|
<p className="text-white tracking-[-5%] font-normal text-[18px] lg:text-[24px] leading-none">
|
||||||
|
{stat.value}
|
||||||
|
</p>
|
||||||
|
{/* whitespace-nowrap ensures it stays on one line regardless of container width */}
|
||||||
|
<p className="text-[#767676] font-light tracking-[-5%] text-[16px] lg:text-[18px] mt-1.5 leading-[20px] whitespace-nowrap">
|
||||||
|
{stat.label}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<div className="hidden md:flex flex-1 items-stretch">
|
||||||
|
{[...Array(4)].map((_, i) => (
|
||||||
|
<div key={i} className="flex-1 border-r border-[#292929]" />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ProblemBgSvg />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* RIGHT COLUMN — problem animation */}
|
||||||
|
<div className="relative overflow-hidden ">
|
||||||
|
<ProblemAnimation />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
227
apps/website/components/production-scale.jsx
Executable file
@@ -0,0 +1,227 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useGSAP } from "@gsap/react";
|
||||||
|
import gsap from "gsap";
|
||||||
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
|
||||||
|
gsap.registerPlugin(ScrollTrigger);
|
||||||
|
|
||||||
|
const SCRAMBLE_CHARS =
|
||||||
|
"!@#$%^&*()_+-=[]{}|;:,.<>?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
|
|
||||||
|
function scrambleText(
|
||||||
|
el,
|
||||||
|
finalText,
|
||||||
|
{ charDuration = 60, cycleSpeed = 30 } = {},
|
||||||
|
) {
|
||||||
|
const len = finalText.length;
|
||||||
|
let settled = 0;
|
||||||
|
const timeouts = [];
|
||||||
|
|
||||||
|
const cycleInterval = setInterval(() => {
|
||||||
|
const display = finalText
|
||||||
|
.split("")
|
||||||
|
.map((ch, i) =>
|
||||||
|
i < settled
|
||||||
|
? ch
|
||||||
|
: SCRAMBLE_CHARS[Math.floor(Math.random() * SCRAMBLE_CHARS.length)],
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
|
el.textContent = display;
|
||||||
|
}, cycleSpeed);
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
const t = setTimeout(
|
||||||
|
() => {
|
||||||
|
settled = i + 1;
|
||||||
|
if (settled === len) {
|
||||||
|
clearInterval(cycleInterval);
|
||||||
|
el.textContent = finalText;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(i + 1) * charDuration,
|
||||||
|
);
|
||||||
|
timeouts.push(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return function cleanup() {
|
||||||
|
clearInterval(cycleInterval);
|
||||||
|
timeouts.forEach(clearTimeout);
|
||||||
|
el.textContent = finalText;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const cards = [
|
||||||
|
{
|
||||||
|
bg: "#FFE8FA",
|
||||||
|
icon: "/images/production/latency.svg",
|
||||||
|
metric: "<100ms",
|
||||||
|
label: "US latency",
|
||||||
|
description:
|
||||||
|
"Every billing check resolves in under 100ms. Your users never wait for a gate.",
|
||||||
|
clipart: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bg: "#D698FF",
|
||||||
|
icon: "/images/production/uptiime.svg",
|
||||||
|
metric: "99.99%",
|
||||||
|
label: "Uptime SLA",
|
||||||
|
description:
|
||||||
|
"Designed for teams that can't afford billing downtime. Four nines, guaranteed.",
|
||||||
|
clipart: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bg: "#A175FF",
|
||||||
|
icon: "/images/production/uptime2.svg",
|
||||||
|
metric: "10,000+",
|
||||||
|
label: "Uptime SLA",
|
||||||
|
description:
|
||||||
|
"Autumn handles billions of billing events monthly. Open source core, self-host ready.",
|
||||||
|
clipart: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bg: "#F55DD0",
|
||||||
|
icon: "/images/production/churn.svg",
|
||||||
|
metric: "Zero",
|
||||||
|
label: "Churn rate",
|
||||||
|
description: "Per customer. When billing works, customers stay.",
|
||||||
|
clipart: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function ProductionScale() {
|
||||||
|
const containerRef = useRef(null);
|
||||||
|
const scrambleCleanups = useRef([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const cleanups = scrambleCleanups.current;
|
||||||
|
return () => {
|
||||||
|
cleanups.forEach((fn) => fn());
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useGSAP(
|
||||||
|
() => {
|
||||||
|
const isMobile = window.innerWidth < 768;
|
||||||
|
const cardY = isMobile ? 16 : 30;
|
||||||
|
|
||||||
|
gsap.set(".ps-card", { opacity: 0, y: cardY, scale: 0.97 });
|
||||||
|
|
||||||
|
const tl = gsap.timeline({
|
||||||
|
scrollTrigger: {
|
||||||
|
trigger: ".ps-section",
|
||||||
|
start: "top 75%",
|
||||||
|
},
|
||||||
|
defaults: { overwrite: "auto" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const cardEls = gsap.utils.toArray(".ps-card");
|
||||||
|
cardEls.forEach((card, i) => {
|
||||||
|
tl.to(
|
||||||
|
card,
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
scale: 1,
|
||||||
|
duration: 0.9,
|
||||||
|
ease: "power3.out",
|
||||||
|
onComplete() {
|
||||||
|
const metricEl = card.querySelector(".ps-metric");
|
||||||
|
|
||||||
|
if (!metricEl) return;
|
||||||
|
const finalText = metricEl.dataset.final;
|
||||||
|
const delayTimer = setTimeout(() => {
|
||||||
|
const cleanup = scrambleText(metricEl, finalText);
|
||||||
|
scrambleCleanups.current.push(cleanup);
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
scrambleCleanups.current.push(() => clearTimeout(delayTimer));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
0.3 + i * 0.15,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ scope: containerRef },
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={containerRef} className="overflow-hidden">
|
||||||
|
<section className="ps-section flex flex-col lg:flex-row items-start justify-between py-12 lg:py-16 gap-12 lg:gap-0 bg-[#0F0F0F]">
|
||||||
|
<div className="flex px-6 xl:pl-22.5 lg:pr-0 flex-col my-auto gap-4 lg:gap-6 pt-2 w-full lg:w-auto">
|
||||||
|
<div className="leading-none lg:leading-10">
|
||||||
|
<p className="text-[#FFFFFF99] tracking-[-4%] text-[30px] lg:text-[40px] font-normal">
|
||||||
|
Built for
|
||||||
|
</p>
|
||||||
|
<h2 className="text-white tracking-[-4%] text-[30px] lg:text-[40px] font-normal mt-1 lg:mt-0">
|
||||||
|
production scale
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<p className="text-[#FFFFFF99] font-light text-[16px] lg:text-sm lg:w-sm leading-[20px] lg:leading-5">
|
||||||
|
Autumn handles billions of billing events monthly. Open source core,
|
||||||
|
self-host ready,{" "}
|
||||||
|
<span className="text-white">
|
||||||
|
designed for teams that <br className="hidden lg:block" /> can't afford billing downtime.
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-end gap-3 lg:gap-4 w-full pl-6 lg:pl-0 lg:w-[50%] [--card-step:24px] lg:[--card-step:52px]">
|
||||||
|
{cards.map((card, i) => (
|
||||||
|
<div
|
||||||
|
key={card.metric}
|
||||||
|
className="ps-card relative flex items-center justify-between pl-4 pr-3 py-4 lg:pl-6 lg:pr-10 lg:py-3.5 gap-2 lg:gap-6"
|
||||||
|
style={{
|
||||||
|
width: `calc(100% - (var(--card-step) * ${i}))`,
|
||||||
|
backgroundColor: card.bg,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col gap-1 min-w-[95px] lg:min-w-auto shrink-0">
|
||||||
|
<div className="flex items-center gap-1.5 lg:gap-2">
|
||||||
|
<Image
|
||||||
|
src={card.icon}
|
||||||
|
width={18}
|
||||||
|
height={18}
|
||||||
|
alt={card.label}
|
||||||
|
className="w-[14px] h-[14px] lg:w-[18px] lg:h-[18px]"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="ps-metric text-xl lg:text-2xl font-medium tracking-[-5%] text-[#1A0A2E]"
|
||||||
|
data-final={card.metric}
|
||||||
|
>
|
||||||
|
{card.metric}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-[11px] lg:text-[14px] leading-[1] lg:leading-4.5 tracking-[-2%] font-normal text-[#1A0A2E]/60">
|
||||||
|
{card.label}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-[10.5px] lg:text-[14px] text-[#1A0A2E]/80 font-normal leading-[1.3] lg:leading-4.5 tracking-[0] lg:tracking-[-2%] flex-1 lg:flex-none lg:w-66 lg:shrink-0 text-left">
|
||||||
|
{card.description}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{card.badge && (
|
||||||
|
<span className="absolute top-0 right-0 bg-[#1A0A2E] text-white font-mono text-xs px-2.5 py-1">
|
||||||
|
{card.badge}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{card.clipart && (
|
||||||
|
<Image
|
||||||
|
src="/images/production/clipart.svg"
|
||||||
|
width={12}
|
||||||
|
height={12}
|
||||||
|
alt="clipart"
|
||||||
|
className="absolute bottom-0 right-0 max-lg:w-[8px] max-lg:h-[8px]"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
19
apps/website/components/section-divider.jsx
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
export default function SectionDivider({ title }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex flex-col gap-2.5">
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
<div className="border-t border-[#292929] w-full" />
|
||||||
|
</div>
|
||||||
|
<div className="w-[calc(100%+calc(var(--page-pad)*2))] -ml-(--page-pad) flex border-y border-[#292929] bg-[#000000] mt-2.5">
|
||||||
|
<div className="flex-1 py-6.5 pl-[calc(var(--page-pad)+16px)] xl:pl-[calc(var(--page-pad)+90px)] flex items-center">
|
||||||
|
<span className="font-mono text-[#FFFFFF99] text-[14px] tracking-[-2%] leading-[14px] uppercase">
|
||||||
|
// {title}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
54
apps/website/components/solution-animation.jsx
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
import lottie, { AnimationItem } from "lottie-web";
|
||||||
|
import gsap from "gsap";
|
||||||
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||||
|
import desktopAnimationData from "@/public/animation/solution-desktop.json";
|
||||||
|
import mobileAnimationData from "@/public/animation/solution-mobile.json";
|
||||||
|
|
||||||
|
gsap.registerPlugin(ScrollTrigger);
|
||||||
|
|
||||||
|
export default function SolutionAnimation() {
|
||||||
|
const containerRef = useRef(null);
|
||||||
|
const animRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!containerRef.current) return;
|
||||||
|
|
||||||
|
const isMobile = window.innerWidth < 768;
|
||||||
|
const animationData = isMobile ? mobileAnimationData : desktopAnimationData;
|
||||||
|
|
||||||
|
const anim = lottie.loadAnimation({
|
||||||
|
container: containerRef.current,
|
||||||
|
renderer: "svg",
|
||||||
|
loop: false,
|
||||||
|
autoplay: false,
|
||||||
|
animationData,
|
||||||
|
});
|
||||||
|
|
||||||
|
animRef.current = anim;
|
||||||
|
|
||||||
|
const totalFrames = anim.totalFrames;
|
||||||
|
|
||||||
|
const loopStart = Math.floor(totalFrames * 0.2);
|
||||||
|
|
||||||
|
anim.addEventListener("complete", () => {
|
||||||
|
anim.loop = true;
|
||||||
|
anim.playSegments([loopStart, totalFrames], true);
|
||||||
|
});
|
||||||
|
|
||||||
|
const st = ScrollTrigger.create({
|
||||||
|
trigger: containerRef.current,
|
||||||
|
start: "top 75%", // Plays when the top of the animation reaches 75% viewport height
|
||||||
|
onEnter: () => anim.play(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
st.kill();
|
||||||
|
anim.destroy();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <div ref={containerRef} style={{ width: "100%" }} />;
|
||||||
|
}
|
||||||
68
apps/website/components/solution.jsx
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
import React from "react";
|
||||||
|
import SolutionAnimation from "./solution-animation";
|
||||||
|
|
||||||
|
const dbItems = [
|
||||||
|
{ text: "SUBSCRIPTION STATE", active: true },
|
||||||
|
{ text: "CREDIT BALANCES & ROLLOVERS", active: false },
|
||||||
|
{ text: "FEATURE ENTITLEMENTS", active: false },
|
||||||
|
{ text: "WEBHOOK HANDLING", active: false },
|
||||||
|
{ text: "USAGE RESETS & PRORATION", active: false },
|
||||||
|
];
|
||||||
|
|
||||||
|
const appItems = [
|
||||||
|
{ text: "PRODUCT FEATURES", icon: "grid" },
|
||||||
|
{ text: "USER INTERFACE", icon: "crossfade" },
|
||||||
|
{ text: "BUSINESS LOGIC", icon: "box-grid" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const stripeItems = [
|
||||||
|
{ text: "MOVES MONEY", icon: "grid" },
|
||||||
|
{ text: "INVOICING", icon: "crossfade" },
|
||||||
|
{ text: "CARD PROCESSING", icon: "box-grid" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const iconSrc = {
|
||||||
|
grid: "/images/solutions/grid.svg",
|
||||||
|
crossfade: "/images/solutions/crossfade.svg",
|
||||||
|
"box-grid": "/images/solutions/box-grid.svg",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Solution() {
|
||||||
|
return (
|
||||||
|
<section className="relative w-full bg-[#000000] border-t border-[#292929] overflow-hidden pt-24">
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 z-0 pointer-events-none"
|
||||||
|
style={{
|
||||||
|
backgroundImage:
|
||||||
|
"linear-gradient(to right, rgba(128,128,128,0.07) 1px, transparent 1px), linear-gradient(to bottom, rgba(128,128,128,0.07) 1px, transparent 1px)",
|
||||||
|
backgroundSize: "40px 40px",
|
||||||
|
maskImage:
|
||||||
|
"linear-gradient(to bottom, transparent 0%, black 18%, black 78%, transparent 100%)",
|
||||||
|
WebkitMaskImage:
|
||||||
|
"linear-gradient(to bottom, transparent 0%, black 18%, black 78%, transparent 100%)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="relative z-10 max-w-[1400px] mx-auto px-4 flex flex-col items-center">
|
||||||
|
{/* Heading */}
|
||||||
|
<div className="text-center mb-16 lg:mb-4 flex flex-col items-center">
|
||||||
|
<h2 className="text-[30px] leading-[30px] md:text-[40px] md:leading-[40px] font-normal tracking-tight mb-6">
|
||||||
|
<span className="text-[#A3A3A3]">Replace it all with </span>
|
||||||
|
<span className="text-white">Autumn</span>
|
||||||
|
</h2>
|
||||||
|
<p className="text-[#A3A3A3] text-[14px] md:text-[16px] sm:text-base max-w-2xl mx-auto font-light leading-[20px] tracking-[-2%]">
|
||||||
|
Autumn is a database purpose-built for billing state. Configure your
|
||||||
|
pricing
|
||||||
|
<br className="hidden sm:block" />
|
||||||
|
in the dashboard.{" "}
|
||||||
|
<span className="text-white">
|
||||||
|
Three API calls handle everything else.
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<SolutionAnimation />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
206
apps/website/components/testimonials.jsx
Executable file
@@ -0,0 +1,206 @@
|
|||||||
|
"use client";
|
||||||
|
import {
|
||||||
|
IconArrowLeft,
|
||||||
|
IconArrowRight,
|
||||||
|
IconQuotes,
|
||||||
|
PixelatedPattern,
|
||||||
|
} from "@/app/constant";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
const testimonialsData = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
quote:
|
||||||
|
"Literally cannot imagine going without it. Thank you. We had some pretty crazy usage-based limitations for different features, as well as a free trial.",
|
||||||
|
author: "DANIEL EDRISIAR",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
quote: "Amazing product. Amazing founders.",
|
||||||
|
author: "NIZZY",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
quote:
|
||||||
|
"Autumn is awesome. We've been happy customers since the very beginning - it was a no-brainer to be honest. The founders are in true founder mode.",
|
||||||
|
author: "MAX PRILUTSKIY",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
quote: "What migrating to Autumn does (scroll!)",
|
||||||
|
author: "Ben Y",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
quote:
|
||||||
|
"Autumn fixed stripe. Trust me. Save you at least a week and potentially months of Stripe integration time. I wish we could have discovered Autumn earlier.",
|
||||||
|
author: "Benny Kok",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
quote:
|
||||||
|
"@autumnpricing is so good it ruined every other tool for me. nothing else even feels right anymore",
|
||||||
|
author: "Can Vardar",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const Testimonials = () => {
|
||||||
|
const scrollRef = useRef(null);
|
||||||
|
const progressRef = useRef(null);
|
||||||
|
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
||||||
|
const [canScrollRight, setCanScrollRight] = useState(true);
|
||||||
|
|
||||||
|
const handleScroll = () => {
|
||||||
|
if (scrollRef.current) {
|
||||||
|
const { scrollLeft, scrollWidth, clientWidth } = scrollRef.current;
|
||||||
|
setCanScrollLeft(scrollLeft > 0);
|
||||||
|
setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1);
|
||||||
|
|
||||||
|
if (progressRef.current) {
|
||||||
|
const maxScroll = scrollWidth - clientWidth;
|
||||||
|
const progress = maxScroll > 0 ? (scrollLeft / maxScroll) * 100 : 0;
|
||||||
|
progressRef.current.style.transform = `translateX(${progress}%)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleScroll();
|
||||||
|
window.addEventListener("resize", handleScroll);
|
||||||
|
return () => window.removeEventListener("resize", handleScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const scrollByAmount = (amount) => {
|
||||||
|
if (scrollRef.current) {
|
||||||
|
scrollRef.current.scrollBy({ left: amount, behavior: "smooth" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="w-full bg-[#000000] text-white overflow-hidden">
|
||||||
|
<div className=" mx-auto">
|
||||||
|
<div className="px-4 sm:px-6 md:px-4 xl:px-22.75 pt-[48px] xl:pt-32 pb-[48px] flex flex-row items-start justify-between">
|
||||||
|
<h2 className="w-full text-center md:w-auto md:text-left text-[30px] leading-[32px] sm:text-5xl md:text-[40px] font-normal tracking-[-5%]">
|
||||||
|
<span className="text-[#FFFFFF99]">Built by </span>
|
||||||
|
<span className="text-white">teams</span>
|
||||||
|
<br className="sm:hidden" />
|
||||||
|
<span className="text-white"> who ship</span>
|
||||||
|
</h2>
|
||||||
|
<div className="hidden md:flex items-center space-x-4">
|
||||||
|
<button
|
||||||
|
onClick={() => scrollByAmount(-400)}
|
||||||
|
disabled={!canScrollLeft}
|
||||||
|
className="group p-1.5 bg-transparent cursor-pointer flex items-center justify-center transition-all duration-300 border border-[#292929]"
|
||||||
|
aria-label="Previous testimonials"
|
||||||
|
>
|
||||||
|
<IconArrowLeft
|
||||||
|
disabled={!canScrollLeft}
|
||||||
|
className="w-6 h-6 text-gray-400 hover:text-white"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => scrollByAmount(400)}
|
||||||
|
disabled={!canScrollRight}
|
||||||
|
className="group p-1.5 bg-transparent cursor-pointer flex items-center justify-center transition-all duration-300 border border-[#292929]"
|
||||||
|
aria-label="Next testimonials"
|
||||||
|
>
|
||||||
|
<IconArrowRight
|
||||||
|
disabled={!canScrollRight}
|
||||||
|
className="w-6 h-6 text-gray-400 hover:text-white"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-t border-[#1A1A1A] w-full"></div>
|
||||||
|
|
||||||
|
<div className="px-0 xl:pl-22.75">
|
||||||
|
<div
|
||||||
|
ref={scrollRef}
|
||||||
|
onScroll={handleScroll}
|
||||||
|
className="flex overflow-x-auto snap-x snap-mandatory hide-scrollbar group/track"
|
||||||
|
style={{ scrollbarWidth: "none", msOverflowStyle: "none" }}
|
||||||
|
>
|
||||||
|
{testimonialsData.map((testimonial) => (
|
||||||
|
<div
|
||||||
|
key={testimonial.id}
|
||||||
|
className="group shrink-0 w-[300px] sm:w-[300px] md:w-[360px] snap-start min-h-[360px] flex flex-col justify-between p-4 sm:p-10 border-l border-r border-b border-[#1A1A1A] transition-all duration-300 relative overflow-hidden"
|
||||||
|
>
|
||||||
|
{/* Hover Pixelated Pattern (Masked) */}
|
||||||
|
<div className="absolute inset-x-0 bottom-0 h-[120%] pointer-events-none z-0 overflow-hidden">
|
||||||
|
<PixelatedPattern className="w-full h-full object-cover object-bottom opacity-0 translate-y-6 group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-500 ease-out" />
|
||||||
|
</div>
|
||||||
|
{/* Purple Glow Gradient Overlay */}
|
||||||
|
<div className="absolute inset-x-0 bottom-0 h-[70%] bg-[linear-gradient(to_bottom,rgba(10,10,10,0)_0%,rgba(135,82,250,0.15)_40%,rgba(135,82,250,0.45)_70%,rgba(135,82,250,0.85)_90%)] opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none z-0" />
|
||||||
|
<div className="relative z-10 flex flex-col h-full justify-start">
|
||||||
|
<IconQuotes className="w-8 h-8 text-[#4C4C4C] opacity-60 group-hover:text-[#9564FF] group-hover:opacity-100 transition-colors duration-500 mb-6" />
|
||||||
|
<p className="text-white text-[14px] leading-[18px] sm:text-xl sm:leading-6 font-extralight tracking-[-2%] transition-colors duration-500">
|
||||||
|
{testimonial.quote}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="relative z-10 font-mono text-sm tracking-[-2%] uppercase text-white opacity-60 group-hover:opacity-100 transition-colors duration-500 mt-33.5">
|
||||||
|
{testimonial.author}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="border-t border-[#1A1A1A] w-full"></div>
|
||||||
|
|
||||||
|
<div className="flex md:hidden justify-end px-4 mt-6">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<button
|
||||||
|
onClick={() => scrollByAmount(-400)}
|
||||||
|
disabled={!canScrollLeft}
|
||||||
|
className="p-1.5 bg-transparent flex items-center justify-center border border-[#292929]"
|
||||||
|
aria-label="Previous testimonials"
|
||||||
|
>
|
||||||
|
<IconArrowLeft
|
||||||
|
disabled={!canScrollLeft}
|
||||||
|
className="w-6 h-6 text-white"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => scrollByAmount(400)}
|
||||||
|
disabled={!canScrollRight}
|
||||||
|
className="p-1.5 bg-transparent flex items-center justify-center border border-[#292929]"
|
||||||
|
aria-label="Next testimonials"
|
||||||
|
>
|
||||||
|
<IconArrowRight
|
||||||
|
disabled={!canScrollRight}
|
||||||
|
className="w-6 h-6 text-white"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-center mt-5 md:mt-10 pb-0 md:pb-10">
|
||||||
|
<div className="w-[168px] hidden md:block h-1 bg-[#1A1A1A] rounded-full overflow-hidden relative">
|
||||||
|
<div
|
||||||
|
ref={progressRef}
|
||||||
|
className="absolute left-0 top-0 h-full bg-[#8752FA] w-[84px] rounded-full"
|
||||||
|
style={{ transform: `translateX(0%)` }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style jsx global>{`
|
||||||
|
.hide-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.arrow-corners {
|
||||||
|
transform-box: fill-box;
|
||||||
|
transform-origin: center;
|
||||||
|
transition: transform 0.25s ease;
|
||||||
|
}
|
||||||
|
.group:hover .arrow-corners {
|
||||||
|
transform: scale(1.4);
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Testimonials;
|
||||||
16
apps/website/eslint.config.mjs
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
import { defineConfig, globalIgnores } from "eslint/config";
|
||||||
|
import nextVitals from "eslint-config-next/core-web-vitals";
|
||||||
|
|
||||||
|
const eslintConfig = defineConfig([
|
||||||
|
...nextVitals,
|
||||||
|
// Override default ignores of eslint-config-next.
|
||||||
|
globalIgnores([
|
||||||
|
// Default ignores of eslint-config-next:
|
||||||
|
".next/**",
|
||||||
|
"out/**",
|
||||||
|
"build/**",
|
||||||
|
"next-env.d.ts",
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
export default eslintConfig;
|
||||||
7
apps/website/jsconfig.json
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
apps/website/next.config.mjs
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
const nextConfig = {
|
||||||
|
/* config options here */
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
6958
apps/website/package-lock.json
generated
Executable file
28
apps/website/package.json
Executable file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "pixelup-dev",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "npx next dev -p 3005",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "eslint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@gsap/react": "^2.1.2",
|
||||||
|
"gsap": "^3.14.2",
|
||||||
|
"lottie-react": "^2.4.1",
|
||||||
|
"matter-js": "^0.20.0",
|
||||||
|
"motion": "^12.38.0",
|
||||||
|
"next": "16.2.1",
|
||||||
|
"react": "19.2.4",
|
||||||
|
"react-dom": "19.2.4",
|
||||||
|
"react-syntax-highlighter": "^16.1.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/postcss": "^4.2.2",
|
||||||
|
"eslint": "^9",
|
||||||
|
"eslint-config-next": "16.2.1",
|
||||||
|
"tailwindcss": "^4.2.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
7
apps/website/postcss.config.mjs
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
const config = {
|
||||||
|
plugins: {
|
||||||
|
"@tailwindcss/postcss": {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
1
apps/website/public/animation/problem_desktop.json
Executable file
1
apps/website/public/animation/problem_mobile.json
Executable file
1
apps/website/public/animation/solution-desktop.json
Executable file
1
apps/website/public/animation/solution-mobile.json
Executable file
15
apps/website/public/images/404.svg
Executable file
|
After Width: | Height: | Size: 4.4 MiB |
3
apps/website/public/images/autumn-notfound.svg
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M48 48H0V0H48V48ZM18.3667 15.5466C16.761 19.2189 15.1552 22.8912 13.5495 26.5634C14.8079 28.1941 16.0664 29.8258 17.3248 31.4564C21.056 26.6349 24.7883 21.8133 28.5206 16.9917L15.8928 39.3452C22.142 35.5746 28.3912 31.8049 34.6404 28.0343V8.31487L18.3667 15.5466Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 435 B |
31
apps/website/public/images/docs.svg
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="24" height="24" fill="white"/>
|
||||||
|
<g clip-path="url(#clip0_4003_1213)">
|
||||||
|
<path d="M15.7758 16.5301H17.2863V7.46715H15.7758V16.5301Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M6.71289 16.5301H8.22338V7.46715H6.71289V16.5301Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M6.71289 7.46715H8.22338V8.97764H6.71289V7.46715Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M8.22338 5.95667H9.73387V7.46715H8.22338V5.95667Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M8.22338 18.0406H9.73387V16.5301H8.22338V18.0406Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M9.73387 5.95667H11.2444V7.46715H9.73387V5.95667Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M9.73387 18.0406H11.2444V16.5301H9.73387V18.0406Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M11.2444 5.95667H12.7548V7.46715H11.2444V5.95667Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M12.7548 5.95667H15.7758V7.46715H12.7548V5.95667Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M11.2444 18.0406H12.7548V16.5301H11.2444V18.0406Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M9.73387 8.97764H11.2444V10.4881H9.73387V8.97764Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M9.73387 11.9986H11.2444V13.5091H9.73387V11.9986Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M11.2444 8.97764H12.7548V10.4881H11.2444V8.97764Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M11.2444 11.9986H12.7548V13.5091H11.2444V11.9986Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M12.7548 8.97764H14.2653V10.4881H12.7548V8.97764Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M12.7548 11.9986H14.2653V13.5091H12.7548V11.9986Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M12.7548 18.0406H15.7758V16.5301H12.7548V18.0406Z" fill="#0A0A0A"/>
|
||||||
|
<rect x="3.69141" y="3.69226" width="1.51049" height="1.51049" fill="#0A0A0A"/>
|
||||||
|
<rect x="3.69141" y="18.7969" width="1.51049" height="1.51049" fill="#0A0A0A"/>
|
||||||
|
<rect x="18.793" y="3.69226" width="1.51049" height="1.51049" fill="#0A0A0A"/>
|
||||||
|
<rect x="18.793" y="18.7969" width="1.51049" height="1.51049" fill="#0A0A0A"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_4003_1213">
|
||||||
|
<rect width="16.6154" height="16.6154" fill="white" transform="translate(3.69141 3.69226)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
11
apps/website/public/images/features/analytics.svg
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 0H4.8V4.8H0V0Z" fill="white"/>
|
||||||
|
<path d="M0 19.2H4.8V24H0V19.2Z" fill="white"/>
|
||||||
|
<path d="M0 14.4H4.8V19.2H0V14.4Z" fill="white"/>
|
||||||
|
<path d="M4.8 0H9.6V4.8H4.8V0Z" fill="white"/>
|
||||||
|
<path d="M14.4 19.2H19.2V24H14.4V19.2Z" fill="white"/>
|
||||||
|
<path d="M9.6 9.6H14.4V14.4H9.6V9.6Z" fill="white"/>
|
||||||
|
<path d="M19.2 4.8H24V9.6H19.2V4.8Z" fill="white"/>
|
||||||
|
<path d="M19.2 0H24V4.8H19.2V0Z" fill="white"/>
|
||||||
|
<path d="M19.2 19.2H24V24H19.2V19.2Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 552 B |
11
apps/website/public/images/features/billing.svg
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.6 0H14.4V4.8H9.6V0Z" fill="white"/>
|
||||||
|
<path d="M24 9.6V14.4H19.2V9.6H24Z" fill="white"/>
|
||||||
|
<path d="M9.6 19.2H14.4V24H9.6V19.2Z" fill="white"/>
|
||||||
|
<path d="M4.8 9.6V14.4H0L2.09827e-07 9.6H4.8Z" fill="white"/>
|
||||||
|
<path d="M4.8 4.8H19.2V19.2H4.8V4.8Z" fill="white"/>
|
||||||
|
<path d="M9.61986 4.82072H14.4011V9.62618H9.61986V4.82072Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M9.61986 14.4088H14.4011V19.2143H9.61986V14.4088Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M4.79872 9.59735H9.57997V14.4028H4.79872V9.59735Z" fill="#0A0A0A"/>
|
||||||
|
<path d="M14.4279 9.59719H19.2092V14.4027H14.4279V9.59719Z" fill="#0A0A0A"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 678 B |
11
apps/website/public/images/features/custom-plans.svg
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 0H4.8V4.8H0V0Z" fill="white"/>
|
||||||
|
<path d="M0 9.6H4.8V14.4H0V9.6Z" fill="white"/>
|
||||||
|
<path d="M0 19.2H4.8V24H0V19.2Z" fill="white"/>
|
||||||
|
<path d="M9.6 0H14.4V4.8H9.6V0Z" fill="white"/>
|
||||||
|
<path d="M9.6 9.6H14.4V14.4H9.6V9.6Z" fill="white"/>
|
||||||
|
<path d="M9.6 19.2H14.4V24H9.6V19.2Z" fill="white"/>
|
||||||
|
<path d="M19.2 0H24V4.8H19.2V0Z" fill="white"/>
|
||||||
|
<path d="M19.2 9.6H24V14.4H19.2V9.6Z" fill="white"/>
|
||||||
|
<path d="M19.2 19.2H24V24H19.2V19.2Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 550 B |
BIN
apps/website/public/images/features/pixel effect.webm
Executable file
14
apps/website/public/images/features/pricing.svg
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M24 0L24 4.7874L19.2 4.7874L19.2 -2.09815e-07L24 0Z" fill="white"/>
|
||||||
|
<path d="M-1.04632e-06 23.937L-8.37056e-07 19.1496L4.8 19.1496L4.8 23.937L-1.04632e-06 23.937Z" fill="white"/>
|
||||||
|
<path d="M19.2 4.7874L19.2 9.5748L14.4 9.5748L14.4 4.7874L19.2 4.7874Z" fill="white"/>
|
||||||
|
<path d="M4.8 19.1496L4.8 14.3622L9.6 14.3622L9.6 19.1496L4.8 19.1496Z" fill="white"/>
|
||||||
|
<path d="M24 9.5748L24 14.3622L19.2 14.3622L19.2 9.5748L24 9.5748Z" fill="white"/>
|
||||||
|
<path d="M-6.27792e-07 14.3622L-4.18528e-07 9.5748L4.8 9.5748L4.8 14.3622L-6.27792e-07 14.3622Z" fill="white"/>
|
||||||
|
<path d="M19.2 14.3622L19.2 19.1496L14.4 19.1496L14.4 14.3622L19.2 14.3622Z" fill="white"/>
|
||||||
|
<path d="M4.8 9.5748L4.8 4.7874L9.6 4.7874L9.6 9.5748L4.8 9.5748Z" fill="white"/>
|
||||||
|
<path d="M24 19.1496L24 23.937L19.2 23.937L19.2 19.1496L24 19.1496Z" fill="white"/>
|
||||||
|
<path d="M-2.09264e-07 4.7874L0 -1.04907e-06L4.8 -4.20741e-07L4.8 4.7874L-2.09264e-07 4.7874Z" fill="white"/>
|
||||||
|
<path d="M14.4 -4.19629e-07L14.4 4.7874L9.6 4.7874L9.6 -6.29444e-07L14.4 -4.19629e-07Z" fill="white"/>
|
||||||
|
<path d="M14.4 19.2126L14.4 24L9.6 24L9.6 19.2126L14.4 19.2126Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
10
apps/website/public/images/features/react-components.svg
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 24L-2.09815e-07 19.2L4.8 19.2L4.8 24L0 24Z" fill="white"/>
|
||||||
|
<path d="M-4.19629e-07 14.4L-1.04907e-06 1.90735e-06L4.8 1.69753e-06L4.8 14.4L-4.19629e-07 14.4Z" fill="white"/>
|
||||||
|
<path d="M4.8 19.2L4.8 14.4L9.6 14.4L9.6 19.2L4.8 19.2Z" fill="white"/>
|
||||||
|
<path d="M9.6 24L9.6 19.2L14.4 19.2L14.4 24L9.6 24Z" fill="white"/>
|
||||||
|
<path d="M9.6 14.4L9.6 1.48772e-06L14.4 1.2779e-06L14.4 14.4L9.6 14.4Z" fill="white"/>
|
||||||
|
<path d="M14.4 19.2L14.4 14.4L19.2 14.4L19.2 19.2L14.4 19.2Z" fill="white"/>
|
||||||
|
<path d="M19.2 24L19.2 19.2L24 19.2L24 24L19.2 24Z" fill="white"/>
|
||||||
|
<path d="M19.2 14.4L19.2 1.06809e-06L24 8.58275e-07L24 14.4L19.2 14.4Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 745 B |
17
apps/website/public/images/features/referral.svg
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 9.6H4.8V14.4H0V9.6Z" fill="white"/>
|
||||||
|
<path d="M19.2 9.6H24V14.4H19.2V9.6Z" fill="white"/>
|
||||||
|
<path d="M4.8 14.4H9.6V19.2H4.8V14.4Z" fill="white"/>
|
||||||
|
<path d="M0 0H4.8V4.8H0V0Z" fill="white"/>
|
||||||
|
<path d="M0 19.2H4.8V24H0V19.2Z" fill="white"/>
|
||||||
|
<path d="M9.6 9.6H14.4V14.4H9.6V9.6Z" fill="white"/>
|
||||||
|
<path d="M9.6 4.8H14.4V9.6H9.6V4.8Z" fill="white"/>
|
||||||
|
<path d="M14.4 14.4H19.2V19.2H14.4V14.4Z" fill="white"/>
|
||||||
|
<path d="M9.6 14.4H14.4V19.2H9.6V14.4Z" fill="white"/>
|
||||||
|
<path d="M9.6 19.2H14.4V24H9.6V19.2Z" fill="white"/>
|
||||||
|
<path d="M9.6 0H14.4V4.8H9.6V0Z" fill="white"/>
|
||||||
|
<path d="M19.2 0H24V4.8H19.2V0Z" fill="white"/>
|
||||||
|
<path d="M14.4 4.8H19.2V9.6H14.4V4.8Z" fill="white"/>
|
||||||
|
<path d="M4.8 4.8H9.6V9.6H4.8V4.8Z" fill="white"/>
|
||||||
|
<path d="M19.2 19.2H24V24H19.2V19.2Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 873 B |
15
apps/website/public/images/features/top-ups.svg
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.6 4.8H14.4V19.2H9.6V4.8Z" fill="white"/>
|
||||||
|
<path d="M0 4.8H4.8V9.6H0V4.8Z" fill="white"/>
|
||||||
|
<path d="M0 0H4.8V4.8H0V0Z" fill="white"/>
|
||||||
|
<path d="M4.8 0H9.6V4.8H4.8V0Z" fill="white"/>
|
||||||
|
<path d="M14.4 0H19.2V4.8H14.4V0Z" fill="white"/>
|
||||||
|
<path d="M19.2 0H24V4.8H19.2V0Z" fill="white"/>
|
||||||
|
<path d="M19.2 4.8H24V9.6H19.2V4.8Z" fill="white"/>
|
||||||
|
<path d="M19.2 19.2H24V24H19.2V19.2Z" fill="white"/>
|
||||||
|
<path d="M19.2 14.4H24V19.2H19.2V14.4Z" fill="white"/>
|
||||||
|
<path d="M14.4 19.2H19.2V24H14.4V19.2Z" fill="white"/>
|
||||||
|
<path d="M4.8 19.2H9.6V24H4.8V19.2Z" fill="white"/>
|
||||||
|
<path d="M0 19.2H4.8V24H0V19.2Z" fill="white"/>
|
||||||
|
<path d="M0 14.4H4.8V19.2H0V14.4Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 756 B |
13
apps/website/public/images/features/webhooks.svg
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 0H4.8V4.8H0V0Z" fill="white"/>
|
||||||
|
<path d="M24 24H19.2V19.2H24V24Z" fill="white"/>
|
||||||
|
<path d="M4.8 4.8H9.6V9.6H4.8V4.8Z" fill="white"/>
|
||||||
|
<path d="M9.6 9.6H14.4V14.4H9.6V9.6Z" fill="white"/>
|
||||||
|
<path d="M19.2 19.2H14.4V14.4H19.2V19.2Z" fill="white"/>
|
||||||
|
<path d="M9.6 0H14.4V4.8H9.6V0Z" fill="white"/>
|
||||||
|
<path d="M14.4 24H9.6V19.2H14.4V24Z" fill="white"/>
|
||||||
|
<path d="M14.4 4.8H19.2V9.6H14.4V4.8Z" fill="white"/>
|
||||||
|
<path d="M9.6 19.2H4.8L4.8 14.4H9.6V19.2Z" fill="white"/>
|
||||||
|
<path d="M19.2 0H24V4.8H19.2V0Z" fill="white"/>
|
||||||
|
<path d="M4.8 24H0L4.19619e-07 19.2H4.8V24Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 676 B |
19
apps/website/public/images/footer/footerbg.svg
Executable file
|
After Width: | Height: | Size: 416 KiB |
BIN
apps/website/public/images/footer/maskedimage.webp
Executable file
|
After Width: | Height: | Size: 641 KiB |
BIN
apps/website/public/images/footer/maskedmobile.webp
Executable file
|
After Width: | Height: | Size: 540 KiB |
BIN
apps/website/public/images/hero-bg.png
Executable file
|
After Width: | Height: | Size: 884 KiB |
9
apps/website/public/images/hero-bg.svg
Executable file
|
After Width: | Height: | Size: 22 MiB |
57
apps/website/public/images/hero/autumn_mobile.svg
Executable file
|
After Width: | Height: | Size: 226 KiB |
3
apps/website/public/images/hero/box.svg
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="74" height="14" viewBox="0 0 74 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0.324219 4.45108H72.7829M0.324219 8.57648H72.7829M0.324219 0.325684C0.324219 0.325684 44.486 0.325684 72.7829 0.325684V12.7019H0.324219V0.325684Z" stroke="#333333" stroke-width="0.651379"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 306 B |
3
apps/website/public/images/hero/cross.svg
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="11" height="11" viewBox="0 0 11 11" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0.359375 0.359375L10.5228 10.5228M10.5228 0.359375L0.359375 10.5228" stroke="#292929" stroke-width="1.01634"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 227 B |
9
apps/website/public/images/hero/cta_bg.svg
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
<svg width="200" height="18" viewBox="0 0 200 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 17.5H200M0 14.6667H200M0 11.8333H200M0 9H200M0 6.16667H200M0 3.33333H200M0 0.5H200" stroke="url(#paint0_linear_4873_221)" stroke-opacity="0.12"/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_4873_221" x1="100" y1="17.5" x2="100" y2="0.5" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white"/>
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 500 B |
BIN
apps/website/public/images/hero/hero_img.webp
Executable file
|
After Width: | Height: | Size: 587 KiB |
BIN
apps/website/public/images/hero/hero_mobile.webp
Executable file
|
After Width: | Height: | Size: 307 KiB |
44
apps/website/public/images/issues/Frame 2147242729.svg
Executable file
|
After Width: | Height: | Size: 49 KiB |
20
apps/website/public/images/issues/Frame 2147243001.svg
Executable file
|
After Width: | Height: | Size: 66 KiB |
38
apps/website/public/images/issues/Frame 2147243134.svg
Executable file
|
After Width: | Height: | Size: 652 KiB |
37
apps/website/public/images/issues/Frame 2147243146.svg
Executable file
|
After Width: | Height: | Size: 1.0 MiB |
19
apps/website/public/images/issues/Slack-1.svg
Executable file
|
After Width: | Height: | Size: 36 KiB |
25
apps/website/public/images/issues/Slack-2.svg
Executable file
|
After Width: | Height: | Size: 21 KiB |
19
apps/website/public/images/issues/Slack.svg
Executable file
|
After Width: | Height: | Size: 33 KiB |
20
apps/website/public/images/issues/Stripe.svg
Executable file
|
After Width: | Height: | Size: 28 KiB |
9
apps/website/public/images/navbar/autumnlogo.svg
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
<svg width="114" height="28" viewBox="0 0 114 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M28 28H0V0H28V28ZM10.7139 9.06887C9.77726 11.211 8.84052 13.3532 7.90386 15.4953C8.63795 16.4465 9.37205 17.3984 10.1061 18.3496C12.2827 15.537 14.4599 12.7244 16.637 9.91183L9.27077 22.9514C12.9161 20.7518 16.5615 18.5529 20.2069 16.3534V4.85034L10.7139 9.06887Z" fill="white"/>
|
||||||
|
<path d="M51.9683 16.7168C51.9683 17.7995 52.1779 18.6235 52.5979 19.1885C53.0179 19.7383 53.6245 20.0133 54.4161 20.0133C55.3045 20.0133 55.9995 19.6976 56.5001 19.068C57.0176 18.4376 57.2756 17.5407 57.2756 16.3774V10.1724H60.1841V22.1939H57.2756V20.9211C57.5812 20.5928 58.0631 19.6599 58.0656 19.6552L57.7898 19.4752C57.6379 19.779 57.4945 20.0344 57.2756 20.3763C56.9201 21.039 56.428 21.5557 55.7975 21.9273C55.1671 22.299 54.4077 22.4849 53.5193 22.4849C52.1618 22.4848 51.0791 22.025 50.2713 21.1036C49.4797 20.1668 49.0834 18.8007 49.0834 17.0078V10.1724H51.9683V16.7168Z" fill="white"/>
|
||||||
|
<path d="M72.6539 16.7168C72.6539 17.7995 72.8633 18.6235 73.2833 19.1885C73.7033 19.7384 74.31 20.0133 75.1017 20.0133C75.99 20.0133 76.685 19.6976 77.1856 19.068C77.7032 18.4376 77.961 17.5406 77.961 16.3774V10.1724H80.8697V22.1939H77.961V20.9211C78.2661 20.5933 78.7469 19.663 78.751 19.6552L78.4753 19.4752C78.3234 19.779 78.1799 20.0344 77.961 20.3763C77.6055 21.039 77.1135 21.5557 76.4831 21.9273C75.8527 22.299 75.0932 22.4848 74.2049 22.4849C72.8473 22.4849 71.7646 22.025 70.9569 21.1036C70.1653 20.1668 69.769 18.8007 69.769 17.0078V10.1724H72.6539V16.7168Z" fill="white"/>
|
||||||
|
<path d="M65.8577 10.1727H69.0082V12.6205H65.8577V18.2188C65.8577 18.6549 65.8985 18.9783 65.9791 19.1887C66.0758 19.3991 66.2379 19.5442 66.4635 19.6248C66.6901 19.6893 67.0211 19.7215 67.4572 19.7215H68.8868V22.194H66.5365C65.761 22.194 65.1068 22.1049 64.5731 21.9276C64.0394 21.7342 63.6355 21.3786 63.3614 20.8611C63.0865 20.3443 62.949 19.5925 62.949 18.6066V12.6205H60.889V10.1727H62.949V7.02223H65.8577V10.1727Z" fill="white"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M49.0481 22.1939H46.0224L44.6436 18.2629H38.0372L36.6584 22.1939H33.6566L39.7555 5.51515H42.9483L49.0481 22.1939ZM41.1784 9.30709L38.8313 15.999H43.8497L41.5026 9.30709V8.33556H41.1784V9.30709Z" fill="white"/>
|
||||||
|
<path d="M88.5704 9.88131C89.9458 9.88133 91.042 10.3412 91.8608 11.2626C92.0585 11.4942 92.2315 11.7513 92.38 12.0339C92.8144 11.3687 93.3898 10.8452 94.1059 10.4634C94.8491 10.0757 95.6569 9.88215 96.5299 9.88214C98.0648 9.88214 99.2519 10.3506 100.093 11.2873C100.933 12.2088 101.353 13.5663 101.353 15.36V22.1937H98.4688V15.6502C98.4688 14.5675 98.2584 13.7522 97.8384 13.2023C97.4184 12.6373 96.788 12.3539 95.948 12.3539C95.108 12.3539 94.3969 12.6694 93.8632 13.299C93.3304 13.9294 93.0639 14.8263 93.0639 15.9896V22.1937H90.1409V15.6493C90.1409 14.5667 89.9288 13.7427 89.5037 13.1776C89.0777 12.6278 88.4634 12.3529 87.6616 12.3529C86.7614 12.3529 86.0571 12.6686 85.5506 13.2982C85.0262 13.9286 84.7649 14.8255 84.7649 15.9888V22.1937H81.8182V10.1723H84.7649V11.445C84.4553 11.7732 83.9678 12.7052 83.9648 12.711L84.2439 12.8909C84.3975 12.5872 84.5426 12.3318 84.7649 11.9898C85.1247 11.3272 85.6236 10.8105 86.2617 10.4388C86.9006 10.0672 87.6702 9.88131 88.5704 9.88131Z" fill="white"/>
|
||||||
|
<path d="M109.109 9.88131C110.529 9.88131 111.662 10.3411 112.506 11.2626C113.334 12.1993 113.748 13.5655 113.748 15.3584V22.1937H110.731V15.6493C110.731 14.5667 110.512 13.7427 110.072 13.1776C109.633 12.6278 108.999 12.3529 108.171 12.3529C107.242 12.3529 106.515 12.6686 105.991 13.2982C105.45 13.9286 105.18 14.8255 105.18 15.9888V22.1937H102.139V10.1723H105.181V11.445C104.861 11.7733 104.357 12.7056 104.354 12.711L104.643 12.8909C104.802 12.5872 104.952 12.3317 105.181 11.9898C105.552 11.3272 106.068 10.8105 106.727 10.4388C107.386 10.0672 108.18 9.88131 109.109 9.88131Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.8 KiB |
14
apps/website/public/images/navbar/blog.svg
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 2.80055H2.80009V5.60064H0V2.80055Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M0 8.4005H2.80009V11.2006H0V8.4005Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M2.79941 0H5.5995V2.80009H2.79941V0Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M2.79941 5.59995H5.5995V8.40005H2.79941V5.59995Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M2.79941 11.1999H5.5995V14H2.79941V11.1999Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M5.59995 2.80055H8.40005V5.60064H5.59995V2.80055Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M5.59995 8.4005H8.40005V11.2006H5.59995V8.4005Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M8.4005 0H11.2006V2.80009H8.4005V0Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M11.1999 2.80055H14V5.60064H11.1999V2.80055Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M8.4005 5.59995H11.2006V8.40005H8.4005V5.59995Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M8.4005 11.1999H11.2006V14H8.4005V11.1999Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M11.1999 8.4005H14V11.2006H11.1999V8.4005Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
11
apps/website/public/images/navbar/cross.svg
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 0H3V3H0V0Z" fill="#515151"/>
|
||||||
|
<path d="M15 15H12V12H15V15Z" fill="#515151"/>
|
||||||
|
<path d="M3 3H6V6H3V3Z" fill="#515151"/>
|
||||||
|
<path d="M12 12H9V9H12V12Z" fill="#515151"/>
|
||||||
|
<path d="M9 3H12V6H9V3Z" fill="#515151"/>
|
||||||
|
<path d="M6 12H3L3 9H6L6 12Z" fill="#515151"/>
|
||||||
|
<path d="M9 9H6L6 6H9V9Z" fill="#515151"/>
|
||||||
|
<path d="M12 0H15V3H12V0Z" fill="#515151"/>
|
||||||
|
<path d="M3 15H0L2.62269e-07 12H3V15Z" fill="#515151"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 520 B |
13
apps/website/public/images/navbar/dashboard.svg
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g opacity="0.9">
|
||||||
|
<path d="M0 2.80055H2.80009V5.60064H0V2.80055Z" fill="#FCFCFC"/>
|
||||||
|
<path d="M0 8.4005H2.80009V11.2006H0V8.4005Z" fill="#FCFCFC"/>
|
||||||
|
<path d="M2.80055 0H5.60064V2.80009H2.80055V0Z" fill="#FCFCFC"/>
|
||||||
|
<path d="M2.80055 11.1999H5.60064V14H2.80055V11.1999Z" fill="#FCFCFC"/>
|
||||||
|
<path d="M5.59995 5.59995H8.40005V8.40005H5.59995V5.59995Z" fill="#FCFCFC"/>
|
||||||
|
<path d="M8.4005 0H11.2006V2.80009H8.4005V0Z" fill="#FCFCFC"/>
|
||||||
|
<path d="M11.1999 2.80055H14V5.60064H11.1999V2.80055Z" fill="#FCFCFC"/>
|
||||||
|
<path d="M8.4005 11.1999H11.2006V14H8.4005V11.1999Z" fill="#FCFCFC"/>
|
||||||
|
<path d="M11.1999 8.4005H14V11.2006H11.1999V8.4005Z" fill="#FCFCFC"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 743 B |
14
apps/website/public/images/navbar/discord.svg
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 0H2.80009V2.80009H0V0Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M0 11.1999H2.80009V14H0V11.1999Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M2.79941 2.80055H5.5995V5.60064H2.79941V2.80055Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M8.4005 2.80055H11.2006V5.60064H8.4005V2.80055Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M5.59995 0H8.40005V2.80009H5.59995V0Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M11.1999 0H14V2.80009H11.1999V0Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M0 5.59995H2.80009V8.40005H0V5.59995Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M2.79941 8.4005H5.5995V11.2006H2.79941V8.4005Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M8.4005 8.4005H11.2006V11.2006H8.4005V8.4005Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M5.59995 11.1999H8.40005V14H5.59995V11.1999Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M11.1999 5.59995H14V8.40005H11.1999V5.59995Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M11.1999 11.1999H14V14H11.1999V11.1999Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
11
apps/website/public/images/navbar/docs.svg
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M2.3335 0L4.667 2.3335L2.3335 4.667L0 2.3335L2.3335 0Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M7 0L9.3335 2.3335L7 4.667L4.667 2.3335L7 0Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M2.3335 4.667L4.667 7L2.3335 9.3335L0 7L2.3335 4.667Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M11.6665 0L14 2.3335L11.6665 4.667L9.3335 2.3335L11.6665 0Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M7 4.667L9.3335 7L7 9.3335L4.667 7L7 4.667Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M2.3335 9.3335L4.667 11.6665L2.3335 14L0 11.6665L2.3335 9.3335Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M11.6665 4.667L14 7L11.6665 9.3335L9.3335 7L11.6665 4.667Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M11.6665 9.3335L14 11.6665L11.6665 14L9.333 11.6665L11.6665 9.3335Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M7 9.3335L9.333 11.6665L7 14L4.667 11.6665L7 9.3335Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1001 B |
11
apps/website/public/images/navbar/dropdown.svg
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 0H3V3H0V0Z" fill="#515151"/>
|
||||||
|
<path d="M0 6H3V9H0V6Z" fill="#515151"/>
|
||||||
|
<path d="M0 12H3V15H0V12Z" fill="#515151"/>
|
||||||
|
<path d="M6 0H9V3H6V0Z" fill="#515151"/>
|
||||||
|
<path d="M6 6H9V9H6V6Z" fill="#515151"/>
|
||||||
|
<path d="M6 12H9V15H6V12Z" fill="#515151"/>
|
||||||
|
<path d="M12 0H15V3H12V0Z" fill="#515151"/>
|
||||||
|
<path d="M12 6H15V9H12V6Z" fill="#515151"/>
|
||||||
|
<path d="M12 12H15V15H12V12Z" fill="#515151"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 501 B |
13
apps/website/public/images/navbar/pricing.svg
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 0H2.8V2.8H0V0Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M14 14H11.2V11.2L14 11.2V14Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M14 8.40023H11.2V5.60023H14V8.40023Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M0 11.1995H2.8V13.9995H0V11.1995Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M2.80046 2.80046H5.60046V5.60046H2.80046V2.80046Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M11.2007 11.1995H8.40068V8.39954H11.2007V11.1995Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M8.40023 8.40023H5.60023L5.60046 5.60046L8.40023 5.60023V8.40023Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M11.2007 0H14.0007V2.8H11.2007V0Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M5.59977 0H8.39977V2.8H5.59977V0Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M8.40023 14H5.60023V11.2L8.40023 11.2V14Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
<path d="M0 5.59977H2.8V8.39977H0V5.59977Z" fill="white" fill-opacity="0.6"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1015 B |
BIN
apps/website/public/images/og-image.png
Executable file
|
After Width: | Height: | Size: 636 KiB |
BIN
apps/website/public/images/preloader/grid.png
Executable file
|
After Width: | Height: | Size: 12 KiB |
40
apps/website/public/images/preloader/grid.svg
Executable file
|
After Width: | Height: | Size: 417 KiB |
BIN
apps/website/public/images/preloader/logo.png
Executable file
|
After Width: | Height: | Size: 15 KiB |
19
apps/website/public/images/preloader/logo.svg
Executable file
|
After Width: | Height: | Size: 587 KiB |
BIN
apps/website/public/images/pricing-models/Hybrid Plan Builder (1).webp
Executable file
|
After Width: | Height: | Size: 54 KiB |
BIN
apps/website/public/images/pricing-models/Hybrid Plan Builder.webp
Executable file
|
After Width: | Height: | Size: 42 KiB |
BIN
apps/website/public/images/pricing-models/Subscriptions (1).webp
Executable file
|
After Width: | Height: | Size: 48 KiB |
BIN
apps/website/public/images/pricing-models/Subscriptions (2).webp
Executable file
|
After Width: | Height: | Size: 36 KiB |
BIN
apps/website/public/images/pricing-models/Subscriptions (3).webp
Executable file
|
After Width: | Height: | Size: 50 KiB |
BIN
apps/website/public/images/pricing-models/Subscriptions.webp
Executable file
|
After Width: | Height: | Size: 54 KiB |
BIN
apps/website/public/images/pricing-models/Trial Configuration.webp
Executable file
|
After Width: | Height: | Size: 52 KiB |
BIN
apps/website/public/images/pricing-models/Usage Metering.webp
Executable file
|
After Width: | Height: | Size: 40 KiB |
9
apps/website/public/images/pricing-models/pricingbg.svg
Executable file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
apps/website/public/images/pricing-models/pricingbg.webm
Executable file
3
apps/website/public/images/pricing-models/tickarrow.svg
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="13" height="11" viewBox="0 0 13 11" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12.875 0.125V2.04199H11.3125V3.70801H9.75V5.375H8.1875V7.04199H6.625V8.70801H5.0625V10.375H3.25V8.70801H1.6875V7.04199H0.125V5.125H1.9375V6.79199H3.5V8.45801H4.8125V6.79199H6.375V5.125H7.9375V3.45801H9.5V1.79199H11.0625V0.125H12.875Z" fill="#178000" stroke="#178000" stroke-width="0.25"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 405 B |
13
apps/website/public/images/pricing/FAQ/faqbg.svg
Executable file
|
After Width: | Height: | Size: 2.0 MiB |
10
apps/website/public/images/pricing/FAQ/minus.svg
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="16" y="16" width="2" height="2" transform="rotate(-180 16 16)" fill="#D9D9D9"/>
|
||||||
|
<rect x="7" y="9.08008" width="2" height="2" transform="rotate(-180 7 9.08008)" fill="#D9D9D9"/>
|
||||||
|
<rect width="4.43945" height="2" transform="matrix(1 8.74228e-08 8.74228e-08 -1 6.56055 9.08008)" fill="#D9D9D9"/>
|
||||||
|
<rect x="5" y="9.08008" width="2" height="2" transform="rotate(-180 5 9.08008)" fill="#D9D9D9"/>
|
||||||
|
<rect width="2" height="2" transform="matrix(1 8.74228e-08 8.74228e-08 -1 11 9.08008)" fill="#D9D9D9"/>
|
||||||
|
<rect x="16" y="2" width="2" height="2" transform="rotate(-180 16 2)" fill="#D9D9D9"/>
|
||||||
|
<rect x="2" y="16" width="2" height="2" transform="rotate(-180 2 16)" fill="#D9D9D9"/>
|
||||||
|
<rect x="2" y="2" width="2" height="2" transform="rotate(-180 2 2)" fill="#D9D9D9"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 874 B |
16
apps/website/public/images/pricing/FAQ/plus.svg
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g opacity="0.4">
|
||||||
|
<rect x="16" y="16" width="2" height="2" transform="rotate(-180 16 16)" fill="#D9D9D9"/>
|
||||||
|
<rect x="7" y="9.08008" width="2" height="2" transform="rotate(-180 7 9.08008)" fill="#D9D9D9"/>
|
||||||
|
<rect x="9" y="7" width="2" height="2" transform="rotate(-180 9 7)" fill="#D9D9D9"/>
|
||||||
|
<rect x="9" y="13.0469" width="2" height="2" transform="rotate(-180 9 13.0469)" fill="#D9D9D9"/>
|
||||||
|
<rect x="9" y="5.02832" width="2" height="2" transform="rotate(-180 9 5.02832)" fill="#D9D9D9"/>
|
||||||
|
<rect x="9" y="11.0752" width="2" height="2" transform="rotate(-180 9 11.0752)" fill="#D9D9D9"/>
|
||||||
|
<rect width="2" height="2" transform="matrix(1 8.74228e-08 8.74228e-08 -1 9 9.08008)" fill="#D9D9D9"/>
|
||||||
|
<rect x="5" y="9.08008" width="2" height="2" transform="rotate(-180 5 9.08008)" fill="#D9D9D9"/>
|
||||||
|
<rect width="2" height="2" transform="matrix(1 8.74228e-08 8.74228e-08 -1 11 9.08008)" fill="#D9D9D9"/>
|
||||||
|
<rect x="16" y="2" width="2" height="2" transform="rotate(-180 16 2)" fill="#D9D9D9"/>
|
||||||
|
<rect x="2" y="16" width="2" height="2" transform="rotate(-180 2 16)" fill="#D9D9D9"/>
|
||||||
|
<rect x="2" y="2" width="2" height="2" transform="rotate(-180 2 2)" fill="#D9D9D9"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
BIN
apps/website/public/images/pricing/pricing_mobile.webp
Executable file
|
After Width: | Height: | Size: 530 KiB |
15
apps/website/public/images/pricing/pricingbg.svg
Executable file
|
After Width: | Height: | Size: 18 MiB |