diff --git a/thunder/frontend/package-lock.json b/thunder/frontend/package-lock.json index ccb721f..bfde5d8 100644 --- a/thunder/frontend/package-lock.json +++ b/thunder/frontend/package-lock.json @@ -23,8 +23,8 @@ "framer-motion": "^12.9.7", "jszip": "^3.10.1", "lucide-react": "0.321.0", - "react": "^19.1.1", - "react-dom": "^19.1.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-responsive": "^10.0.1", "react-router-dom": "^6.22.3", "react-textarea-autosize": "^8.5.9", @@ -388,13 +388,13 @@ } }, "node_modules/@clerk/shared": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-3.22.0.tgz", - "integrity": "sha512-qBtWjnqST0a+sYRArkFwyCwlAM5NxyZvbicz6uvQnq0ZuFQwoGzYiZ0V47kJ+rc6c2jz3qAd8GR1h0hUtfI5cg==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-3.23.0.tgz", + "integrity": "sha512-HzUzkpjoCMGq3RlpFlWmWYUzD7b2Arqqz5EgPJ5+FsQhCLbq1kHqoTQByTJDX0Ahf8Pvp9E+fbkovaMzBVbuow==", "hasInstallScript": true, "license": "MIT", "dependencies": { - "@clerk/types": "^4.81.0", + "@clerk/types": "^4.83.0", "dequal": "2.0.3", "glob-to-regexp": "0.4.1", "js-cookie": "3.0.5", @@ -418,9 +418,9 @@ } }, "node_modules/@clerk/types": { - "version": "4.81.0", - "resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.81.0.tgz", - "integrity": "sha512-uSVAKUmYiFy2POXP3jNh7iCqdbEpzQe+IjY6MWiI5eYjMXR1l+TwYbU0r3IqnTzAzwm8TlklkpTaeR5ZXKW1Gw==", + "version": "4.83.0", + "resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.83.0.tgz", + "integrity": "sha512-WEILYgTGkwdB7OUoxHPrdHe/UAUPYvwutJxrwPyHfTejBmRD0RcKmB8VwTqwOxlfQgcKVDfLQ9jLW8m7NeJHIA==", "license": "MIT", "dependencies": { "csstype": "3.1.3" @@ -1350,12 +1350,73 @@ "node": ">=14" } }, + "node_modules/@react-spring/animated": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", + "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", + "license": "MIT", + "dependencies": { + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz", + "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", + "license": "MIT", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@react-spring/rafz": { "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz", "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==", "license": "MIT" }, + "node_modules/@react-spring/shared": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz", + "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", + "license": "MIT", + "dependencies": { + "@react-spring/rafz": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/three": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.7.5.tgz", + "integrity": "sha512-RxIsCoQfUqOS3POmhVHa1wdWS0wyHAUway73uRLp3GAL5U2iYVNdnzQsep6M2NZ994BlW8TcKuMtQHUqOsy6WA==", + "license": "MIT", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/core": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "@react-three/fiber": ">=6.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "three": ">=0.126" + } + }, "node_modules/@react-spring/types": { "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz", @@ -1403,67 +1464,6 @@ } } }, - "node_modules/@react-three/drei/node_modules/@react-spring/three": { - "version": "9.7.5", - "resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.7.5.tgz", - "integrity": "sha512-RxIsCoQfUqOS3POmhVHa1wdWS0wyHAUway73uRLp3GAL5U2iYVNdnzQsep6M2NZ994BlW8TcKuMtQHUqOsy6WA==", - "license": "MIT", - "dependencies": { - "@react-spring/animated": "~9.7.5", - "@react-spring/core": "~9.7.5", - "@react-spring/shared": "~9.7.5", - "@react-spring/types": "~9.7.5" - }, - "peerDependencies": { - "@react-three/fiber": ">=6.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "three": ">=0.126" - } - }, - "node_modules/@react-three/drei/node_modules/@react-spring/three/node_modules/@react-spring/animated": { - "version": "9.7.5", - "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", - "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", - "license": "MIT", - "dependencies": { - "@react-spring/shared": "~9.7.5", - "@react-spring/types": "~9.7.5" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@react-three/drei/node_modules/@react-spring/three/node_modules/@react-spring/core": { - "version": "9.7.5", - "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz", - "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", - "license": "MIT", - "dependencies": { - "@react-spring/animated": "~9.7.5", - "@react-spring/shared": "~9.7.5", - "@react-spring/types": "~9.7.5" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/react-spring/donate" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@react-three/drei/node_modules/@react-spring/three/node_modules/@react-spring/shared": { - "version": "9.7.5", - "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz", - "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", - "license": "MIT", - "dependencies": { - "@react-spring/rafz": "~9.7.5", - "@react-spring/types": "~9.7.5" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/@react-three/drei/node_modules/react-composer": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/react-composer/-/react-composer-5.0.3.tgz", @@ -4793,31 +4793,38 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", - "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", - "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "dependencies": { - "scheduler": "^0.26.0" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^19.1.1" + "react": "^18.3.1" } }, "node_modules/react-dom/node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", - "license": "MIT" + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } }, "node_modules/react-is": { "version": "16.13.1", diff --git a/thunder/frontend/package.json b/thunder/frontend/package.json index 6635521..5a9f818 100644 --- a/thunder/frontend/package.json +++ b/thunder/frontend/package.json @@ -25,8 +25,8 @@ "framer-motion": "^12.9.7", "jszip": "^3.10.1", "lucide-react": "0.321.0", - "react": "^19.1.1", - "react-dom": "^19.1.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-responsive": "^10.0.1", "react-router-dom": "^6.22.3", "react-textarea-autosize": "^8.5.9", diff --git a/thunder/frontend/src/pages/Home.tsx b/thunder/frontend/src/pages/Home.tsx index aaba784..387da80 100644 --- a/thunder/frontend/src/pages/Home.tsx +++ b/thunder/frontend/src/pages/Home.tsx @@ -1,32 +1,55 @@ - -import { useState, useRef, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { motion, AnimatePresence } from 'framer-motion'; -import { UserButton, SignInButton, SignUpButton, SignedIn, SignedOut, useAuth, useUser } from '@clerk/clerk-react'; -import { Home as HomeIcon, Plus, DollarSign, Eye, Gift, HelpCircle, Settings as SettingsIcon, X } from 'lucide-react'; -import { useMediaQuery } from 'react-responsive'; -import { Lightning } from '../components/lightning'; -import { Settings } from '../components/setting'; +import { useState, useRef, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import { motion, AnimatePresence } from "framer-motion"; +import { + UserButton, + SignInButton, + SignUpButton, + SignedIn, + SignedOut, + useAuth, + useUser, +} from "@clerk/clerk-react"; +import { + Home as HomeIcon, + Plus, + DollarSign, + Eye, + Gift, + HelpCircle, + Settings as SettingsIcon, + X, +} from "lucide-react"; +import { useMediaQuery } from "react-responsive"; +import { Lightning } from "../components/lightning"; +import { Settings } from "../components/setting"; // SVG Logo Component with Lightning Colors const ThunderLogoSVG = () => ( - + - - + + ); interface UserMetadata { - tier: 'free' | 'pro' | 'enterprise'; + tier: "free" | "pro" | "enterprise"; remainingTokens: number; showTokenUsage: boolean; lineWrapping: boolean; - theme: 'dark' | 'light' | 'system'; + theme: "dark" | "light" | "system"; notifications: boolean; dailyTokens: number; extraTokens: number; @@ -52,24 +75,24 @@ interface Chat { } export function Home() { - const [prompt, setPrompt] = useState(''); + const [prompt, setPrompt] = useState(""); const navigate = useNavigate(); const fileInputRef = useRef(null); const { isSignedIn, userId } = useAuth(); const { user } = useUser(); const [usage, setUsage] = useState({ - tier: 'free', + tier: "free", remainingTokens: 3, showTokenUsage: false, lineWrapping: false, - theme: 'dark', + theme: "dark", notifications: true, dailyTokens: 0, extraTokens: 922000, monthlyTokens: 240000, totalMonthlyTokens: 1000000, nextRefill: 1000000, - referralId: '', + referralId: "", referralTokensEarned: 0, freeReferrals: 0, proReferrals: 0, @@ -82,27 +105,29 @@ export function Home() { const isMobile = useMediaQuery({ maxWidth: 640 }); // Generate referral link - const referralLink = userId ? `https://thunder-muneer.vercel.app/?ref=${userId}` : ''; + const referralLink = userId + ? `https://thunder-muneer.vercel.app/?ref=${userId}` + : ""; const loadProjects = () => { try { - const storedProjects = localStorage.getItem('projects'); + const storedProjects = localStorage.getItem("projects"); if (storedProjects) { setProjects(JSON.parse(storedProjects)); } } catch (error) { - console.error('Error loading projects:', error); + console.error("Error loading projects:", error); } }; const loadChats = () => { try { - const storedChats = localStorage.getItem('chats'); + const storedChats = localStorage.getItem("chats"); if (storedChats) { setChats(JSON.parse(storedChats)); } } catch (error) { - console.error('Error loading chats:', error); + console.error("Error loading chats:", error); } }; @@ -111,24 +136,24 @@ export function Home() { if (isSignedIn && user) { const metadata = user.unsafeMetadata as Partial; setUsage({ - tier: metadata.tier || 'free', + tier: metadata.tier || "free", remainingTokens: metadata.remainingTokens || 3, showTokenUsage: metadata.showTokenUsage ?? false, lineWrapping: metadata.lineWrapping ?? false, - theme: metadata.theme || 'dark', + theme: metadata.theme || "dark", notifications: metadata.notifications ?? true, dailyTokens: metadata.dailyTokens ?? 0, extraTokens: metadata.extraTokens ?? 922000, monthlyTokens: metadata.monthlyTokens ?? 240000, totalMonthlyTokens: metadata.totalMonthlyTokens ?? 1000000, nextRefill: metadata.nextRefill ?? 1000000, - referralId: metadata.referralId || userId || '', + referralId: metadata.referralId || userId || "", referralTokensEarned: metadata.referralTokensEarned || 0, freeReferrals: metadata.freeReferrals || 0, proReferrals: metadata.proReferrals || 0, }); } else { - const localUsage = localStorage.getItem('usage'); + const localUsage = localStorage.getItem("usage"); if (localUsage) { setUsage(JSON.parse(localUsage)); } @@ -140,33 +165,37 @@ export function Home() { loadChats(); const handleStorageChange = (e: StorageEvent) => { - if (e.key === 'projects') loadProjects(); - else if (e.key === 'chats') loadChats(); + if (e.key === "projects") loadProjects(); + else if (e.key === "chats") loadChats(); }; - window.addEventListener('storage', handleStorageChange); - return () => window.removeEventListener('storage', handleStorageChange); + window.addEventListener("storage", handleStorageChange); + return () => window.removeEventListener("storage", handleStorageChange); }, [isSignedIn, user, userId]); const recommendations = [ - 'Design a futuristic portfolio for my digital art', - 'Create an online store for sustainable fashion', - 'Build a tech blog with interactive demos', - 'Make a vibrant landing page for my app', + "Design a futuristic portfolio for my digital art", + "Create an online store for sustainable fashion", + "Build a tech blog with interactive demos", + "Make a vibrant landing page for my app", ]; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!isSignedIn) { - alert('Please sign in to submit prompts'); + alert("Please sign in to submit prompts"); return; } - if (usage.remainingTokens <= 0 && usage.tier === 'free') { + if (usage.remainingTokens <= 0 && usage.tier === "free") { alert("You've reached your free limit. Please upgrade to continue."); - navigate('/pricing'); + navigate("/pricing"); return; } if (prompt.trim()) { - const newUsage = { ...usage, remainingTokens: usage.remainingTokens - 1, dailyTokens: usage.dailyTokens + 1 }; + const newUsage = { + ...usage, + remainingTokens: usage.remainingTokens - 1, + dailyTokens: usage.dailyTokens + 1, + }; const newProject: Project = { id: crypto.randomUUID(), prompt, @@ -174,7 +203,7 @@ export function Home() { }; const updatedProjects = [newProject, ...projects]; try { - localStorage.setItem('projects', JSON.stringify(updatedProjects)); + localStorage.setItem("projects", JSON.stringify(updatedProjects)); setProjects(updatedProjects); const newChat: Chat = { id: crypto.randomUUID(), @@ -182,153 +211,201 @@ export function Home() { createdAt: new Date().toISOString(), }; const updatedChats = [newChat, ...chats]; - localStorage.setItem('chats', JSON.stringify(updatedChats)); + localStorage.setItem("chats", JSON.stringify(updatedChats)); setChats(updatedChats); setUsage(newUsage); if (user) { await user.update({ unsafeMetadata: newUsage }); } else { - localStorage.setItem('usage', JSON.stringify(newUsage)); + localStorage.setItem("usage", JSON.stringify(newUsage)); } - navigate('/builder', { state: { prompt } }); - setPrompt(''); + navigate("/builder", { state: { prompt } }); + setPrompt(""); } catch (error) { - console.error('Error saving data:', error); - alert('Failed to save project or chat.'); + console.error("Error saving data:", error); + alert("Failed to save project or chat."); } } }; const handleFileUpload = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; - if (file) console.log('Uploaded file:', file); + if (file) console.log("Uploaded file:", file); }; const viewProject = (projectPrompt: string) => { - navigate('/builder', { state: { prompt: projectPrompt } }); + navigate("/builder", { state: { prompt: projectPrompt } }); }; const handleCopyReferralLink = () => { if (referralLink) { navigator.clipboard.writeText(referralLink); - alert('Referral link copied!'); + alert("Referral link copied!"); } }; return ( -
- {!isMobile && } +
+ {!isMobile && ( + + )} setIsSidebarExpanded(true)} onMouseLeave={() => setIsSidebarExpanded(false)} initial={{ scaleX: 0 }} animate={{ scaleX: 1 }} - transition={{ type: 'spring', stiffness: 200, damping: 30 }} + transition={{ type: "spring", stiffness: 200, damping: 30 }} > -
-
- - {isSidebarExpanded && ( - Thunder - )} -
- -
- - - {isSidebarExpanded && Profile} - - setIsSettingsOpen(true)} - whileHover={{ scale: 1.05, backgroundColor: '#1E3A8A' }} - className="flex items-center space-x-3 text-blue-200 hover:text-blue-400 w-full p-2 rounded-lg hover:bg-blue-900/60 transition-colors" - > - - {isSidebarExpanded && Settings} - -
-
+
+ {/* Logo Section */} +
+
+ +
+ {isSidebarExpanded && ( + + Thunder + + )} +
+ + {/* Navigation */} + + + {/* Bottom Section */} +
+ {/* Profile */} + +
+ + {isSidebarExpanded && Profile} +
+
+ + {/* Settings */} + setIsSettingsOpen(true)} + whileHover={{ scale: 1.05, backgroundColor: '#1E3A8A' }} + className="w-full p-2 rounded-lg hover:bg-blue-900/60 transition-colors text-blue-200 hover:text-blue-400" + > +
+ + {isSidebarExpanded && Settings} +
+
+
+
navigate('/')} + onClick={() => navigate("/")} whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} className="flex flex-col items-center text-blue-200 hover:text-blue-400 p-2" @@ -346,7 +423,9 @@ export function Home() { Tokens window.open('https://thunder-docs.vercel.app/', '_blank')} + onClick={() => + window.open("https://thunder-docs.vercel.app/", "_blank") + } whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} className="flex flex-col items-center text-blue-200 hover:text-blue-400 p-2" @@ -355,7 +434,7 @@ export function Home() { Help navigate('/')} + onClick={() => navigate("/")} whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} className="flex flex-col items-center text-blue-200 hover:text-blue-400 p-2" @@ -393,9 +472,11 @@ export function Home() { appearance={{ elements: { userButtonAvatarBox: "w-6 h-6", - userButtonPopoverCard: "bg-gray-900/80 border border-blue-500/40 backdrop-blur-2xl", + userButtonPopoverCard: + "bg-gray-900/80 border border-blue-500/40 backdrop-blur-2xl", userPreviewMainIdentifier: "text-blue-400", - userButtonPopoverActionButtonText: "text-blue-200 hover:text-blue-400", + userButtonPopoverActionButtonText: + "text-blue-200 hover:text-blue-400", }, }} /> @@ -430,7 +511,7 @@ export function Home() { initial={{ scale: 0.8, y: 50 }} animate={{ scale: 1, y: 0 }} exit={{ scale: 0.8, y: 50 }} - transition={{ type: 'spring', stiffness: 200, damping: 20 }} + transition={{ type: "spring", stiffness: 200, damping: 20 }} >

@@ -447,30 +528,45 @@ export function Home() {

- Earn 200K tokens for yourself & each new user you refer to Thunder. + Earn 200K tokens for yourself & each new user you refer to + Thunder.

- Pro users: earn an additional 5M tokens for yourself & your referral when they upgrade to a Pro account within 30 days! + Pro users: earn an additional 5M tokens for yourself & your + referral when they upgrade to a Pro account within 30 days!

-

Referral tokens earned

-

{(usage.referralTokensEarned ?? 0).toLocaleString()}

+

+ Referral tokens earned +

+

+ {(usage.referralTokensEarned ?? 0).toLocaleString()} +

-

Free Referrals

-

{usage.freeReferrals ?? 0}

+

+ Free Referrals +

+

+ {usage.freeReferrals ?? 0} +

-

Pro Referrals

+

+ Pro Referrals +

- {usage.tier === 'pro' ? (usage.proReferrals ?? 0) : 'Upgrade to Pro to unlock Pro referrals'} + {usage.tier === "pro" + ? usage.proReferrals ?? 0 + : "Upgrade to Pro to unlock Pro referrals"}

- Use your personal referral link to invite users to join Thunder: + Use your personal referral link to invite users to join + Thunder:

- {usage.tier === 'free' ? ( + {usage.tier === "free" ? ( Free Tokens: {usage.remainingTokens}/3 @@ -521,11 +617,13 @@ export function Home() {
- Thunder + + Thunder +
navigate('/pricing')} + onClick={() => navigate("/pricing")} className="text-blue-200 hover:text-blue-400 transition-colors" whileHover={{ scale: 1.05 }} > @@ -562,9 +660,13 @@ export function Home() { > What do you want to build? @@ -574,7 +676,8 @@ export function Home() { animate={{ opacity: 1 }} transition={{ delay: 0.5, duration: 0.7 }} > - Prompt, run, edit, and deploy full-stack web and mobile apps with Thunder. + Prompt, run, edit, and deploy full-stack web and mobile apps with + Thunder. @@ -582,14 +685,22 @@ export function Home() {
fileInputRef.current?.click()} - whileHover={{ scale: 1.2, rotate: 15, boxShadow: '0 0 25px rgba(96, 165, 250, 0.8)' }} + whileHover={{ + scale: 1.2, + rotate: 15, + boxShadow: "0 0 25px rgba(96, 165, 250, 0.8)", + }} whileTap={{ scale: 0.85 }} className="absolute bottom-4 sm:bottom-5 left-4 sm:left-6 bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white rounded-full p-3 sm:p-4 shadow-lg shadow-blue-500/60 hover:shadow-purple-600/80 transition-all duration-500" > @@ -608,12 +719,18 @@ export function Home() { placeholder="e.g. A modern SaaS website with animations and 3D assets" rows={4} className="w-full p-4 sm:p-6 sm:px-16 bg-transparent text-blue-100 rounded-xl border-none placeholder-blue-200/60 focus:outline-none focus:ring-4 focus:ring-blue-500/70 transition-all duration-500 text-base sm:text-lg resize-none" - whileFocus={{ scale: 1.03, boxShadow: '0 0 20px rgba(96, 165, 250, 0.5)' }} + whileFocus={{ + scale: 1.03, + boxShadow: "0 0 20px rgba(96, 165, 250, 0.5)", + }} /> {prompt.trim() && ( @@ -635,7 +752,9 @@ export function Home() {

Join Thunder to Unleash Creativity

-

Sign up to start generating amazing website designs

+

+ Sign up to start generating amazing website designs +

{recommendations.map((rec, index) => ( setPrompt(rec)} - whileHover={{ scale: 1.15, y: -5, boxShadow: '0 0 20px rgba(192, 38, 211, 0.6)' }} + whileHover={{ + scale: 1.15, + y: -5, + boxShadow: "0 0 20px rgba(192, 38, 211, 0.6)", + }} whileTap={{ scale: 0.9 }} className="bg-gray-900/60 backdrop-blur-2xl hover:bg-gray-800/70 border border-blue-500/40 text-blue-100 hover:text-blue-400 px-4 sm:px-6 py-2 sm:py-3 rounded-xl text-sm font-medium transition-all duration-500 shadow-lg hover:shadow-2xl hover:shadow-purple-600/50" initial={{ opacity: 0, y: 30 }} @@ -673,7 +800,7 @@ export function Home() { - {usage.tier === 'free' && usage.remainingTokens <= 1 && ( + {usage.tier === "free" && usage.remainingTokens <= 1 && (