feat: Add responsive Navbar component with smooth scrolling and enhanced UX
Browse files- Implemented a new Navbar component with mobile and desktop views.
- Added smooth scrolling functionality for internal links.
- Enhanced scroll handling with throttling for performance.
- Integrated Framer Motion for animations and transitions.
- Updated global styles for improved theming and scrollbar customization.
refactor: Update _app.js to include Google Fonts and improve layout
- Changed font from Bricolage Grotesque to Inter for better performance.
- Added Head component for preconnecting to Google Fonts and including stylesheet.
feat: Revamp index.js with new layout and sections for features, converters, and social media
- Introduced sections for features, converters, and social media downloading.
- Utilized Framer Motion for animations and scroll effects.
- Added converter tabs and dynamic content rendering based on user selection.
style: Enhance global styles for light and dark themes
- Defined new CSS variables for light and dark themes.
- Improved body styles for better font rendering and line height.
- Added custom scrollbar styles and selection colors.
- Implemented glassmorphism effect for UI elements.
- frontend/bun.lock +43 -2
- frontend/next.config.mjs +61 -0
- frontend/package.json +4 -1
- frontend/src/components/Footer.js +230 -0
- frontend/src/components/Navbar.js +228 -0
- frontend/src/pages/_app.js +16 -8
- frontend/src/pages/index.js +629 -91
- frontend/src/styles/globals.css +119 -6
|
@@ -4,9 +4,12 @@
|
|
| 4 |
"": {
|
| 5 |
"name": "lumakit-frontend",
|
| 6 |
"dependencies": {
|
|
|
|
|
|
|
| 7 |
"next": "15.1.8",
|
| 8 |
"react": "^19.0.0",
|
| 9 |
"react-dom": "^19.0.0",
|
|
|
|
| 10 |
},
|
| 11 |
"devDependencies": {
|
| 12 |
"postcss": "^8",
|
|
@@ -101,7 +104,7 @@
|
|
| 101 |
|
| 102 |
"ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
| 103 |
|
| 104 |
-
"ansi-styles": ["ansi-styles@
|
| 105 |
|
| 106 |
"any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
|
| 107 |
|
|
@@ -113,6 +116,8 @@
|
|
| 113 |
|
| 114 |
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
| 115 |
|
|
|
|
|
|
|
| 116 |
"brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
| 117 |
|
| 118 |
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
|
@@ -123,6 +128,8 @@
|
|
| 123 |
|
| 124 |
"caniuse-lite": ["caniuse-lite@1.0.30001718", "", {}, "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw=="],
|
| 125 |
|
|
|
|
|
|
|
| 126 |
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
| 127 |
|
| 128 |
"client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="],
|
|
@@ -137,8 +144,14 @@
|
|
| 137 |
|
| 138 |
"commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
|
| 139 |
|
|
|
|
|
|
|
| 140 |
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
| 141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
"cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
|
| 143 |
|
| 144 |
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
|
|
@@ -147,10 +160,20 @@
|
|
| 147 |
|
| 148 |
"dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="],
|
| 149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
| 151 |
|
| 152 |
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
| 153 |
|
|
|
|
|
|
|
| 154 |
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
| 155 |
|
| 156 |
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
|
|
@@ -159,6 +182,8 @@
|
|
| 159 |
|
| 160 |
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
| 161 |
|
|
|
|
|
|
|
| 162 |
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
| 163 |
|
| 164 |
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
|
@@ -167,8 +192,12 @@
|
|
| 167 |
|
| 168 |
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
| 169 |
|
|
|
|
|
|
|
| 170 |
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
| 171 |
|
|
|
|
|
|
|
| 172 |
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
|
| 173 |
|
| 174 |
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
|
@@ -203,6 +232,10 @@
|
|
| 203 |
|
| 204 |
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
| 205 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
|
| 207 |
|
| 208 |
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
|
@@ -211,6 +244,8 @@
|
|
| 211 |
|
| 212 |
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
| 213 |
|
|
|
|
|
|
|
| 214 |
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
| 215 |
|
| 216 |
"object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="],
|
|
@@ -239,6 +274,8 @@
|
|
| 239 |
|
| 240 |
"postcss-load-config": ["postcss-load-config@4.0.2", "", { "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "optionalPeers": ["postcss", "ts-node"] }, "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ=="],
|
| 241 |
|
|
|
|
|
|
|
| 242 |
"postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="],
|
| 243 |
|
| 244 |
"postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
|
|
@@ -251,6 +288,8 @@
|
|
| 251 |
|
| 252 |
"react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="],
|
| 253 |
|
|
|
|
|
|
|
| 254 |
"read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="],
|
| 255 |
|
| 256 |
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
|
@@ -291,6 +330,8 @@
|
|
| 291 |
|
| 292 |
"sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="],
|
| 293 |
|
|
|
|
|
|
|
| 294 |
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
| 295 |
|
| 296 |
"tailwindcss": ["tailwindcss@3.4.17", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.6", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og=="],
|
|
@@ -327,7 +368,7 @@
|
|
| 327 |
|
| 328 |
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
| 329 |
|
| 330 |
-
"wrap-ansi
|
| 331 |
|
| 332 |
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
| 333 |
|
|
|
|
| 4 |
"": {
|
| 5 |
"name": "lumakit-frontend",
|
| 6 |
"dependencies": {
|
| 7 |
+
"critters": "^0.0.25",
|
| 8 |
+
"framer-motion": "^12.12.2",
|
| 9 |
"next": "15.1.8",
|
| 10 |
"react": "^19.0.0",
|
| 11 |
"react-dom": "^19.0.0",
|
| 12 |
+
"react-icons": "^5.5.0",
|
| 13 |
},
|
| 14 |
"devDependencies": {
|
| 15 |
"postcss": "^8",
|
|
|
|
| 104 |
|
| 105 |
"ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
| 106 |
|
| 107 |
+
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
| 108 |
|
| 109 |
"any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
|
| 110 |
|
|
|
|
| 116 |
|
| 117 |
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
| 118 |
|
| 119 |
+
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
|
| 120 |
+
|
| 121 |
"brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
| 122 |
|
| 123 |
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
|
|
|
| 128 |
|
| 129 |
"caniuse-lite": ["caniuse-lite@1.0.30001718", "", {}, "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw=="],
|
| 130 |
|
| 131 |
+
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
| 132 |
+
|
| 133 |
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
| 134 |
|
| 135 |
"client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="],
|
|
|
|
| 144 |
|
| 145 |
"commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
|
| 146 |
|
| 147 |
+
"critters": ["critters@0.0.25", "", { "dependencies": { "chalk": "^4.1.0", "css-select": "^5.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.2", "htmlparser2": "^8.0.2", "postcss": "^8.4.23", "postcss-media-query-parser": "^0.2.3" } }, "sha512-ROF/tjJyyRdM8/6W0VqoN5Ql05xAGnkf5b7f3sTEl1bI5jTQQf8O918RD/V9tEb9pRY/TKcvJekDbJtniHyPtQ=="],
|
| 148 |
+
|
| 149 |
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
| 150 |
|
| 151 |
+
"css-select": ["css-select@5.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg=="],
|
| 152 |
+
|
| 153 |
+
"css-what": ["css-what@6.1.0", "", {}, "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="],
|
| 154 |
+
|
| 155 |
"cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
|
| 156 |
|
| 157 |
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
|
|
|
|
| 160 |
|
| 161 |
"dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="],
|
| 162 |
|
| 163 |
+
"dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
|
| 164 |
+
|
| 165 |
+
"domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
|
| 166 |
+
|
| 167 |
+
"domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
|
| 168 |
+
|
| 169 |
+
"domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
|
| 170 |
+
|
| 171 |
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
| 172 |
|
| 173 |
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
| 174 |
|
| 175 |
+
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
|
| 176 |
+
|
| 177 |
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
| 178 |
|
| 179 |
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
|
|
|
|
| 182 |
|
| 183 |
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
| 184 |
|
| 185 |
+
"framer-motion": ["framer-motion@12.12.2", "", { "dependencies": { "motion-dom": "^12.12.1", "motion-utils": "^12.12.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-qCszZCiGWkilL40E3VuhIJJC/CS3SIBl2IHyGK8FU30nOUhTmhBNWPrNFyozAWH/bXxwzi19vJHIGVdALF0LCg=="],
|
| 186 |
+
|
| 187 |
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
| 188 |
|
| 189 |
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
|
|
|
| 192 |
|
| 193 |
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
| 194 |
|
| 195 |
+
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
| 196 |
+
|
| 197 |
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
| 198 |
|
| 199 |
+
"htmlparser2": ["htmlparser2@8.0.2", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1", "entities": "^4.4.0" } }, "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA=="],
|
| 200 |
+
|
| 201 |
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
|
| 202 |
|
| 203 |
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
|
|
|
| 232 |
|
| 233 |
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
| 234 |
|
| 235 |
+
"motion-dom": ["motion-dom@12.12.1", "", { "dependencies": { "motion-utils": "^12.12.1" } }, "sha512-GXq/uUbZBEiFFE+K1Z/sxdPdadMdfJ/jmBALDfIuHGi0NmtealLOfH9FqT+6aNPgVx8ilq0DtYmyQlo6Uj9LKQ=="],
|
| 236 |
+
|
| 237 |
+
"motion-utils": ["motion-utils@12.12.1", "", {}, "sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w=="],
|
| 238 |
+
|
| 239 |
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
|
| 240 |
|
| 241 |
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
|
|
|
| 244 |
|
| 245 |
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
| 246 |
|
| 247 |
+
"nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="],
|
| 248 |
+
|
| 249 |
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
| 250 |
|
| 251 |
"object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="],
|
|
|
|
| 274 |
|
| 275 |
"postcss-load-config": ["postcss-load-config@4.0.2", "", { "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "optionalPeers": ["postcss", "ts-node"] }, "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ=="],
|
| 276 |
|
| 277 |
+
"postcss-media-query-parser": ["postcss-media-query-parser@0.2.3", "", {}, "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig=="],
|
| 278 |
+
|
| 279 |
"postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="],
|
| 280 |
|
| 281 |
"postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
|
|
|
|
| 288 |
|
| 289 |
"react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="],
|
| 290 |
|
| 291 |
+
"react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="],
|
| 292 |
+
|
| 293 |
"read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="],
|
| 294 |
|
| 295 |
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
|
|
|
| 330 |
|
| 331 |
"sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="],
|
| 332 |
|
| 333 |
+
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
| 334 |
+
|
| 335 |
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
| 336 |
|
| 337 |
"tailwindcss": ["tailwindcss@3.4.17", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.6", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og=="],
|
|
|
|
| 368 |
|
| 369 |
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
| 370 |
|
| 371 |
+
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
| 372 |
|
| 373 |
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
| 374 |
|
|
@@ -1,6 +1,67 @@
|
|
| 1 |
/** @type {import('next').NextConfig} */
|
| 2 |
const nextConfig = {
|
| 3 |
reactStrictMode: true,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
};
|
| 5 |
|
| 6 |
export default nextConfig;
|
|
|
|
| 1 |
/** @type {import('next').NextConfig} */
|
| 2 |
const nextConfig = {
|
| 3 |
reactStrictMode: true,
|
| 4 |
+
|
| 5 |
+
// Performance optimizations
|
| 6 |
+
swcMinify: true,
|
| 7 |
+
compress: true,
|
| 8 |
+
|
| 9 |
+
// Image optimization
|
| 10 |
+
images: {
|
| 11 |
+
formats: ['image/webp', 'image/avif'],
|
| 12 |
+
minimumCacheTTL: 60,
|
| 13 |
+
dangerouslyAllowSVG: true,
|
| 14 |
+
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
|
| 15 |
+
},
|
| 16 |
+
|
| 17 |
+
// Experimental features for better performance
|
| 18 |
+
experimental: {
|
| 19 |
+
optimizeCss: true,
|
| 20 |
+
scrollRestoration: true,
|
| 21 |
+
},
|
| 22 |
+
|
| 23 |
+
// Headers for better caching and security
|
| 24 |
+
async headers() {
|
| 25 |
+
return [
|
| 26 |
+
{
|
| 27 |
+
source: '/(.*)',
|
| 28 |
+
headers: [
|
| 29 |
+
{
|
| 30 |
+
key: 'X-Frame-Options',
|
| 31 |
+
value: 'DENY',
|
| 32 |
+
},
|
| 33 |
+
{
|
| 34 |
+
key: 'X-Content-Type-Options',
|
| 35 |
+
value: 'nosniff',
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
key: 'Referrer-Policy',
|
| 39 |
+
value: 'origin-when-cross-origin',
|
| 40 |
+
},
|
| 41 |
+
],
|
| 42 |
+
},
|
| 43 |
+
{
|
| 44 |
+
source: '/(.*)\\.(ico|png|jpg|jpeg|gif|webp|svg|mp4|webm)',
|
| 45 |
+
headers: [
|
| 46 |
+
{
|
| 47 |
+
key: 'Cache-Control',
|
| 48 |
+
value: 'public, max-age=31536000, immutable',
|
| 49 |
+
},
|
| 50 |
+
],
|
| 51 |
+
},
|
| 52 |
+
];
|
| 53 |
+
},
|
| 54 |
+
|
| 55 |
+
// Bundle analyzer (optional - uncomment to analyze bundle size)
|
| 56 |
+
// webpack: (config, { isServer }) => {
|
| 57 |
+
// if (!isServer) {
|
| 58 |
+
// config.resolve.fallback = {
|
| 59 |
+
// ...config.resolve.fallback,
|
| 60 |
+
// fs: false,
|
| 61 |
+
// };
|
| 62 |
+
// }
|
| 63 |
+
// return config;
|
| 64 |
+
// },
|
| 65 |
};
|
| 66 |
|
| 67 |
export default nextConfig;
|
|
@@ -9,9 +9,12 @@
|
|
| 9 |
"lint": "next lint"
|
| 10 |
},
|
| 11 |
"dependencies": {
|
|
|
|
|
|
|
|
|
|
| 12 |
"react": "^19.0.0",
|
| 13 |
"react-dom": "^19.0.0",
|
| 14 |
-
"
|
| 15 |
},
|
| 16 |
"devDependencies": {
|
| 17 |
"postcss": "^8",
|
|
|
|
| 9 |
"lint": "next lint"
|
| 10 |
},
|
| 11 |
"dependencies": {
|
| 12 |
+
"critters": "^0.0.25",
|
| 13 |
+
"framer-motion": "^12.12.2",
|
| 14 |
+
"next": "15.1.8",
|
| 15 |
"react": "^19.0.0",
|
| 16 |
"react-dom": "^19.0.0",
|
| 17 |
+
"react-icons": "^5.5.0"
|
| 18 |
},
|
| 19 |
"devDependencies": {
|
| 20 |
"postcss": "^8",
|
|
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { motion } from 'framer-motion';
|
| 2 |
+
import { FiGithub, FiTwitter, FiMail, FiHeart } from 'react-icons/fi';
|
| 3 |
+
import { HiSparkles } from 'react-icons/hi';
|
| 4 |
+
import { useMemo, useCallback } from 'react';
|
| 5 |
+
|
| 6 |
+
export default function Footer() {
|
| 7 |
+
const currentYear = new Date().getFullYear();
|
| 8 |
+
|
| 9 |
+
// Memoized data for better performance
|
| 10 |
+
const socialLinks = useMemo(
|
| 11 |
+
() => [
|
| 12 |
+
{ icon: FiGithub, href: 'https://github.com/YoruAkio', label: 'GitHub' },
|
| 13 |
+
{
|
| 14 |
+
icon: FiTwitter,
|
| 15 |
+
href: 'https://twitter.com/YoruAkio',
|
| 16 |
+
label: 'Twitter',
|
| 17 |
+
},
|
| 18 |
+
{ icon: FiMail, href: 'mailto:hello@akio.lol', label: 'Email' },
|
| 19 |
+
],
|
| 20 |
+
[],
|
| 21 |
+
);
|
| 22 |
+
|
| 23 |
+
const quickLinks = useMemo(
|
| 24 |
+
() => [
|
| 25 |
+
{ label: 'Features', href: '#features' },
|
| 26 |
+
{ label: 'File Converters', href: '#converters' },
|
| 27 |
+
{ label: 'Social Media Downloader', href: '#social-media' },
|
| 28 |
+
{
|
| 29 |
+
label: 'Documentation',
|
| 30 |
+
// href: 'https://huggingface.co/spaces/YoruAkio/LumaKit',
|
| 31 |
+
href: '#hero',
|
| 32 |
+
},
|
| 33 |
+
],
|
| 34 |
+
[],
|
| 35 |
+
);
|
| 36 |
+
|
| 37 |
+
// Enhanced smooth scroll with easing function
|
| 38 |
+
const easeInOutCubic = t => {
|
| 39 |
+
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
|
| 40 |
+
};
|
| 41 |
+
|
| 42 |
+
const smoothScrollTo = useCallback((targetPosition, duration = 1200) => {
|
| 43 |
+
const startPosition = window.pageYOffset;
|
| 44 |
+
const distance = targetPosition - startPosition;
|
| 45 |
+
let startTime = null;
|
| 46 |
+
|
| 47 |
+
const animation = currentTime => {
|
| 48 |
+
if (startTime === null) startTime = currentTime;
|
| 49 |
+
const timeElapsed = currentTime - startTime;
|
| 50 |
+
const progress = Math.min(timeElapsed / duration, 1);
|
| 51 |
+
const ease = easeInOutCubic(progress);
|
| 52 |
+
|
| 53 |
+
window.scrollTo(0, startPosition + distance * ease);
|
| 54 |
+
|
| 55 |
+
if (timeElapsed < duration) {
|
| 56 |
+
requestAnimationFrame(animation);
|
| 57 |
+
}
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
requestAnimationFrame(animation);
|
| 61 |
+
}, []);
|
| 62 |
+
|
| 63 |
+
// Smooth scroll handler with improved offset calculation and animation
|
| 64 |
+
const handleSmoothScroll = useCallback(
|
| 65 |
+
href => {
|
| 66 |
+
if (href.startsWith('#')) {
|
| 67 |
+
const element = document.querySelector(href);
|
| 68 |
+
if (element) {
|
| 69 |
+
const offset = 80; // Account for fixed navbar height
|
| 70 |
+
const elementPosition = element.getBoundingClientRect().top;
|
| 71 |
+
const offsetPosition = elementPosition + window.pageYOffset - offset;
|
| 72 |
+
|
| 73 |
+
smoothScrollTo(offsetPosition, 1200); // 1.2 second duration
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
},
|
| 77 |
+
[smoothScrollTo],
|
| 78 |
+
);
|
| 79 |
+
|
| 80 |
+
return (
|
| 81 |
+
<footer className="relative bg-[var(--background-secondary)] border-t border-[var(--border)]">
|
| 82 |
+
{/* Background decorative elements */}
|
| 83 |
+
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
| 84 |
+
<div className="absolute -top-20 -right-20 w-40 h-40 sm:w-60 sm:h-60 lg:w-80 lg:h-80 bg-[var(--accent)]/5 rounded-full blur-3xl"></div>
|
| 85 |
+
<div className="absolute -bottom-20 -left-20 w-40 h-40 sm:w-60 sm:h-60 lg:w-80 lg:h-80 bg-[var(--accent)]/5 rounded-full blur-3xl"></div>
|
| 86 |
+
</div>
|
| 87 |
+
|
| 88 |
+
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 sm:py-12">
|
| 89 |
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 sm:gap-8">
|
| 90 |
+
{/* Brand Section */}
|
| 91 |
+
<div className="space-y-4">
|
| 92 |
+
<motion.div
|
| 93 |
+
className="flex items-center space-x-2"
|
| 94 |
+
initial={{ opacity: 0, y: 20 }}
|
| 95 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 96 |
+
viewport={{ once: true, margin: '-50px' }}
|
| 97 |
+
transition={{ duration: 0.6 }}
|
| 98 |
+
>
|
| 99 |
+
<div className="relative">
|
| 100 |
+
<HiSparkles className="text-xl sm:text-2xl text-[var(--accent)]" />
|
| 101 |
+
<div className="absolute inset-0 bg-[var(--accent)] blur-lg opacity-20"></div>
|
| 102 |
+
</div>
|
| 103 |
+
<span className="text-lg sm:text-xl font-bold gradient-text">
|
| 104 |
+
LumaKit
|
| 105 |
+
</span>
|
| 106 |
+
</motion.div>
|
| 107 |
+
<motion.p
|
| 108 |
+
className="text-[var(--foreground-secondary)] text-sm leading-relaxed max-w-sm"
|
| 109 |
+
initial={{ opacity: 0, y: 20 }}
|
| 110 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 111 |
+
viewport={{ once: true, margin: '-50px' }}
|
| 112 |
+
transition={{ duration: 0.6, delay: 0.1 }}
|
| 113 |
+
>
|
| 114 |
+
A versatile suite of tools for social media downloading, file
|
| 115 |
+
conversion, and AI-powered code transformation. Streamline your
|
| 116 |
+
workflow with our modern, intuitive platform.
|
| 117 |
+
</motion.p>
|
| 118 |
+
</div>
|
| 119 |
+
|
| 120 |
+
{/* Quick Links */}
|
| 121 |
+
<div className="space-y-4">
|
| 122 |
+
<motion.h3
|
| 123 |
+
className="text-[var(--foreground)] font-semibold text-base sm:text-lg"
|
| 124 |
+
initial={{ opacity: 0, y: 20 }}
|
| 125 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 126 |
+
viewport={{ once: true, margin: '-50px' }}
|
| 127 |
+
transition={{ duration: 0.6, delay: 0.2 }}
|
| 128 |
+
>
|
| 129 |
+
Quick Links
|
| 130 |
+
</motion.h3>
|
| 131 |
+
<motion.div
|
| 132 |
+
className="space-y-2"
|
| 133 |
+
initial={{ opacity: 0, y: 20 }}
|
| 134 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 135 |
+
viewport={{ once: true, margin: '-50px' }}
|
| 136 |
+
transition={{ duration: 0.6, delay: 0.3 }}
|
| 137 |
+
>
|
| 138 |
+
{quickLinks.map((link, index) => (
|
| 139 |
+
<motion.button
|
| 140 |
+
key={index}
|
| 141 |
+
onClick={() =>
|
| 142 |
+
link.href.startsWith('#')
|
| 143 |
+
? handleSmoothScroll(link.href)
|
| 144 |
+
: window.open(link.href, '_blank')
|
| 145 |
+
}
|
| 146 |
+
className="block text-[var(--foreground-muted)] hover:text-[var(--accent)] transition-colors duration-300 text-sm text-left"
|
| 147 |
+
whileHover={{ x: 4 }}
|
| 148 |
+
transition={{ duration: 0.2 }}
|
| 149 |
+
>
|
| 150 |
+
{link.label}
|
| 151 |
+
</motion.button>
|
| 152 |
+
))}
|
| 153 |
+
</motion.div>
|
| 154 |
+
</div>
|
| 155 |
+
|
| 156 |
+
{/* Contact & Social */}
|
| 157 |
+
<div className="space-y-4">
|
| 158 |
+
<motion.h3
|
| 159 |
+
className="text-[var(--foreground)] font-semibold text-base sm:text-lg"
|
| 160 |
+
initial={{ opacity: 0, y: 20 }}
|
| 161 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 162 |
+
viewport={{ once: true, margin: '-50px' }}
|
| 163 |
+
transition={{ duration: 0.6, delay: 0.4 }}
|
| 164 |
+
>
|
| 165 |
+
Connect
|
| 166 |
+
</motion.h3>
|
| 167 |
+
<motion.div
|
| 168 |
+
className="flex space-x-4"
|
| 169 |
+
initial={{ opacity: 0, y: 20 }}
|
| 170 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 171 |
+
viewport={{ once: true, margin: '-50px' }}
|
| 172 |
+
transition={{ duration: 0.6, delay: 0.5 }}
|
| 173 |
+
>
|
| 174 |
+
{socialLinks.map((social, index) => (
|
| 175 |
+
<motion.a
|
| 176 |
+
key={index}
|
| 177 |
+
href={social.href}
|
| 178 |
+
target="_blank"
|
| 179 |
+
rel="noopener noreferrer"
|
| 180 |
+
className="text-[var(--foreground-muted)] hover:text-[var(--accent)] transition-colors duration-300 p-2 rounded-lg hover:bg-[var(--background-tertiary)]"
|
| 181 |
+
whileHover={{ scale: 1.1, y: -2 }}
|
| 182 |
+
whileTap={{ scale: 0.95 }}
|
| 183 |
+
aria-label={social.label}
|
| 184 |
+
>
|
| 185 |
+
<social.icon size={18} />
|
| 186 |
+
</motion.a>
|
| 187 |
+
))}
|
| 188 |
+
</motion.div>
|
| 189 |
+
{/* <motion.p
|
| 190 |
+
className="text-[var(--foreground-muted)] text-xs leading-relaxed"
|
| 191 |
+
initial={{ opacity: 0, y: 20 }}
|
| 192 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 193 |
+
viewport={{ once: true, margin: '-50px' }}
|
| 194 |
+
transition={{ duration: 0.6, delay: 0.6 }}
|
| 195 |
+
>
|
| 196 |
+
Visit our{' '}
|
| 197 |
+
<a
|
| 198 |
+
href="https://huggingface.co/spaces/YoruAkio/LumaKit"
|
| 199 |
+
target="_blank"
|
| 200 |
+
rel="noopener noreferrer"
|
| 201 |
+
className="text-[var(--accent)] hover:text-[var(--accent-hover)] transition-colors duration-300 underline decoration-1 underline-offset-2"
|
| 202 |
+
>
|
| 203 |
+
Hugging Face Space
|
| 204 |
+
</a>{' '}
|
| 205 |
+
to try LumaKit now.
|
| 206 |
+
</motion.p> */}
|
| 207 |
+
</div>
|
| 208 |
+
</div>
|
| 209 |
+
|
| 210 |
+
{/* Bottom Section */}
|
| 211 |
+
<motion.div
|
| 212 |
+
className="mt-8 sm:mt-12 pt-6 sm:pt-8 border-t border-[var(--border)] flex flex-col sm:flex-row items-center justify-between space-y-4 sm:space-y-0"
|
| 213 |
+
initial={{ opacity: 0, y: 20 }}
|
| 214 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 215 |
+
viewport={{ once: true, margin: '-50px' }}
|
| 216 |
+
transition={{ duration: 0.6, delay: 0.7 }}
|
| 217 |
+
>
|
| 218 |
+
<p className="text-[var(--foreground-muted)] text-xs sm:text-sm flex items-center space-x-1">
|
| 219 |
+
<span>© {currentYear} LumaKit. Made with</span>
|
| 220 |
+
<FiHeart className="text-red-400 text-xs animate-pulse" />
|
| 221 |
+
<span>by the community</span>
|
| 222 |
+
</p>
|
| 223 |
+
<p className="text-[var(--foreground-muted)] text-xs sm:text-sm">
|
| 224 |
+
Powered by AI • Built for Creators
|
| 225 |
+
</p>
|
| 226 |
+
</motion.div>
|
| 227 |
+
</div>
|
| 228 |
+
</footer>
|
| 229 |
+
);
|
| 230 |
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { useState, useEffect, useCallback, useMemo } from 'react';
|
| 2 |
+
import { motion, AnimatePresence } from 'framer-motion';
|
| 3 |
+
import { FiMenu, FiX, FiExternalLink, FiArrowUpRight } from 'react-icons/fi';
|
| 4 |
+
import { HiSparkles } from 'react-icons/hi';
|
| 5 |
+
|
| 6 |
+
export default function Navbar() {
|
| 7 |
+
const [isOpen, setIsOpen] = useState(false);
|
| 8 |
+
const [scrolled, setScrolled] = useState(false);
|
| 9 |
+
|
| 10 |
+
// Memoized menu items for better performance
|
| 11 |
+
const menuItems = useMemo(
|
| 12 |
+
() => [
|
| 13 |
+
{ label: 'Features', href: '#features' },
|
| 14 |
+
{ label: 'Converters', href: '#converters' },
|
| 15 |
+
{ label: 'Social Media', href: '#social-media' },
|
| 16 |
+
{ label: 'About', href: '#about' },
|
| 17 |
+
],
|
| 18 |
+
[],
|
| 19 |
+
);
|
| 20 |
+
|
| 21 |
+
// Optimized scroll handler with throttling
|
| 22 |
+
const handleScroll = useCallback(() => {
|
| 23 |
+
const scrollTop = window.scrollY;
|
| 24 |
+
setScrolled(scrollTop > 20);
|
| 25 |
+
}, []);
|
| 26 |
+
|
| 27 |
+
useEffect(() => {
|
| 28 |
+
let ticking = false;
|
| 29 |
+
|
| 30 |
+
const throttledScroll = () => {
|
| 31 |
+
if (!ticking) {
|
| 32 |
+
requestAnimationFrame(() => {
|
| 33 |
+
handleScroll();
|
| 34 |
+
ticking = false;
|
| 35 |
+
});
|
| 36 |
+
ticking = true;
|
| 37 |
+
}
|
| 38 |
+
};
|
| 39 |
+
|
| 40 |
+
window.addEventListener('scroll', throttledScroll, { passive: true });
|
| 41 |
+
return () => window.removeEventListener('scroll', throttledScroll);
|
| 42 |
+
}, [handleScroll]);
|
| 43 |
+
|
| 44 |
+
// Close mobile menu when clicking outside
|
| 45 |
+
useEffect(() => {
|
| 46 |
+
const handleClickOutside = event => {
|
| 47 |
+
if (isOpen && !event.target.closest('nav')) {
|
| 48 |
+
setIsOpen(false);
|
| 49 |
+
}
|
| 50 |
+
};
|
| 51 |
+
|
| 52 |
+
document.addEventListener('click', handleClickOutside);
|
| 53 |
+
return () => document.removeEventListener('click', handleClickOutside);
|
| 54 |
+
}, [isOpen]);
|
| 55 |
+
|
| 56 |
+
// Enhanced smooth scroll with easing function
|
| 57 |
+
const easeInOutCubic = (t) => {
|
| 58 |
+
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
|
| 59 |
+
};
|
| 60 |
+
|
| 61 |
+
const smoothScrollTo = useCallback((targetPosition, duration = 1200) => {
|
| 62 |
+
const startPosition = window.pageYOffset;
|
| 63 |
+
const distance = targetPosition - startPosition;
|
| 64 |
+
let startTime = null;
|
| 65 |
+
|
| 66 |
+
const animation = (currentTime) => {
|
| 67 |
+
if (startTime === null) startTime = currentTime;
|
| 68 |
+
const timeElapsed = currentTime - startTime;
|
| 69 |
+
const progress = Math.min(timeElapsed / duration, 1);
|
| 70 |
+
const ease = easeInOutCubic(progress);
|
| 71 |
+
|
| 72 |
+
window.scrollTo(0, startPosition + distance * ease);
|
| 73 |
+
|
| 74 |
+
if (timeElapsed < duration) {
|
| 75 |
+
requestAnimationFrame(animation);
|
| 76 |
+
}
|
| 77 |
+
};
|
| 78 |
+
|
| 79 |
+
requestAnimationFrame(animation);
|
| 80 |
+
}, []);
|
| 81 |
+
|
| 82 |
+
// Smooth scroll handler with improved offset calculation and animation
|
| 83 |
+
const handleSmoothScroll = useCallback(
|
| 84 |
+
href => {
|
| 85 |
+
if (href.startsWith('#')) {
|
| 86 |
+
const element = document.querySelector(href);
|
| 87 |
+
if (element) {
|
| 88 |
+
const offset = 80; // Account for fixed navbar height
|
| 89 |
+
const elementPosition = element.getBoundingClientRect().top;
|
| 90 |
+
const offsetPosition = elementPosition + window.pageYOffset - offset;
|
| 91 |
+
|
| 92 |
+
smoothScrollTo(offsetPosition, 1200); // 1.2 second duration
|
| 93 |
+
setIsOpen(false);
|
| 94 |
+
}
|
| 95 |
+
}
|
| 96 |
+
},
|
| 97 |
+
[smoothScrollTo, setIsOpen],
|
| 98 |
+
);
|
| 99 |
+
|
| 100 |
+
// Enhanced scroll to top with animation
|
| 101 |
+
const scrollToTop = useCallback(() => {
|
| 102 |
+
smoothScrollTo(0, 1000); // 1 second duration for scroll to top
|
| 103 |
+
}, [smoothScrollTo]);
|
| 104 |
+
|
| 105 |
+
return (
|
| 106 |
+
<motion.nav
|
| 107 |
+
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-500 ease-out ${
|
| 108 |
+
scrolled
|
| 109 |
+
? 'bg-[var(--background-secondary)]/95 backdrop-blur-xl border-b border-[var(--border)] shadow-lg'
|
| 110 |
+
: 'bg-transparent'
|
| 111 |
+
}`}
|
| 112 |
+
initial={{ y: -100, opacity: 0 }}
|
| 113 |
+
animate={{ y: 0, opacity: 1 }}
|
| 114 |
+
transition={{ duration: 0.8, ease: [0.16, 1, 0.3, 1] }}
|
| 115 |
+
>
|
| 116 |
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
| 117 |
+
<div className="flex items-center justify-between h-14 sm:h-16">
|
| 118 |
+
{/* Logo */}
|
| 119 |
+
<motion.div
|
| 120 |
+
className="flex items-center space-x-2 cursor-pointer group"
|
| 121 |
+
whileHover={{ scale: 1.02 }}
|
| 122 |
+
whileTap={{ scale: 0.98 }}
|
| 123 |
+
transition={{ duration: 0.2 }}
|
| 124 |
+
onClick={scrollToTop}
|
| 125 |
+
>
|
| 126 |
+
<div className="relative">
|
| 127 |
+
<HiSparkles className="text-xl sm:text-2xl text-[var(--accent)] group-hover:text-[var(--accent-hover)] transition-colors duration-300" />
|
| 128 |
+
<div className="absolute inset-0 bg-[var(--accent)] blur-lg opacity-20 group-hover:opacity-30 transition-opacity duration-300"></div>
|
| 129 |
+
</div>
|
| 130 |
+
<span className="text-lg sm:text-xl font-bold gradient-text">
|
| 131 |
+
LumaKit
|
| 132 |
+
</span>
|
| 133 |
+
</motion.div>
|
| 134 |
+
|
| 135 |
+
{/* Desktop Menu */}
|
| 136 |
+
<div className="hidden md:flex items-center space-x-6 lg:space-x-8">
|
| 137 |
+
{menuItems.map((item, index) => (
|
| 138 |
+
<motion.button
|
| 139 |
+
key={index}
|
| 140 |
+
onClick={() => handleSmoothScroll(item.href)}
|
| 141 |
+
className="text-[var(--foreground-secondary)] hover:text-[var(--foreground)] transition-colors duration-300 text-sm font-medium relative group"
|
| 142 |
+
whileHover={{ y: -1 }}
|
| 143 |
+
transition={{ duration: 0.2 }}
|
| 144 |
+
>
|
| 145 |
+
{item.label}
|
| 146 |
+
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[var(--accent)] group-hover:w-full transition-all duration-300"></span>
|
| 147 |
+
</motion.button>
|
| 148 |
+
))}
|
| 149 |
+
<motion.a
|
| 150 |
+
onClick={() => handleSmoothScroll("#features")}
|
| 151 |
+
rel="noopener noreferrer"
|
| 152 |
+
className="group relative flex items-center space-x-2 bg-[var(--accent)] hover:bg-[var(--accent-hover)] text-[var(--background)] px-4 py-2 rounded-xl transition-all duration-300 text-sm font-medium shadow-lg hover:shadow-xl overflow-hidden"
|
| 153 |
+
whileHover={{ scale: 1.02, y: -1 }}
|
| 154 |
+
whileTap={{ scale: 0.98 }}
|
| 155 |
+
transition={{ duration: 0.2 }}
|
| 156 |
+
>
|
| 157 |
+
<div className="absolute inset-0 bg-gradient-to-r from-[var(--accent)] to-[var(--accent-hover)] opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
| 158 |
+
<FiExternalLink className="text-sm relative z-10" />
|
| 159 |
+
<span className="relative z-10">Try LumaKit</span>
|
| 160 |
+
</motion.a>
|
| 161 |
+
</div>
|
| 162 |
+
|
| 163 |
+
{/* Mobile Menu Button */}
|
| 164 |
+
<motion.button
|
| 165 |
+
className="md:hidden text-[var(--foreground-secondary)] hover:text-[var(--foreground)] transition-colors duration-300 p-2 rounded-lg hover:bg-[var(--background-secondary)]"
|
| 166 |
+
onClick={() => setIsOpen(!isOpen)}
|
| 167 |
+
whileTap={{ scale: 0.95 }}
|
| 168 |
+
aria-label="Toggle menu"
|
| 169 |
+
>
|
| 170 |
+
<motion.div
|
| 171 |
+
animate={isOpen ? 'open' : 'closed'}
|
| 172 |
+
variants={{
|
| 173 |
+
open: { rotate: 180 },
|
| 174 |
+
closed: { rotate: 0 },
|
| 175 |
+
}}
|
| 176 |
+
transition={{ duration: 0.3 }}
|
| 177 |
+
>
|
| 178 |
+
{isOpen ? <FiX size={20} /> : <FiMenu size={20} />}
|
| 179 |
+
</motion.div>
|
| 180 |
+
</motion.button>
|
| 181 |
+
</div>
|
| 182 |
+
|
| 183 |
+
{/* Mobile Menu */}
|
| 184 |
+
<AnimatePresence mode="wait">
|
| 185 |
+
{isOpen && (
|
| 186 |
+
<motion.div
|
| 187 |
+
className="md:hidden absolute top-full left-0 right-0 bg-[var(--background-secondary)]/98 backdrop-blur-xl border-b border-[var(--border)] shadow-2xl"
|
| 188 |
+
initial={{ opacity: 0, height: 0, y: -10 }}
|
| 189 |
+
animate={{ opacity: 1, height: 'auto', y: 0 }}
|
| 190 |
+
exit={{ opacity: 0, height: 0, y: -10 }}
|
| 191 |
+
transition={{ duration: 0.4, ease: [0.16, 1, 0.3, 1] }}
|
| 192 |
+
>
|
| 193 |
+
<div className="px-4 py-6 space-y-4">
|
| 194 |
+
{menuItems.map((item, index) => (
|
| 195 |
+
<motion.button
|
| 196 |
+
key={index}
|
| 197 |
+
onClick={() => handleSmoothScroll(item.href)}
|
| 198 |
+
className="block w-full text-left text-[var(--foreground-secondary)] hover:text-[var(--foreground)] transition-colors duration-300 text-base font-medium py-2 px-3 rounded-lg hover:bg-[var(--background-tertiary)]"
|
| 199 |
+
initial={{ opacity: 0, x: -20 }}
|
| 200 |
+
animate={{ opacity: 1, x: 0 }}
|
| 201 |
+
transition={{ delay: index * 0.1, duration: 0.3 }}
|
| 202 |
+
>
|
| 203 |
+
{item.label}
|
| 204 |
+
</motion.button>
|
| 205 |
+
))}
|
| 206 |
+
<motion.a
|
| 207 |
+
href="https://huggingface.co/spaces/YoruAkio/LumaKit"
|
| 208 |
+
target="_blank"
|
| 209 |
+
rel="noopener noreferrer"
|
| 210 |
+
className="group relative flex items-center space-x-2 bg-[var(--accent)] hover:bg-[var(--accent-hover)] text-[var(--background)] px-4 py-3 rounded-xl transition-all duration-300 text-base font-medium w-fit shadow-lg overflow-hidden"
|
| 211 |
+
onClick={() => setIsOpen(false)}
|
| 212 |
+
initial={{ opacity: 0, x: -20 }}
|
| 213 |
+
animate={{ opacity: 1, x: 0 }}
|
| 214 |
+
transition={{ delay: 0.4, duration: 0.3 }}
|
| 215 |
+
>
|
| 216 |
+
<div className="absolute inset-0 bg-gradient-to-r from-[var(--accent)] to-[var(--accent-hover)] opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
| 217 |
+
<FiExternalLink className="text-sm relative z-10" />
|
| 218 |
+
<span className="relative z-10">Try LumaKit</span>
|
| 219 |
+
<FiArrowUpRight className="text-sm group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-transform duration-200 relative z-10" />
|
| 220 |
+
</motion.a>
|
| 221 |
+
</div>
|
| 222 |
+
</motion.div>
|
| 223 |
+
)}
|
| 224 |
+
</AnimatePresence>
|
| 225 |
+
</div>
|
| 226 |
+
</motion.nav>
|
| 227 |
+
);
|
| 228 |
+
}
|
|
@@ -1,15 +1,23 @@
|
|
| 1 |
-
import '
|
| 2 |
-
import
|
|
|
|
| 3 |
|
| 4 |
-
const bricolageGrotesque =
|
| 5 |
-
variable: '--font-bricolage-grotesque',
|
| 6 |
subsets: ['latin'],
|
|
|
|
| 7 |
});
|
| 8 |
|
| 9 |
export default function App({ Component, pageProps }) {
|
| 10 |
return (
|
| 11 |
-
|
| 12 |
-
<
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
);
|
| 15 |
-
}
|
|
|
|
| 1 |
+
import { Inter } from 'next/font/google';
|
| 2 |
+
import Head from 'next/head';
|
| 3 |
+
import '../styles/globals.css';
|
| 4 |
|
| 5 |
+
const bricolageGrotesque = Inter({
|
|
|
|
| 6 |
subsets: ['latin'],
|
| 7 |
+
variable: '--font-bricolage',
|
| 8 |
});
|
| 9 |
|
| 10 |
export default function App({ Component, pageProps }) {
|
| 11 |
return (
|
| 12 |
+
<>
|
| 13 |
+
<Head>
|
| 14 |
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
| 15 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="true" />
|
| 16 |
+
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200..800&display=swap" rel="stylesheet" />
|
| 17 |
+
</Head>
|
| 18 |
+
<div className={bricolageGrotesque.variable} style={{ fontFamily: 'Bricolage Grotesque, sans-serif' }}>
|
| 19 |
+
<Component {...pageProps} />
|
| 20 |
+
</div>
|
| 21 |
+
</>
|
| 22 |
);
|
| 23 |
+
}
|
|
@@ -1,101 +1,639 @@
|
|
| 1 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
export default function Home() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
return (
|
| 5 |
-
<div className="
|
| 6 |
-
<
|
| 7 |
-
<
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
width={180}
|
| 12 |
-
height={38}
|
| 13 |
-
priority
|
| 14 |
/>
|
| 15 |
-
<
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
>
|
| 33 |
-
<
|
| 34 |
-
className="
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
<
|
| 43 |
-
className="
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
|
|
|
| 47 |
>
|
| 48 |
-
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
</div>
|
| 51 |
-
</
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
</div>
|
| 100 |
);
|
| 101 |
}
|
|
|
|
| 1 |
+
import Head from 'next/head';
|
| 2 |
+
import { motion, useScroll, useTransform } from 'framer-motion';
|
| 3 |
+
import { useState, useRef, useMemo, useCallback } from 'react';
|
| 4 |
+
import {
|
| 5 |
+
FiDownload,
|
| 6 |
+
FiRefreshCw,
|
| 7 |
+
FiZap,
|
| 8 |
+
FiStar,
|
| 9 |
+
FiArrowRight,
|
| 10 |
+
FiPlay,
|
| 11 |
+
FiGift,
|
| 12 |
+
FiExternalLink,
|
| 13 |
+
FiArrowUpRight,
|
| 14 |
+
} from 'react-icons/fi';
|
| 15 |
+
import {
|
| 16 |
+
HiSparkles,
|
| 17 |
+
HiLightningBolt,
|
| 18 |
+
HiPhotograph,
|
| 19 |
+
HiVideoCamera,
|
| 20 |
+
HiCode,
|
| 21 |
+
HiChip,
|
| 22 |
+
} from 'react-icons/hi';
|
| 23 |
+
import { SiYoutube, SiInstagram } from 'react-icons/si';
|
| 24 |
+
import { FaSquareXTwitter } from 'react-icons/fa6';
|
| 25 |
+
import Navbar from '../components/Navbar';
|
| 26 |
+
import Footer from '../components/Footer';
|
| 27 |
|
| 28 |
export default function Home() {
|
| 29 |
+
const [activeConverter, setActiveConverter] = useState('image');
|
| 30 |
+
const heroRef = useRef(null);
|
| 31 |
+
|
| 32 |
+
const { scrollYProgress } = useScroll({
|
| 33 |
+
target: heroRef,
|
| 34 |
+
offset: ['start start', 'end start'],
|
| 35 |
+
});
|
| 36 |
+
|
| 37 |
+
const yBg = useTransform(scrollYProgress, [0, 1], ['0%', '30%']);
|
| 38 |
+
const opacity = useTransform(scrollYProgress, [0, 0.7], [1, 0]);
|
| 39 |
+
|
| 40 |
+
// Add smooth scroll handler
|
| 41 |
+
const handleSmoothScroll = useCallback(href => {
|
| 42 |
+
if (href.startsWith('#')) {
|
| 43 |
+
const element = document.querySelector(href);
|
| 44 |
+
if (element) {
|
| 45 |
+
const offset = 80; // Account for fixed navbar
|
| 46 |
+
const elementPosition = element.getBoundingClientRect().top;
|
| 47 |
+
const offsetPosition = elementPosition + window.pageYOffset - offset;
|
| 48 |
+
|
| 49 |
+
window.scrollTo({
|
| 50 |
+
top: offsetPosition,
|
| 51 |
+
behavior: 'smooth',
|
| 52 |
+
});
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
}, []);
|
| 56 |
+
|
| 57 |
+
// Memoized data for better performance
|
| 58 |
+
const features = useMemo(
|
| 59 |
+
() => [
|
| 60 |
+
{
|
| 61 |
+
icon: FiDownload,
|
| 62 |
+
title: 'Social Media Downloader',
|
| 63 |
+
description:
|
| 64 |
+
'Download content from YouTube, Twitter, and Instagram with ease',
|
| 65 |
+
iconColor: 'text-white',
|
| 66 |
+
status: 'Available',
|
| 67 |
+
},
|
| 68 |
+
{
|
| 69 |
+
icon: FiRefreshCw,
|
| 70 |
+
title: 'File Converter',
|
| 71 |
+
description: 'Convert images, videos, and files to any format you need',
|
| 72 |
+
iconColor: 'text-white',
|
| 73 |
+
status: 'Available',
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
icon: HiChip,
|
| 77 |
+
title: 'AI Code Transformer',
|
| 78 |
+
description:
|
| 79 |
+
'Transform code between programming languages using Gemini AI',
|
| 80 |
+
iconColor: 'text-white',
|
| 81 |
+
status: 'Coming Soon',
|
| 82 |
+
},
|
| 83 |
+
],
|
| 84 |
+
[],
|
| 85 |
+
);
|
| 86 |
+
|
| 87 |
+
const converters = useMemo(
|
| 88 |
+
() => [
|
| 89 |
+
{
|
| 90 |
+
id: 'image',
|
| 91 |
+
icon: HiPhotograph,
|
| 92 |
+
title: 'Image Converter',
|
| 93 |
+
description: 'Convert to WebP, JPG, PNG, ICO and more',
|
| 94 |
+
formats: ['WebP', 'JPG', 'PNG', 'ICO', 'SVG', 'BMP'],
|
| 95 |
+
},
|
| 96 |
+
{
|
| 97 |
+
id: 'video',
|
| 98 |
+
icon: HiVideoCamera,
|
| 99 |
+
title: 'Video Converter',
|
| 100 |
+
description: 'Convert videos to GIF or extract MP3 audio',
|
| 101 |
+
formats: ['GIF', 'MP3', 'MP4', 'WebM', 'AVI'],
|
| 102 |
+
},
|
| 103 |
+
{
|
| 104 |
+
id: 'code',
|
| 105 |
+
icon: HiCode,
|
| 106 |
+
title: 'Code Transformer',
|
| 107 |
+
description: 'AI-powered language conversion with Gemini',
|
| 108 |
+
formats: ['Python', 'JavaScript', 'TypeScript', 'Go', 'Rust'],
|
| 109 |
+
},
|
| 110 |
+
],
|
| 111 |
+
[],
|
| 112 |
+
);
|
| 113 |
+
|
| 114 |
+
const socialPlatforms = useMemo(
|
| 115 |
+
() => [
|
| 116 |
+
{
|
| 117 |
+
name: 'YouTube',
|
| 118 |
+
icon: SiYoutube,
|
| 119 |
+
color: 'text-[var(--accent)]',
|
| 120 |
+
status: 'Available',
|
| 121 |
+
description: 'Download videos and audio from YouTube',
|
| 122 |
+
},
|
| 123 |
+
{
|
| 124 |
+
name: 'Twitter',
|
| 125 |
+
icon: FaSquareXTwitter,
|
| 126 |
+
color: 'text-[var(--accent)]',
|
| 127 |
+
status: 'Coming Soon',
|
| 128 |
+
description: 'Save tweets, images, and videos',
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
name: 'Instagram',
|
| 132 |
+
icon: SiInstagram,
|
| 133 |
+
color: 'text-[var(--accent)]',
|
| 134 |
+
status: 'Coming Soon',
|
| 135 |
+
description: 'Download photos, stories, and reels',
|
| 136 |
+
},
|
| 137 |
+
],
|
| 138 |
+
[],
|
| 139 |
+
);
|
| 140 |
+
|
| 141 |
+
const stats = useMemo(
|
| 142 |
+
() => [
|
| 143 |
+
{ label: 'Downloads', value: '10K+' },
|
| 144 |
+
{ label: 'Formats', value: '50+' },
|
| 145 |
+
{ label: 'Users', value: '1K+' },
|
| 146 |
+
],
|
| 147 |
+
[],
|
| 148 |
+
);
|
| 149 |
+
|
| 150 |
+
const aboutFeatures = useMemo(
|
| 151 |
+
() => [
|
| 152 |
+
'Social media content downloading',
|
| 153 |
+
'Multi-format file conversion',
|
| 154 |
+
'AI-powered code transformation',
|
| 155 |
+
'User-friendly interface',
|
| 156 |
+
'Fast and reliable processing',
|
| 157 |
+
],
|
| 158 |
+
[],
|
| 159 |
+
);
|
| 160 |
+
|
| 161 |
+
// Animation variants
|
| 162 |
+
const containerVariants = {
|
| 163 |
+
hidden: { opacity: 0 },
|
| 164 |
+
visible: {
|
| 165 |
+
opacity: 1,
|
| 166 |
+
transition: {
|
| 167 |
+
staggerChildren: 0.1,
|
| 168 |
+
delayChildren: 0.2,
|
| 169 |
+
},
|
| 170 |
+
},
|
| 171 |
+
};
|
| 172 |
+
|
| 173 |
+
const itemVariants = {
|
| 174 |
+
hidden: { opacity: 0, y: 20 },
|
| 175 |
+
visible: {
|
| 176 |
+
opacity: 1,
|
| 177 |
+
y: 0,
|
| 178 |
+
transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] },
|
| 179 |
+
},
|
| 180 |
+
};
|
| 181 |
+
|
| 182 |
+
const handleConverterChange = useCallback(converterId => {
|
| 183 |
+
setActiveConverter(converterId);
|
| 184 |
+
}, []);
|
| 185 |
+
|
| 186 |
return (
|
| 187 |
+
<div className="min-h-screen bg-[var(--background)] text-[var(--foreground)]">
|
| 188 |
+
<Head>
|
| 189 |
+
<title>LumaKit - Powerful Media Tools & AI Transformations</title>
|
| 190 |
+
<meta
|
| 191 |
+
name="description"
|
| 192 |
+
content="LumaKit offers powerful tools for social media downloading, file conversion, and AI-powered transformations. Transform your digital workflow with our modern platform."
|
|
|
|
|
|
|
|
|
|
| 193 |
/>
|
| 194 |
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
| 195 |
+
<meta name="theme-color" content="#D4A574" />
|
| 196 |
+
<link rel="icon" href="/favicon.ico" />
|
| 197 |
+
</Head>
|
| 198 |
+
|
| 199 |
+
<Navbar />
|
| 200 |
+
|
| 201 |
+
{/* Hero Section */}
|
| 202 |
+
<section
|
| 203 |
+
ref={heroRef}
|
| 204 |
+
id="hero"
|
| 205 |
+
className="relative min-h-screen flex items-center justify-center overflow-hidden pt-16 sm:pt-0"
|
| 206 |
+
>
|
| 207 |
+
{/* Background Elements */}
|
| 208 |
+
<motion.div
|
| 209 |
+
className="absolute inset-0 opacity-20 pointer-events-none"
|
| 210 |
+
style={{ y: yBg, opacity }}
|
| 211 |
+
>
|
| 212 |
+
<div className="absolute top-1/4 left-1/4 w-32 h-32 sm:w-48 sm:h-48 lg:w-64 lg:h-64 bg-[var(--accent)]/20 rounded-full blur-3xl"></div>
|
| 213 |
+
<div className="absolute top-3/4 right-1/4 w-40 h-40 sm:w-60 sm:h-60 lg:w-80 lg:h-80 bg-[var(--accent)]/15 rounded-full blur-3xl"></div>
|
| 214 |
+
<div className="absolute bottom-1/4 left-1/2 w-48 h-48 sm:w-72 sm:h-72 lg:w-96 lg:h-96 bg-[var(--accent)]/10 rounded-full blur-3xl"></div>
|
| 215 |
+
</motion.div>
|
| 216 |
+
|
| 217 |
+
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
| 218 |
+
<motion.div
|
| 219 |
+
initial={{ opacity: 0, y: 30 }}
|
| 220 |
+
animate={{ opacity: 1, y: 0 }}
|
| 221 |
+
transition={{ duration: 1, ease: [0.16, 1, 0.3, 1] }}
|
| 222 |
+
className="space-y-6 sm:space-y-8"
|
| 223 |
+
>
|
| 224 |
+
{/* Main Title */}
|
| 225 |
+
<div className="space-y-4 sm:space-y-6">
|
| 226 |
+
<motion.div
|
| 227 |
+
className="flex items-center justify-center space-x-2 mb-4 sm:mb-6"
|
| 228 |
+
initial={{ opacity: 0, scale: 0.8 }}
|
| 229 |
+
animate={{ opacity: 1, scale: 1 }}
|
| 230 |
+
transition={{ duration: 0.8, delay: 0.2 }}
|
| 231 |
+
>
|
| 232 |
+
<div className="relative">
|
| 233 |
+
<HiSparkles className="text-3xl sm:text-4xl text-[var(--accent)]" />
|
| 234 |
+
<div className="absolute inset-0 bg-[var(--accent)] blur-lg opacity-30"></div>
|
| 235 |
+
</div>
|
| 236 |
+
</motion.div>
|
| 237 |
+
|
| 238 |
+
<motion.h1
|
| 239 |
+
className="text-4xl sm:text-6xl lg:text-7xl font-bold leading-tight"
|
| 240 |
+
initial={{ opacity: 0, y: 20 }}
|
| 241 |
+
animate={{ opacity: 1, y: 0 }}
|
| 242 |
+
transition={{ duration: 0.8, delay: 0.3 }}
|
| 243 |
+
>
|
| 244 |
+
<span className="gradient-text">LumaKit</span>
|
| 245 |
+
</motion.h1>
|
| 246 |
+
|
| 247 |
+
<motion.p
|
| 248 |
+
className="text-lg sm:text-xl lg:text-2xl text-[var(--foreground-secondary)] max-w-4xl mx-auto leading-relaxed px-4"
|
| 249 |
+
initial={{ opacity: 0, y: 20 }}
|
| 250 |
+
animate={{ opacity: 1, y: 0 }}
|
| 251 |
+
transition={{ duration: 0.8, delay: 0.4 }}
|
| 252 |
+
>
|
| 253 |
+
A versatile suite of tools for{' '}
|
| 254 |
+
<span className="text-[var(--accent)] font-semibold">
|
| 255 |
+
social media downloading
|
| 256 |
+
</span>
|
| 257 |
+
,{' '}
|
| 258 |
+
<span className="text-[var(--accent)] font-semibold">
|
| 259 |
+
file conversion
|
| 260 |
+
</span>
|
| 261 |
+
, and{' '}
|
| 262 |
+
<span className="text-[var(--accent)] font-semibold">
|
| 263 |
+
AI-powered transformations
|
| 264 |
+
</span>
|
| 265 |
+
</motion.p>
|
| 266 |
+
</div>
|
| 267 |
+
|
| 268 |
+
{/* CTA Button */}
|
| 269 |
+
<motion.div
|
| 270 |
+
className="flex items-center justify-center"
|
| 271 |
+
initial={{ opacity: 0, y: 20 }}
|
| 272 |
+
animate={{ opacity: 1, y: 0 }}
|
| 273 |
+
transition={{ duration: 0.8, delay: 0.6 }}
|
| 274 |
+
>
|
| 275 |
+
<motion.a
|
| 276 |
+
href="https://huggingface.co/spaces/YoruAkio/LumaKit"
|
| 277 |
+
target="_blank"
|
| 278 |
+
rel="noopener noreferrer"
|
| 279 |
+
className="group relative flex items-center space-x-2 bg-[var(--accent)] hover:bg-[var(--accent-hover)] text-[var(--background)] px-6 sm:px-8 py-3 sm:py-4 rounded-xl font-semibold text-base sm:text-lg transition-all duration-300 shadow-lg hover:shadow-2xl overflow-hidden"
|
| 280 |
+
whileHover={{ scale: 1.05, y: -2 }}
|
| 281 |
+
whileTap={{ scale: 0.98 }}
|
| 282 |
+
>
|
| 283 |
+
<div className="absolute inset-0 bg-gradient-to-r from-[var(--accent)] to-[var(--accent-hover)] opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
| 284 |
+
<FiExternalLink className="text-lg sm:text-xl relative z-10" />
|
| 285 |
+
<span className="relative z-10">Try LumaKit Now</span>
|
| 286 |
+
<FiArrowUpRight className="text-base sm:text-lg group-hover:translate-x-1 group-hover:-translate-y-1 transition-transform duration-200 relative z-10" />
|
| 287 |
+
</motion.a>
|
| 288 |
+
</motion.div>
|
| 289 |
+
|
| 290 |
+
{/* Stats */}
|
| 291 |
+
<motion.div
|
| 292 |
+
className="grid grid-cols-3 gap-4 sm:gap-8 max-w-md sm:max-w-lg mx-auto mt-12 sm:mt-16"
|
| 293 |
+
initial={{ opacity: 0, y: 20 }}
|
| 294 |
+
animate={{ opacity: 1, y: 0 }}
|
| 295 |
+
transition={{ duration: 0.8, delay: 0.8 }}
|
| 296 |
+
>
|
| 297 |
+
{stats.map((stat, index) => (
|
| 298 |
+
<motion.div
|
| 299 |
+
key={index}
|
| 300 |
+
className="text-center"
|
| 301 |
+
whileHover={{ scale: 1.05 }}
|
| 302 |
+
transition={{ duration: 0.2 }}
|
| 303 |
+
>
|
| 304 |
+
<div className="text-xl sm:text-2xl lg:text-3xl font-bold text-[var(--accent)]">
|
| 305 |
+
{stat.value}
|
| 306 |
+
</div>
|
| 307 |
+
<div className="text-xs sm:text-sm text-[var(--foreground-muted)]">
|
| 308 |
+
{stat.label}
|
| 309 |
+
</div>
|
| 310 |
+
</motion.div>
|
| 311 |
+
))}
|
| 312 |
+
</motion.div>
|
| 313 |
+
</motion.div>
|
| 314 |
+
</div>
|
| 315 |
+
</section>
|
| 316 |
+
|
| 317 |
+
{/* Features Section */}
|
| 318 |
+
<section
|
| 319 |
+
id="features"
|
| 320 |
+
className="py-16 sm:py-20 lg:py-24 bg-[var(--background-secondary)]"
|
| 321 |
+
>
|
| 322 |
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
| 323 |
+
<motion.div
|
| 324 |
+
className="text-center mb-12 sm:mb-16"
|
| 325 |
+
initial={{ opacity: 0, y: 30 }}
|
| 326 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 327 |
+
viewport={{ once: true, margin: '-100px' }}
|
| 328 |
+
transition={{ duration: 0.8 }}
|
| 329 |
>
|
| 330 |
+
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-bold mb-4 sm:mb-6">
|
| 331 |
+
<span className="gradient-text">Powerful Features</span>
|
| 332 |
+
</h2>
|
| 333 |
+
<p className="text-lg sm:text-xl text-[var(--foreground-secondary)] max-w-3xl mx-auto px-4">
|
| 334 |
+
Everything you need to download, convert, and transform your
|
| 335 |
+
digital content
|
| 336 |
+
</p>
|
| 337 |
+
</motion.div>
|
| 338 |
+
|
| 339 |
+
<motion.div
|
| 340 |
+
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8"
|
| 341 |
+
variants={containerVariants}
|
| 342 |
+
initial="hidden"
|
| 343 |
+
whileInView="visible"
|
| 344 |
+
viewport={{ once: true, margin: '-100px' }}
|
| 345 |
>
|
| 346 |
+
{features.map((feature, index) => (
|
| 347 |
+
<motion.div
|
| 348 |
+
key={index}
|
| 349 |
+
className="group relative glass rounded-2xl p-6 sm:p-8 hover:bg-[var(--background-tertiary)]/50 transition-all duration-300 will-change-transform flex flex-col h-full min-h-[320px]"
|
| 350 |
+
variants={itemVariants}
|
| 351 |
+
whileHover={{ y: -5, scale: 1.02 }}
|
| 352 |
+
transition={{ duration: 0.3 }}
|
| 353 |
+
>
|
| 354 |
+
{/* Icon */}
|
| 355 |
+
<div className="inline-flex p-3 sm:p-4 rounded-xl bg-[var(--accent)] mb-4 sm:mb-6 shadow-lg w-fit">
|
| 356 |
+
<feature.icon className="text-xl sm:text-2xl text-white" />
|
| 357 |
+
</div>
|
| 358 |
+
|
| 359 |
+
{/* Content */}
|
| 360 |
+
<div className="flex-1 flex flex-col">
|
| 361 |
+
<h3 className="text-lg sm:text-xl font-semibold text-[var(--foreground)] mb-3 sm:mb-4">
|
| 362 |
+
{feature.title}
|
| 363 |
+
</h3>
|
| 364 |
+
<p className="text-[var(--foreground-secondary)] mb-6 text-sm sm:text-base leading-relaxed flex-1">
|
| 365 |
+
{feature.description}
|
| 366 |
+
</p>
|
| 367 |
+
</div>
|
| 368 |
+
|
| 369 |
+
{/* Status and Arrow - Fixed at bottom */}
|
| 370 |
+
<div className="flex items-center justify-between mt-auto pt-4">
|
| 371 |
+
<span
|
| 372 |
+
className={`px-3 py-1 rounded-full text-xs font-medium ${
|
| 373 |
+
feature.status === 'Available'
|
| 374 |
+
? 'bg-green-500/20 text-green-400 font-semibold border border-green-500/30'
|
| 375 |
+
: 'bg-[var(--accent)] text-[var(--accent)]/20 border border-[var(--accent)]'
|
| 376 |
+
}`}
|
| 377 |
+
>
|
| 378 |
+
{feature.status}
|
| 379 |
+
</span>
|
| 380 |
+
<FiArrowRight className="text-[var(--accent)] group-hover:translate-x-1 transition-transform duration-200" />
|
| 381 |
+
</div>
|
| 382 |
+
</motion.div>
|
| 383 |
+
))}
|
| 384 |
+
</motion.div>
|
| 385 |
</div>
|
| 386 |
+
</section>
|
| 387 |
+
|
| 388 |
+
{/* Converters Section */}
|
| 389 |
+
<section id="converters" className="py-16 sm:py-20 lg:py-24">
|
| 390 |
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
| 391 |
+
<motion.div
|
| 392 |
+
className="text-center mb-12 sm:mb-16"
|
| 393 |
+
initial={{ opacity: 0, y: 30 }}
|
| 394 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 395 |
+
viewport={{ once: true, margin: '-100px' }}
|
| 396 |
+
transition={{ duration: 0.8 }}
|
| 397 |
+
>
|
| 398 |
+
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-bold mb-4 sm:mb-6">
|
| 399 |
+
<span className="gradient-text">File Converters</span>
|
| 400 |
+
</h2>
|
| 401 |
+
<p className="text-lg sm:text-xl text-[var(--foreground-secondary)] max-w-3xl mx-auto px-4">
|
| 402 |
+
Transform your files between different formats with ease
|
| 403 |
+
</p>
|
| 404 |
+
</motion.div>
|
| 405 |
+
|
| 406 |
+
{/* Converter Tabs */}
|
| 407 |
+
<div className="flex justify-center mb-8 sm:mb-12">
|
| 408 |
+
<div className="flex flex-wrap glass rounded-xl p-1 sm:p-2 gap-1 sm:gap-0">
|
| 409 |
+
{converters.map(converter => (
|
| 410 |
+
<button
|
| 411 |
+
key={converter.id}
|
| 412 |
+
onClick={() => handleConverterChange(converter.id)}
|
| 413 |
+
className={`flex items-center space-x-2 px-4 sm:px-6 py-2 sm:py-3 rounded-lg font-medium transition-all duration-200 text-sm sm:text-base ${
|
| 414 |
+
activeConverter === converter.id
|
| 415 |
+
? 'bg-[var(--accent)] text-[var(--background)]'
|
| 416 |
+
: 'text-[var(--foreground-secondary)] hover:text-[var(--foreground)]'
|
| 417 |
+
}`}
|
| 418 |
+
>
|
| 419 |
+
<converter.icon className="text-base sm:text-lg" />
|
| 420 |
+
<span className="hidden sm:inline">{converter.title}</span>
|
| 421 |
+
<span className="sm:hidden">
|
| 422 |
+
{converter.title.split(' ')[0]}
|
| 423 |
+
</span>
|
| 424 |
+
</button>
|
| 425 |
+
))}
|
| 426 |
+
</div>
|
| 427 |
+
</div>
|
| 428 |
+
|
| 429 |
+
{/* Active Converter Details */}
|
| 430 |
+
<motion.div
|
| 431 |
+
key={activeConverter}
|
| 432 |
+
className="glass rounded-2xl p-6 sm:p-8"
|
| 433 |
+
initial={{ opacity: 0, y: 20 }}
|
| 434 |
+
animate={{ opacity: 1, y: 0 }}
|
| 435 |
+
transition={{ duration: 0.4 }}
|
| 436 |
+
>
|
| 437 |
+
{converters.map(converter => {
|
| 438 |
+
if (converter.id !== activeConverter) return null;
|
| 439 |
+
return (
|
| 440 |
+
<div key={converter.id} className="text-center">
|
| 441 |
+
<converter.icon className="text-4xl sm:text-5xl text-[var(--accent)] mx-auto mb-4 sm:mb-6" />
|
| 442 |
+
<h3 className="text-xl sm:text-2xl font-bold text-[var(--foreground)] mb-3 sm:mb-4">
|
| 443 |
+
{converter.title}
|
| 444 |
+
</h3>
|
| 445 |
+
<p className="text-[var(--foreground-secondary)] mb-6 sm:mb-8 text-base sm:text-lg max-w-2xl mx-auto">
|
| 446 |
+
{converter.description}
|
| 447 |
+
</p>
|
| 448 |
+
<div className="flex flex-wrap justify-center gap-2 sm:gap-3">
|
| 449 |
+
{converter.formats.map((format, index) => (
|
| 450 |
+
<span
|
| 451 |
+
key={index}
|
| 452 |
+
className="px-3 sm:px-4 py-2 bg-[var(--background-tertiary)] border border-[var(--border)] rounded-lg text-[var(--foreground-secondary)] text-xs sm:text-sm font-medium"
|
| 453 |
+
>
|
| 454 |
+
{format}
|
| 455 |
+
</span>
|
| 456 |
+
))}
|
| 457 |
+
</div>
|
| 458 |
+
</div>
|
| 459 |
+
);
|
| 460 |
+
})}
|
| 461 |
+
</motion.div>
|
| 462 |
+
</div>
|
| 463 |
+
</section>
|
| 464 |
+
|
| 465 |
+
{/* Social Media Section */}
|
| 466 |
+
<section
|
| 467 |
+
id="social-media"
|
| 468 |
+
className="py-16 sm:py-20 lg:py-24 bg-[var(--background-secondary)]"
|
| 469 |
+
>
|
| 470 |
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
| 471 |
+
<motion.div
|
| 472 |
+
className="text-center mb-12 sm:mb-16"
|
| 473 |
+
initial={{ opacity: 0, y: 30 }}
|
| 474 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 475 |
+
viewport={{ once: true, margin: '-100px' }}
|
| 476 |
+
transition={{ duration: 0.8 }}
|
| 477 |
+
>
|
| 478 |
+
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-bold mb-4 sm:mb-6">
|
| 479 |
+
<span className="gradient-text">Social Media Downloader</span>
|
| 480 |
+
</h2>
|
| 481 |
+
<p className="text-lg sm:text-xl text-[var(--foreground-secondary)] max-w-3xl mx-auto px-4">
|
| 482 |
+
Download content from your favorite social media platforms
|
| 483 |
+
</p>
|
| 484 |
+
</motion.div>
|
| 485 |
+
|
| 486 |
+
<motion.div
|
| 487 |
+
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8"
|
| 488 |
+
variants={containerVariants}
|
| 489 |
+
initial="hidden"
|
| 490 |
+
whileInView="visible"
|
| 491 |
+
viewport={{ once: true, margin: '-100px' }}
|
| 492 |
+
>
|
| 493 |
+
{socialPlatforms.map((platform, index) => (
|
| 494 |
+
<motion.div
|
| 495 |
+
key={index}
|
| 496 |
+
className="relative group glass rounded-2xl p-6 sm:p-8 hover:bg-[var(--background-tertiary)]/50 transition-all duration-300 flex flex-col h-full min-h-[280px]"
|
| 497 |
+
variants={itemVariants}
|
| 498 |
+
whileHover={{ y: -5, scale: 1.02 }}
|
| 499 |
+
transition={{ duration: 0.3 }}
|
| 500 |
+
>
|
| 501 |
+
{/* Icon */}
|
| 502 |
+
<platform.icon
|
| 503 |
+
className={`text-4xl sm:text-5xl ${platform.color} mb-4 sm:mb-6`}
|
| 504 |
+
/>
|
| 505 |
+
|
| 506 |
+
{/* Content */}
|
| 507 |
+
<div className="flex-1 flex flex-col">
|
| 508 |
+
<h3 className="text-lg sm:text-xl font-semibold text-[var(--foreground)] mb-3">
|
| 509 |
+
{platform.name}
|
| 510 |
+
</h3>
|
| 511 |
+
<p className="text-[var(--foreground-secondary)] text-sm sm:text-base leading-relaxed flex-1 mb-6">
|
| 512 |
+
{platform.description}
|
| 513 |
+
</p>
|
| 514 |
+
</div>
|
| 515 |
+
|
| 516 |
+
{/* Status Badge - Fixed at bottom */}
|
| 517 |
+
<div className="mt-auto pt-4">
|
| 518 |
+
<span
|
| 519 |
+
className={`px-3 py-1 rounded-full text-xs font-medium ${
|
| 520 |
+
platform.status === 'Available'
|
| 521 |
+
? 'bg-green-500/20 text-green-400 font-semibold border border-green-500/30'
|
| 522 |
+
: 'bg-[var(--accent)] text-[var(--accent)]/20 border border-[var(--accent)]'
|
| 523 |
+
}`}
|
| 524 |
+
>
|
| 525 |
+
{platform.status}
|
| 526 |
+
</span>
|
| 527 |
+
</div>
|
| 528 |
+
</motion.div>
|
| 529 |
+
))}
|
| 530 |
+
</motion.div>
|
| 531 |
+
</div>
|
| 532 |
+
</section>
|
| 533 |
+
|
| 534 |
+
{/* About Section */}
|
| 535 |
+
<section id="about" className="py-16 sm:py-20 lg:py-24">
|
| 536 |
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
| 537 |
+
<motion.div
|
| 538 |
+
className="text-center mb-12 sm:mb-16"
|
| 539 |
+
initial={{ opacity: 0, y: 30 }}
|
| 540 |
+
whileInView={{ opacity: 1, y: 0 }}
|
| 541 |
+
viewport={{ once: true, margin: '-100px' }}
|
| 542 |
+
transition={{ duration: 0.8 }}
|
| 543 |
+
>
|
| 544 |
+
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-bold mb-4 sm:mb-6">
|
| 545 |
+
<span className="gradient-text">About LumaKit</span>
|
| 546 |
+
</h2>
|
| 547 |
+
</motion.div>
|
| 548 |
+
|
| 549 |
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 sm:gap-16 items-center">
|
| 550 |
+
<motion.div
|
| 551 |
+
className="space-y-6"
|
| 552 |
+
initial={{ opacity: 0, x: -50 }}
|
| 553 |
+
whileInView={{ opacity: 1, x: 0 }}
|
| 554 |
+
viewport={{ once: true, margin: '-100px' }}
|
| 555 |
+
transition={{ duration: 0.8 }}
|
| 556 |
+
>
|
| 557 |
+
<p className="text-base sm:text-lg text-[var(--foreground-secondary)] leading-relaxed">
|
| 558 |
+
LumaKit is a comprehensive toolkit designed for creators,
|
| 559 |
+
developers, and digital enthusiasts. Our platform combines the
|
| 560 |
+
power of social media downloading, versatile file conversion,
|
| 561 |
+
and cutting-edge AI technology to streamline your workflow.
|
| 562 |
+
</p>
|
| 563 |
+
<p className="text-base sm:text-lg text-[var(--foreground-secondary)] leading-relaxed">
|
| 564 |
+
Built with modern web technologies and powered by Gemini AI,
|
| 565 |
+
LumaKit offers an intuitive and efficient solution for all your
|
| 566 |
+
digital transformation needs.
|
| 567 |
+
</p>
|
| 568 |
+
<div className="space-y-4">
|
| 569 |
+
{aboutFeatures.map((feature, index) => (
|
| 570 |
+
<motion.div
|
| 571 |
+
key={index}
|
| 572 |
+
className="flex items-center space-x-3"
|
| 573 |
+
initial={{ opacity: 0, x: -20 }}
|
| 574 |
+
whileInView={{ opacity: 1, x: 0 }}
|
| 575 |
+
viewport={{ once: true, margin: '-50px' }}
|
| 576 |
+
transition={{ duration: 0.6, delay: index * 0.1 }}
|
| 577 |
+
>
|
| 578 |
+
<FiStar className="text-[var(--accent)] flex-shrink-0" />
|
| 579 |
+
<span className="text-[var(--foreground-secondary)] text-sm sm:text-base">
|
| 580 |
+
{feature}
|
| 581 |
+
</span>
|
| 582 |
+
</motion.div>
|
| 583 |
+
))}
|
| 584 |
+
</div>
|
| 585 |
+
</motion.div>
|
| 586 |
+
|
| 587 |
+
<motion.div
|
| 588 |
+
className="relative"
|
| 589 |
+
initial={{ opacity: 0, x: 50 }}
|
| 590 |
+
whileInView={{ opacity: 1, x: 0 }}
|
| 591 |
+
viewport={{ once: true, margin: '-100px' }}
|
| 592 |
+
transition={{ duration: 0.8 }}
|
| 593 |
+
>
|
| 594 |
+
<div className="glass rounded-2xl p-6 sm:p-8">
|
| 595 |
+
<div className="space-y-6">
|
| 596 |
+
<div className="flex items-center space-x-4">
|
| 597 |
+
<HiLightningBolt className="text-2xl sm:text-3xl text-[var(--accent)] flex-shrink-0" />
|
| 598 |
+
<div>
|
| 599 |
+
<h4 className="text-base sm:text-lg font-semibold text-[var(--foreground)]">
|
| 600 |
+
Powered by AI
|
| 601 |
+
</h4>
|
| 602 |
+
<p className="text-[var(--foreground-secondary)] text-sm sm:text-base">
|
| 603 |
+
Gemini AI integration for smart transformations
|
| 604 |
+
</p>
|
| 605 |
+
</div>
|
| 606 |
+
</div>
|
| 607 |
+
<div className="flex items-center space-x-4">
|
| 608 |
+
<FiGift className="text-2xl sm:text-3xl text-[var(--accent)] flex-shrink-0" />
|
| 609 |
+
<div>
|
| 610 |
+
<h4 className="text-base sm:text-lg font-semibold text-[var(--foreground)]">
|
| 611 |
+
Free to Use
|
| 612 |
+
</h4>
|
| 613 |
+
<p className="text-[var(--foreground-secondary)] text-sm sm:text-base">
|
| 614 |
+
No subscriptions, no hidden fees
|
| 615 |
+
</p>
|
| 616 |
+
</div>
|
| 617 |
+
</div>
|
| 618 |
+
<div className="flex items-center space-x-4">
|
| 619 |
+
<FiZap className="text-2xl sm:text-3xl text-[var(--accent)] flex-shrink-0" />
|
| 620 |
+
<div>
|
| 621 |
+
<h4 className="text-base sm:text-lg font-semibold text-[var(--foreground)]">
|
| 622 |
+
Lightning Fast
|
| 623 |
+
</h4>
|
| 624 |
+
<p className="text-[var(--foreground-secondary)] text-sm sm:text-base">
|
| 625 |
+
Optimized for speed and performance
|
| 626 |
+
</p>
|
| 627 |
+
</div>
|
| 628 |
+
</div>
|
| 629 |
+
</div>
|
| 630 |
+
</div>
|
| 631 |
+
</motion.div>
|
| 632 |
+
</div>
|
| 633 |
+
</div>
|
| 634 |
+
</section>
|
| 635 |
+
|
| 636 |
+
<Footer />
|
| 637 |
</div>
|
| 638 |
);
|
| 639 |
}
|
|
@@ -2,20 +2,133 @@
|
|
| 2 |
@tailwind components;
|
| 3 |
@tailwind utilities;
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
:root {
|
| 6 |
-
|
| 7 |
-
--
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
}
|
| 9 |
|
| 10 |
-
@media (prefers-color-scheme:
|
| 11 |
:root {
|
| 12 |
-
--background:
|
| 13 |
-
--
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
}
|
| 15 |
}
|
| 16 |
|
| 17 |
body {
|
| 18 |
color: var(--foreground);
|
| 19 |
background: var(--background);
|
| 20 |
-
font-family: var(--font-bricolage-grotesque), sans-serif;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
}
|
|
|
|
| 2 |
@tailwind components;
|
| 3 |
@tailwind utilities;
|
| 4 |
|
| 5 |
+
/* Smooth scrolling */
|
| 6 |
+
html {
|
| 7 |
+
scroll-behavior: smooth;
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
:root {
|
| 11 |
+
/* Light Pastel Brown Theme */
|
| 12 |
+
--light-bg-primary: #F7F3F0;
|
| 13 |
+
--light-bg-secondary: #F0E6D6;
|
| 14 |
+
--light-bg-tertiary: #E8DDD0;
|
| 15 |
+
--light-text-primary: #3C2E26;
|
| 16 |
+
--light-text-secondary: #5D4E42;
|
| 17 |
+
--light-text-muted: #8B7355;
|
| 18 |
+
--light-accent: #D4A574;
|
| 19 |
+
--light-accent-hover: #C69963;
|
| 20 |
+
--light-border: #DDD0BB;
|
| 21 |
+
--light-shadow: rgba(60, 46, 38, 0.1);
|
| 22 |
+
|
| 23 |
+
/* Dark Pastel Brown Theme */
|
| 24 |
+
--dark-bg-primary: #1F1B17;
|
| 25 |
+
--dark-bg-secondary: #2A241E;
|
| 26 |
+
--dark-bg-tertiary: #342D25;
|
| 27 |
+
--dark-text-primary: #F5F1EC;
|
| 28 |
+
--dark-text-secondary: #E0D5C7;
|
| 29 |
+
--dark-text-muted: #B8A690;
|
| 30 |
+
--dark-accent: #D4A574;
|
| 31 |
+
--dark-accent-hover: #E6B885;
|
| 32 |
+
--dark-border: #3F362B;
|
| 33 |
+
--dark-shadow: rgba(0, 0, 0, 0.3);
|
| 34 |
+
|
| 35 |
+
/* Default to dark theme */
|
| 36 |
+
--background: var(--dark-bg-primary);
|
| 37 |
+
--background-secondary: var(--dark-bg-secondary);
|
| 38 |
+
--background-tertiary: var(--dark-bg-tertiary);
|
| 39 |
+
--foreground: var(--dark-text-primary);
|
| 40 |
+
--foreground-secondary: var(--dark-text-secondary);
|
| 41 |
+
--foreground-muted: var(--dark-text-muted);
|
| 42 |
+
--accent: var(--dark-accent);
|
| 43 |
+
--accent-hover: var(--dark-accent-hover);
|
| 44 |
+
--border: var(--dark-border);
|
| 45 |
+
--shadow: var(--dark-shadow);
|
| 46 |
}
|
| 47 |
|
| 48 |
+
@media (prefers-color-scheme: light) {
|
| 49 |
:root {
|
| 50 |
+
--background: var(--light-bg-primary);
|
| 51 |
+
--background-secondary: var(--light-bg-secondary);
|
| 52 |
+
--background-tertiary: var(--light-bg-tertiary);
|
| 53 |
+
--foreground: var(--light-text-primary);
|
| 54 |
+
--foreground-secondary: var(--light-text-secondary);
|
| 55 |
+
--foreground-muted: var(--light-text-muted);
|
| 56 |
+
--accent: var(--light-accent);
|
| 57 |
+
--accent-hover: var(--light-accent-hover);
|
| 58 |
+
--border: var(--light-border);
|
| 59 |
+
--shadow: var(--light-shadow);
|
| 60 |
}
|
| 61 |
}
|
| 62 |
|
| 63 |
body {
|
| 64 |
color: var(--foreground);
|
| 65 |
background: var(--background);
|
| 66 |
+
font-family: var(--font-bricolage-grotesque), -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
| 67 |
+
line-height: 1.6;
|
| 68 |
+
-webkit-font-smoothing: antialiased;
|
| 69 |
+
-moz-osx-font-smoothing: grayscale;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
/* Custom scrollbar */
|
| 73 |
+
::-webkit-scrollbar {
|
| 74 |
+
width: 8px;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
::-webkit-scrollbar-track {
|
| 78 |
+
background: var(--background-secondary);
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
::-webkit-scrollbar-thumb {
|
| 82 |
+
background: var(--border);
|
| 83 |
+
border-radius: 4px;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
::-webkit-scrollbar-thumb:hover {
|
| 87 |
+
background: var(--accent);
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
/* Selection color */
|
| 91 |
+
::selection {
|
| 92 |
+
background: var(--accent);
|
| 93 |
+
color: var(--background);
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
/* Focus styles */
|
| 97 |
+
*:focus {
|
| 98 |
+
outline: 2px solid var(--accent);
|
| 99 |
+
outline-offset: 2px;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
/* Smooth transitions for theme changes */
|
| 103 |
+
* {
|
| 104 |
+
transition: background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
/* Performance optimizations */
|
| 108 |
+
.will-change-transform {
|
| 109 |
+
will-change: transform;
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
.will-change-opacity {
|
| 113 |
+
will-change: opacity;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
/* Glass morphism effect */
|
| 117 |
+
.glass {
|
| 118 |
+
background: rgba(212, 165, 116, 0.1);
|
| 119 |
+
backdrop-filter: blur(16px);
|
| 120 |
+
-webkit-backdrop-filter: blur(16px);
|
| 121 |
+
border: 1px solid rgba(212, 165, 116, 0.2);
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
/* Gradient backgrounds */
|
| 125 |
+
.gradient-bg {
|
| 126 |
+
background: linear-gradient(135deg, var(--background) 0%, var(--background-secondary) 100%);
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
.gradient-text {
|
| 130 |
+
background: linear-gradient(135deg, var(--accent) 0%, var(--accent-hover) 100%);
|
| 131 |
+
-webkit-background-clip: text;
|
| 132 |
+
-webkit-text-fill-color: transparent;
|
| 133 |
+
background-clip: text;
|
| 134 |
}
|