YoruAkio commited on
Commit
bbff783
·
1 Parent(s): 6844c91

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 CHANGED
@@ -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@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
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-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
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
 
frontend/next.config.mjs CHANGED
@@ -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;
frontend/package.json CHANGED
@@ -9,9 +9,12 @@
9
  "lint": "next lint"
10
  },
11
  "dependencies": {
 
 
 
12
  "react": "^19.0.0",
13
  "react-dom": "^19.0.0",
14
- "next": "15.1.8"
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",
frontend/src/components/Footer.js ADDED
@@ -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
+ }
frontend/src/components/Navbar.js ADDED
@@ -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
+ }
frontend/src/pages/_app.js CHANGED
@@ -1,15 +1,23 @@
1
- import '@/styles/globals.css';
2
- import { Bricolage_Grotesque } from 'next/font/google';
 
3
 
4
- const bricolageGrotesque = Bricolage_Grotesque({
5
- variable: '--font-bricolage-grotesque',
6
  subsets: ['latin'],
 
7
  });
8
 
9
  export default function App({ Component, pageProps }) {
10
  return (
11
- <div className={`${bricolageGrotesque.variable}`}>
12
- <Component {...pageProps} />
13
- </div>
 
 
 
 
 
 
 
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
+ }
frontend/src/pages/index.js CHANGED
@@ -1,101 +1,639 @@
1
- import Image from 'next/image';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  export default function Home() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  return (
5
- <div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-bricolage-grotesque)]">
6
- <main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
7
- <Image
8
- className="dark:invert"
9
- src="/next.svg"
10
- alt="Next.js logo"
11
- width={180}
12
- height={38}
13
- priority
14
  />
15
- <ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-bricolage-grotesque)]">
16
- <li className="mb-2">
17
- Get started by editing{' '}
18
- <code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold">
19
- src/pages/index.js
20
- </code>
21
- .
22
- </li>
23
- <li>Save and see your changes instantly.</li>
24
- </ol>
25
-
26
- <div className="flex gap-4 items-center flex-col sm:flex-row">
27
- <a
28
- className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
29
- href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
30
- target="_blank"
31
- rel="noopener noreferrer"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  >
33
- <Image
34
- className="dark:invert"
35
- src="/vercel.svg"
36
- alt="Vercel logomark"
37
- width={20}
38
- height={20}
39
- />
40
- Deploy now
41
- </a>
42
- <a
43
- className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
44
- href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
45
- target="_blank"
46
- rel="noopener noreferrer"
 
47
  >
48
- Read our docs
49
- </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  </div>
51
- </main>
52
- <footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
53
- <a
54
- className="flex items-center gap-2 hover:underline hover:underline-offset-4"
55
- href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
56
- target="_blank"
57
- rel="noopener noreferrer"
58
- >
59
- <Image
60
- aria-hidden
61
- src="/file.svg"
62
- alt="File icon"
63
- width={16}
64
- height={16}
65
- />
66
- Learn
67
- </a>
68
- <a
69
- className="flex items-center gap-2 hover:underline hover:underline-offset-4"
70
- href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
71
- target="_blank"
72
- rel="noopener noreferrer"
73
- >
74
- <Image
75
- aria-hidden
76
- src="/window.svg"
77
- alt="Window icon"
78
- width={16}
79
- height={16}
80
- />
81
- Examples
82
- </a>
83
- <a
84
- className="flex items-center gap-2 hover:underline hover:underline-offset-4"
85
- href="https://nextjs.org?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
86
- target="_blank"
87
- rel="noopener noreferrer"
88
- >
89
- <Image
90
- aria-hidden
91
- src="/globe.svg"
92
- alt="Globe icon"
93
- width={16}
94
- height={16}
95
- />
96
- Go to nextjs.org →
97
- </a>
98
- </footer>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
  }
frontend/src/styles/globals.css CHANGED
@@ -2,20 +2,133 @@
2
  @tailwind components;
3
  @tailwind utilities;
4
 
 
 
 
 
 
5
  :root {
6
- --background: #ffffff;
7
- --foreground: #171717;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  }
9
 
10
- @media (prefers-color-scheme: dark) {
11
  :root {
12
- --background: #0a0a0a;
13
- --foreground: #ededed;
 
 
 
 
 
 
 
 
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
  }