diff --git a/app/(root)/layout.tsx b/app/(root)/layout.tsx
new file mode 100644
index 0000000..519e827
--- /dev/null
+++ b/app/(root)/layout.tsx
@@ -0,0 +1,14 @@
+import Navbar from "@/components/Navbar";
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return (
+ <>
+
+ {children}
+ >
+ );
+}
diff --git a/app/page.tsx b/app/(root)/page.tsx
similarity index 100%
rename from app/page.tsx
rename to app/(root)/page.tsx
diff --git a/app/globals.css b/app/globals.css
index 21b3e8a..93ba888 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -194,4 +194,39 @@
*::-webkit-scrollbar-thumb:hover {
background-color: var(--color-border-heavy);
}
-}
\ No newline at end of file
+}
+
+@layer utilities {
+ .nav-hover-btn {
+ @apply relative cursor-pointer;
+ @apply after:absolute after:-bottom-0.5 after:left-0 after:h-0.5 after:w-full;
+ @apply after:origin-bottom-right after:scale-x-0;
+ @apply after:transition-transform after:duration-300 after:ease-[cubic-bezier(0.65_0.05_0.36_1)];
+ @apply hover:after:origin-bottom-left hover:after:scale-x-100;
+ @apply after:bg-primary-500;
+ }
+
+ .dark .nav-hover-btn::after {
+ @apply after:bg-primary-400;
+ }
+
+ .floating-nav {
+ @apply rounded-xl border border-border-light bg-surface/80 backdrop-blur-md shadow-lg transition-all duration-300;
+ }
+
+ .dark .floating-nav {
+ @apply bg-surface/95 border-border-default shadow-xl backdrop-blur-lg;
+ }
+
+ .nav-hover-btn:focus-visible {
+ @apply outline-none ring-2 ring-primary-500 ring-offset-2 ring-offset-surface rounded-sm;
+ }
+
+ /* Reduced motion support */
+ @media (prefers-reduced-motion: reduce) {
+ .nav-hover-btn::after,
+ .floating-nav {
+ @apply transition-none;
+ }
+ }
+}
diff --git a/app/layout.tsx b/app/layout.tsx
index 4d828b2..7345400 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -20,7 +20,9 @@ export default function RootLayout({
}>) {
return (
-
{children}
+
+ {children}
+
);
}
diff --git a/components/Navbar.tsx b/components/Navbar.tsx
new file mode 100644
index 0000000..04a197d
--- /dev/null
+++ b/components/Navbar.tsx
@@ -0,0 +1,113 @@
+"use client";
+
+import { useAuth } from "@/hooks/useAuth";
+import { NAVBAR_ITEMS } from "@/lib/constants";
+import Link from "next/link";
+import { useEffect, useRef, useState } from "react";
+import { useWindowScroll } from "react-use";
+import gsap from "gsap";
+
+const Navbar = () => {
+ const { user } = useAuth();
+ const [isNavVisible, setIsNavVisible] = useState(true);
+ const { y: currentScrollY } = useWindowScroll();
+ const [lastScrollY, setLastScrollY] = useState(0);
+ const navContainerRef = useRef(null);
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
+
+ // Check for reduced motion preference
+ useEffect(() => {
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
+ setPrefersReducedMotion(mediaQuery.matches);
+
+ const handler = (e: MediaQueryListEvent) =>
+ setPrefersReducedMotion(e.matches);
+ mediaQuery.addEventListener("change", handler);
+ return () => mediaQuery.removeEventListener("change", handler);
+ }, []);
+
+ useEffect(() => {
+ const SCROLL_THRESHOLD = 10;
+ const HIDE_DELAY_PX = 50;
+
+ if (currentScrollY === 0) {
+ setIsNavVisible(true);
+ navContainerRef.current?.classList.remove("floating-nav");
+ } else if (currentScrollY > lastScrollY && currentScrollY > HIDE_DELAY_PX) {
+ setIsNavVisible(false);
+ navContainerRef.current?.classList.add("floating-nav");
+ } else if (
+ currentScrollY < lastScrollY &&
+ Math.abs(currentScrollY - lastScrollY) > SCROLL_THRESHOLD
+ ) {
+ setIsNavVisible(true);
+ navContainerRef.current?.classList.add("floating-nav");
+ }
+
+ setLastScrollY(currentScrollY);
+ }, [currentScrollY, lastScrollY]);
+
+ useEffect(() => {
+ if (!navContainerRef.current) return;
+
+ gsap.to(navContainerRef.current, {
+ y: isNavVisible ? 0 : 100,
+ opacity: isNavVisible ? 1 : 0,
+ visibility: isNavVisible ? "visible" : "hidden",
+ duration: prefersReducedMotion ? 0 : 0.2,
+ pointerEvents: isNavVisible ? "auto" : "none",
+ });
+ }, [isNavVisible, prefersReducedMotion]);
+
+ return (
+
+ );
+};
+
+export default Navbar;
diff --git a/lib/constants.ts b/lib/constants.ts
index a0047ed..6ee45a3 100644
--- a/lib/constants.ts
+++ b/lib/constants.ts
@@ -1,3 +1,5 @@
+import { NavItemsTypes } from "@/types/types";
+
export const PLANS = [
{
id: "free",
@@ -101,3 +103,18 @@ export const PLANS_BY_ID = PLANS.reduce(
export const getPlanById = (id: string): Plan | undefined => {
return PLANS_BY_ID[id as PlanId];
};
+
+export const NAVBAR_ITEMS: NavItemsTypes[] = [
+ {
+ name: "Pricing",
+ link: "/pricing",
+ },
+ {
+ name: "About",
+ link: "/#",
+ },
+ {
+ name: "Contact",
+ link: "/#",
+ },
+];
diff --git a/package.json b/package.json
index a30e28c..e4831cd 100644
--- a/package.json
+++ b/package.json
@@ -18,8 +18,10 @@
"seed": "bun run scripts/seed.ts"
},
"dependencies": {
+ "@gsap/react": "^2.1.2",
"@hookform/resolvers": "^5.4.0",
"dotenv": "^17.4.2",
+ "gsap": "^3.15.0",
"jsonwebtoken": "^9.0.3",
"lucide-react": "^1.17.0",
"mongodb": "^7.2.0",
@@ -30,6 +32,7 @@
"react": "19.2.4",
"react-dom": "19.2.4",
"react-hook-form": "^7.77.0",
+ "react-use": "^17.6.1",
"zod": "^4.4.3"
},
"devDependencies": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4eb7432..a3a12f2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,12 +8,18 @@ importers:
.:
dependencies:
+ '@gsap/react':
+ specifier: ^2.1.2
+ version: 2.1.2(gsap@3.15.0)(react@19.2.4)
'@hookform/resolvers':
specifier: ^5.4.0
version: 5.4.0(react-hook-form@7.77.0(react@19.2.4))
dotenv:
specifier: ^17.4.2
version: 17.4.2
+ gsap:
+ specifier: ^3.15.0
+ version: 3.15.0
jsonwebtoken:
specifier: ^9.0.3
version: 9.0.3
@@ -44,6 +50,9 @@ importers:
react-hook-form:
specifier: ^7.77.0
version: 7.77.0(react@19.2.4)
+ react-use:
+ specifier: ^17.6.1
+ version: 17.6.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
zod:
specifier: ^4.4.3
version: 4.4.3
@@ -301,6 +310,12 @@ packages:
'@noble/hashes':
optional: true
+ '@gsap/react@2.1.2':
+ resolution: {integrity: sha512-JqliybO1837UcgH2hVOM4VO+38APk3ECNrsuSM4MuXp+rbf+/2IG2K1YJiqfTcXQHH7XlA0m3ykniFYstfq0Iw==}
+ peerDependencies:
+ gsap: ^3.12.5
+ react: '>=17'
+
'@hookform/resolvers@5.4.0':
resolution: {integrity: sha512-EIsqr/t/qbinPIhGjMdtvutIN1Kk4uwbROE9/UQ93CAVGR7GkA7Y92+fX80OzXi/OB67jVFYwKGO1WzkxmkFZw==}
peerDependencies:
@@ -833,6 +848,9 @@ packages:
'@types/estree@1.0.9':
resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
+ '@types/js-cookie@3.0.6':
+ resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==}
+
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@@ -1097,6 +1115,9 @@ packages:
'@vitest/utils@4.1.7':
resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==}
+ '@xobotyi/scrollbar-width@1.9.5':
+ resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==}
+
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@@ -1282,10 +1303,20 @@ packages:
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+ copy-to-clipboard@3.3.3:
+ resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==}
+
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
+ css-in-js-utils@3.1.0:
+ resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==}
+
+ css-tree@1.1.3:
+ resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==}
+ engines: {node: '>=8.0.0'}
+
css-tree@3.2.1:
resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
@@ -1395,6 +1426,9 @@ packages:
resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==}
engines: {node: '>=20.19.0'}
+ error-stack-parser@2.1.4:
+ resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==}
+
es-abstract@1.24.2:
resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==}
engines: {node: '>= 0.4'}
@@ -1584,6 +1618,12 @@ packages:
fast-safe-stringify@2.1.1:
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+ fast-shallow-equal@1.0.0:
+ resolution: {integrity: sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==}
+
+ fastest-stable-stringify@2.0.2:
+ resolution: {integrity: sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==}
+
fastq@1.20.1:
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
@@ -1690,6 +1730,9 @@ packages:
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+ gsap@3.15.0:
+ resolution: {integrity: sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==}
+
has-bigints@1.1.0:
resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
engines: {node: '>= 0.4'}
@@ -1733,6 +1776,9 @@ packages:
html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+ hyphenate-style-name@1.1.0:
+ resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==}
+
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -1753,6 +1799,9 @@ packages:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
engines: {node: '>=8'}
+ inline-style-prefixer@7.0.1:
+ resolution: {integrity: sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==}
+
internal-slot@1.1.0:
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
engines: {node: '>= 0.4'}
@@ -1893,6 +1942,9 @@ packages:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
+ js-cookie@3.0.8:
+ resolution: {integrity: sha512-yeJd4aNAdYZQjaon2bpD/Gb0B/omw7HQOsynXXcOiWVCacbBcPlgn8S/d1X6blFSaHao7ozqtW7NZW19xpCtIw==}
+
js-tokens@10.0.0:
resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
@@ -2103,6 +2155,9 @@ packages:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
+ mdn-data@2.0.14:
+ resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
+
mdn-data@2.27.1:
resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
@@ -2181,6 +2236,12 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ nano-css@5.6.2:
+ resolution: {integrity: sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw==}
+ peerDependencies:
+ react: '*'
+ react-dom: '*'
+
nanoid@3.3.12:
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -2383,6 +2444,18 @@ packages:
react-is@17.0.2:
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
+ react-universal-interface@0.6.2:
+ resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==}
+ peerDependencies:
+ react: '*'
+ tslib: '*'
+
+ react-use@17.6.1:
+ resolution: {integrity: sha512-uibb3pgzV4LFsYPHyXYGu7dD2+pyk/ZJlPH+AizBR3zolqPWyCleKcWWbUQaKSKfydwgnQ3ymGm1Ab3/saGHCA==}
+ peerDependencies:
+ react: '*'
+ react-dom: '*'
+
react@19.2.4:
resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
engines: {node: '>=0.10.0'}
@@ -2410,6 +2483,9 @@ packages:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
+ resize-observer-polyfill@1.5.1:
+ resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
+
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -2431,6 +2507,9 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
+ rtl-css-js@1.16.1:
+ resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==}
+
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
@@ -2460,6 +2539,10 @@ packages:
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
+ screenfull@5.2.0:
+ resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==}
+ engines: {node: '>=0.10.0'}
+
secure-json-parse@4.1.0:
resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==}
@@ -2480,6 +2563,10 @@ packages:
resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
engines: {node: '>= 0.4'}
+ set-harmonic-interval@1.0.1:
+ resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==}
+ engines: {node: '>=6.9'}
+
set-proto@1.0.0:
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
engines: {node: '>= 0.4'}
@@ -2529,6 +2616,14 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
+ source-map@0.5.6:
+ resolution: {integrity: sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==}
+ engines: {node: '>=0.10.0'}
+
+ source-map@0.6.1:
+ resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+ engines: {node: '>=0.10.0'}
+
sparse-bitfield@3.0.3:
resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
@@ -2539,9 +2634,21 @@ packages:
stable-hash@0.0.5:
resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
+ stack-generator@2.0.10:
+ resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==}
+
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+ stackframe@1.3.4:
+ resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==}
+
+ stacktrace-gps@3.1.2:
+ resolution: {integrity: sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==}
+
+ stacktrace-js@2.0.2:
+ resolution: {integrity: sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==}
+
std-env@4.1.0:
resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==}
@@ -2601,6 +2708,9 @@ packages:
babel-plugin-macros:
optional: true
+ stylis@4.4.0:
+ resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==}
+
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
@@ -2623,6 +2733,10 @@ packages:
resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==}
engines: {node: '>=20'}
+ throttle-debounce@3.0.1:
+ resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==}
+ engines: {node: '>=10'}
+
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
@@ -2649,6 +2763,9 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
+ toggle-selection@1.0.6:
+ resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==}
+
totalist@3.0.1:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
@@ -2671,6 +2788,9 @@ packages:
peerDependencies:
typescript: '>=4.8.4'
+ ts-easing@0.2.0:
+ resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==}
+
tsconfck@3.1.6:
resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==}
engines: {node: ^18 || >=20}
@@ -3133,6 +3253,11 @@ snapshots:
'@exodus/bytes@1.15.1': {}
+ '@gsap/react@2.1.2(gsap@3.15.0)(react@19.2.4)':
+ dependencies:
+ gsap: 3.15.0
+ react: 19.2.4
+
'@hookform/resolvers@5.4.0(react-hook-form@7.77.0(react@19.2.4))':
dependencies:
'@standard-schema/utils': 0.3.0
@@ -3511,6 +3636,8 @@ snapshots:
'@types/estree@1.0.9': {}
+ '@types/js-cookie@3.0.6': {}
+
'@types/json-schema@7.0.15': {}
'@types/json5@0.0.29': {}
@@ -3772,6 +3899,8 @@ snapshots:
convert-source-map: 2.0.0
tinyrainbow: 3.1.0
+ '@xobotyi/scrollbar-width@1.9.5': {}
+
acorn-jsx@5.3.2(acorn@8.16.0):
dependencies:
acorn: 8.16.0
@@ -3969,12 +4098,25 @@ snapshots:
convert-source-map@2.0.0: {}
+ copy-to-clipboard@3.3.3:
+ dependencies:
+ toggle-selection: 1.0.6
+
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
+ css-in-js-utils@3.1.0:
+ dependencies:
+ hyphenate-style-name: 1.1.0
+
+ css-tree@1.1.3:
+ dependencies:
+ mdn-data: 2.0.14
+ source-map: 0.6.1
+
css-tree@3.2.1:
dependencies:
mdn-data: 2.27.1
@@ -4076,6 +4218,10 @@ snapshots:
entities@8.0.0: {}
+ error-stack-parser@2.1.4:
+ dependencies:
+ stackframe: 1.3.4
+
es-abstract@1.24.2:
dependencies:
array-buffer-byte-length: 1.0.2
@@ -4412,6 +4558,10 @@ snapshots:
fast-safe-stringify@2.1.1: {}
+ fast-shallow-equal@1.0.0: {}
+
+ fastest-stable-stringify@2.0.2: {}
+
fastq@1.20.1:
dependencies:
reusify: 1.1.0
@@ -4517,6 +4667,8 @@ snapshots:
graceful-fs@4.2.11: {}
+ gsap@3.15.0: {}
+
has-bigints@1.1.0: {}
has-flag@4.0.0: {}
@@ -4555,6 +4707,8 @@ snapshots:
html-escaper@2.0.2: {}
+ hyphenate-style-name@1.1.0: {}
+
ignore@5.3.2: {}
ignore@7.0.5: {}
@@ -4568,6 +4722,10 @@ snapshots:
indent-string@4.0.0: {}
+ inline-style-prefixer@7.0.1:
+ dependencies:
+ css-in-js-utils: 3.1.0
+
internal-slot@1.1.0:
dependencies:
es-errors: 1.3.0
@@ -4718,6 +4876,8 @@ snapshots:
joycon@3.1.1: {}
+ js-cookie@3.0.8: {}
+
js-tokens@10.0.0: {}
js-tokens@4.0.0: {}
@@ -4915,6 +5075,8 @@ snapshots:
math-intrinsics@1.1.0: {}
+ mdn-data@2.0.14: {}
+
mdn-data@2.27.1: {}
memory-pager@1.5.0: {}
@@ -4974,6 +5136,19 @@ snapshots:
ms@2.1.3: {}
+ nano-css@5.6.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ css-tree: 1.1.3
+ csstype: 3.2.3
+ fastest-stable-stringify: 2.0.2
+ inline-style-prefixer: 7.0.1
+ react: 19.2.4
+ react-dom: 19.2.4(react@19.2.4)
+ rtl-css-js: 1.16.1
+ stacktrace-js: 2.0.2
+ stylis: 4.4.0
+
nanoid@3.3.12: {}
napi-postinstall@0.3.4: {}
@@ -5198,6 +5373,30 @@ snapshots:
react-is@17.0.2: {}
+ react-universal-interface@0.6.2(react@19.2.4)(tslib@2.8.1):
+ dependencies:
+ react: 19.2.4
+ tslib: 2.8.1
+
+ react-use@17.6.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
+ dependencies:
+ '@types/js-cookie': 3.0.6
+ '@xobotyi/scrollbar-width': 1.9.5
+ copy-to-clipboard: 3.3.3
+ fast-deep-equal: 3.1.3
+ fast-shallow-equal: 1.0.0
+ js-cookie: 3.0.8
+ nano-css: 5.6.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ react: 19.2.4
+ react-dom: 19.2.4(react@19.2.4)
+ react-universal-interface: 0.6.2(react@19.2.4)(tslib@2.8.1)
+ resize-observer-polyfill: 1.5.1
+ screenfull: 5.2.0
+ set-harmonic-interval: 1.0.1
+ throttle-debounce: 3.0.1
+ ts-easing: 0.2.0
+ tslib: 2.8.1
+
react@19.2.4: {}
real-require@0.2.0: {}
@@ -5231,6 +5430,8 @@ snapshots:
require-from-string@2.0.2: {}
+ resize-observer-polyfill@1.5.1: {}
+
resolve-from@4.0.0: {}
resolve-pkg-maps@1.0.0: {}
@@ -5267,6 +5468,10 @@ snapshots:
'@rolldown/binding-win32-arm64-msvc': 1.0.2
'@rolldown/binding-win32-x64-msvc': 1.0.2
+ rtl-css-js@1.16.1:
+ dependencies:
+ '@babel/runtime': 7.29.7
+
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
@@ -5300,6 +5505,8 @@ snapshots:
scheduler@0.27.0: {}
+ screenfull@5.2.0: {}
+
secure-json-parse@4.1.0: {}
semver@6.3.1: {}
@@ -5322,6 +5529,8 @@ snapshots:
functions-have-names: 1.2.3
has-property-descriptors: 1.0.2
+ set-harmonic-interval@1.0.1: {}
+
set-proto@1.0.0:
dependencies:
dunder-proto: 1.0.1
@@ -5410,6 +5619,10 @@ snapshots:
source-map-js@1.2.1: {}
+ source-map@0.5.6: {}
+
+ source-map@0.6.1: {}
+
sparse-bitfield@3.0.3:
dependencies:
memory-pager: 1.5.0
@@ -5418,8 +5631,25 @@ snapshots:
stable-hash@0.0.5: {}
+ stack-generator@2.0.10:
+ dependencies:
+ stackframe: 1.3.4
+
stackback@0.0.2: {}
+ stackframe@1.3.4: {}
+
+ stacktrace-gps@3.1.2:
+ dependencies:
+ source-map: 0.5.6
+ stackframe: 1.3.4
+
+ stacktrace-js@2.0.2:
+ dependencies:
+ error-stack-parser: 2.1.4
+ stack-generator: 2.0.10
+ stacktrace-gps: 3.1.2
+
std-env@4.1.0: {}
stop-iteration-iterator@1.1.0:
@@ -5494,6 +5724,8 @@ snapshots:
optionalDependencies:
'@babel/core': 7.29.7
+ stylis@4.4.0: {}
+
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
@@ -5510,6 +5742,8 @@ snapshots:
dependencies:
real-require: 1.0.0
+ throttle-debounce@3.0.1: {}
+
tinybench@2.9.0: {}
tinyexec@1.2.4: {}
@@ -5531,6 +5765,8 @@ snapshots:
dependencies:
is-number: 7.0.0
+ toggle-selection@1.0.6: {}
+
totalist@3.0.1: {}
tough-cookie@6.0.1:
@@ -5549,6 +5785,8 @@ snapshots:
dependencies:
typescript: 5.9.3
+ ts-easing@0.2.0: {}
+
tsconfck@3.1.6(typescript@5.9.3):
optionalDependencies:
typescript: 5.9.3
diff --git a/proxy.ts b/proxy.ts
index baaf7a0..a2d76ac 100644
--- a/proxy.ts
+++ b/proxy.ts
@@ -7,6 +7,7 @@ const publicRoutes = [
"/sign-up",
"/api/sign-in",
"/api/sign-up",
+ "/pricing",
];
const protectedRoutes = ["/dashboard", "/workspaces", "/api/protected"];
diff --git a/types/types.ts b/types/types.ts
new file mode 100644
index 0000000..67760f6
--- /dev/null
+++ b/types/types.ts
@@ -0,0 +1,4 @@
+export interface NavItemsTypes {
+ name: string;
+ link: string;
+}