26 Commits

Author SHA1 Message Date
72ccfef498 Update src/app/page.tsx 2026-03-04 19:05:23 +00:00
67dd981fc3 Update src/app/app/page.tsx 2026-03-04 19:05:23 +00:00
b61160d424 Update src/app/page.tsx 2026-03-04 19:04:22 +00:00
6246fb8a98 Update src/app/layout.tsx 2026-03-04 19:04:22 +00:00
eb9a36ca38 Update src/app/globals.css 2026-03-04 19:04:21 +00:00
7d0711fa12 Add src/app/auth/page.tsx 2026-03-04 19:04:20 +00:00
25ce1007e5 Add src/app/app/page.tsx 2026-03-04 19:04:18 +00:00
9d17ce6163 Merge version_3 into main
Merge version_3 into main
2026-03-04 18:12:23 +00:00
a1113f31cf Update src/app/generate/page.tsx 2026-03-04 18:12:18 +00:00
212dafd864 Merge version_3 into main
Merge version_3 into main
2026-03-04 18:11:13 +00:00
fa9c466286 Update src/app/page.tsx 2026-03-04 18:11:09 +00:00
c74295ff8a Add src/app/generate/page.tsx 2026-03-04 18:11:09 +00:00
b462ddd553 Update src/app/features/page.tsx 2026-03-04 18:11:08 +00:00
c0eefcb803 Update src/app/download/page.tsx 2026-03-04 18:11:08 +00:00
e24491952b Update src/app/contact/page.tsx 2026-03-04 18:11:08 +00:00
575005a59a Merge version_2 into main
Merge version_2 into main
2026-03-04 18:05:30 +00:00
3682f2cfdf Update src/app/page.tsx 2026-03-04 18:05:26 +00:00
9761d07ebf Update src/app/features/page.tsx 2026-03-04 18:05:25 +00:00
9208036b0f Merge version_2 into main
Merge version_2 into main
2026-03-04 18:04:44 +00:00
124ce99cfb Update src/app/styles/variables.css 2026-03-04 18:04:40 +00:00
8935383ef9 Update src/app/page.tsx 2026-03-04 18:04:39 +00:00
f15928fb51 Update src/app/layout.tsx 2026-03-04 18:04:39 +00:00
526f185500 Add src/app/features/page.tsx 2026-03-04 18:04:38 +00:00
24c66e59c0 Add src/app/download/page.tsx 2026-03-04 18:04:38 +00:00
588e13b79f Add src/app/contact/page.tsx 2026-03-04 18:04:38 +00:00
b24b6a7699 Merge version_1 into main
Merge version_1 into main
2026-03-04 17:55:13 +00:00
10 changed files with 1515 additions and 224 deletions

418
src/app/app/page.tsx Normal file
View File

@@ -0,0 +1,418 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarStyleFullscreen from '@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen';
import FooterMedia from '@/components/sections/footer/FooterMedia';
import { useState, useEffect } from "react";
import { ChefHat, LogOut, User, Heart, Settings, Plus, X, Sparkles, Clock, Users2 } from "lucide-react";
import Link from "next/link";
export default function AppPage() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [user, setUser] = useState<any>(null);
const [ingredients, setIngredients] = useState<string[]>([]);
const [currentInput, setCurrentInput] = useState("");
const [recipes, setRecipes] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
const [savedRecipes, setSavedRecipes] = useState<any[]>([]);
const [showSavedOnly, setShowSavedOnly] = useState(false);
const [showProfile, setShowProfile] = useState(false);
useEffect(() => {
// Check if user is logged in
const checkAuth = async () => {
try {
const response = await fetch('/api/auth/me');
if (response.ok) {
const data = await response.json();
setUser(data.user);
setIsLoggedIn(true);
setSavedRecipes(data.user.savedRecipes || []);
} else {
window.location.href = '/auth';
}
} catch (error) {
window.location.href = '/auth';
}
};
checkAuth();
}, []);
const addIngredient = () => {
if (currentInput.trim()) {
setIngredients([...ingredients, currentInput.trim()]);
setCurrentInput("");
}
};
const removeIngredient = (index: number) => {
setIngredients(ingredients.filter((_, i) => i !== index));
};
const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === "Enter") {
e.preventDefault();
addIngredient();
}
};
const generateRecipes = async () => {
if (ingredients.length === 0) {
alert("Please add at least one ingredient");
return;
}
setLoading(true);
try {
const response = await fetch("/api/recipes/generate", {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ingredients })
});
if (response.ok) {
const data = await response.json();
setRecipes(data.recipes || []);
}
} catch (error) {
console.error("Recipe generation failed:", error);
} finally {
setLoading(false);
}
};
const saveRecipe = async (recipe: any) => {
try {
const response = await fetch("/api/recipes/save", {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ recipe })
});
if (response.ok) {
setSavedRecipes([...savedRecipes, recipe]);
}
} catch (error) {
console.error("Failed to save recipe:", error);
}
};
const handleLogout = async () => {
try {
await fetch("/api/auth/logout", { method: "POST" });
window.location.href = "/";
} catch (error) {
console.error("Logout failed:", error);
}
};
if (!isLoggedIn || !user) {
return (
<ThemeProvider
defaultButtonVariant="expand-hover"
defaultTextAnimation="entrance-slide"
borderRadius="pill"
contentWidth="mediumLarge"
sizing="mediumLargeSizeLargeTitles"
background="none"
cardStyle="glass-elevated"
primaryButtonStyle="gradient"
secondaryButtonStyle="glass"
headingFontWeight="semibold"
>
<div className="min-h-screen flex items-center justify-center">
<div className="text-center">
<div className="inline-block animate-spin mb-4">
<Sparkles size={40} className="text-purple-600" />
</div>
<p className="text-gray-600 dark:text-gray-300">Loading your kitchen...</p>
</div>
</div>
</ThemeProvider>
);
}
const displayRecipes = showSavedOnly ? savedRecipes : recipes;
return (
<ThemeProvider
defaultButtonVariant="expand-hover"
defaultTextAnimation="entrance-slide"
borderRadius="pill"
contentWidth="mediumLarge"
sizing="mediumLargeSizeLargeTitles"
background="none"
cardStyle="glass-elevated"
primaryButtonStyle="gradient"
secondaryButtonStyle="glass"
headingFontWeight="semibold"
>
<div id="nav" data-section="nav">
<NavbarStyleFullscreen
brandName="EasyRecipes"
navItems={[
{ name: "Home", id: "/" },
{ name: "Features", id: "/#features" },
{ name: "Auth", id: "/auth" },
{ name: "App", id: "/app" },
{ name: "Contact", id: "/#contact" }
]}
bottomLeftText={`Welcome, ${user?.fullName}`}
bottomRightText={user?.email}
/>
</div>
<div id="app" data-section="app" className="min-h-screen py-20 px-4 bg-gradient-to-br from-purple-50 via-white to-blue-50 dark:from-gray-950 dark:via-gray-900 dark:to-gray-950">
<div className="max-w-6xl mx-auto">
{/* Header with Profile */}
<div className="flex items-center justify-between mb-12">
<div className="flex items-center gap-4">
<div className="w-16 h-16 bg-gradient-to-r from-purple-600 to-blue-600 rounded-full flex items-center justify-center">
<ChefHat size={32} className="text-white" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">Welcome back!</h1>
<p className="text-gray-600 dark:text-gray-400">{user?.email}</p>
</div>
</div>
<div className="flex gap-2">
<button
onClick={() => setShowProfile(!showProfile)}
className="p-3 bg-white dark:bg-gray-800 rounded-full shadow-lg hover:shadow-xl transition-shadow"
>
<User size={20} className="text-gray-600 dark:text-gray-300" />
</button>
<button
onClick={handleLogout}
className="p-3 bg-red-500/10 hover:bg-red-500/20 rounded-full transition-colors"
>
<LogOut size={20} className="text-red-600" />
</button>
</div>
</div>
{/* Profile Card */}
{showProfile && (
<div className="mb-8 backdrop-blur-xl bg-white/10 dark:bg-white/5 border border-white/20 dark:border-white/10 rounded-3xl p-8 shadow-xl">
<div className="flex items-center justify-between mb-6">
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">Your Profile</h2>
<button onClick={() => setShowProfile(false)}>
<X size={24} className="text-gray-600 dark:text-gray-300" />
</button>
</div>
<div className="grid md:grid-cols-3 gap-6">
<div className="bg-gradient-to-br from-purple-500/20 to-blue-500/20 rounded-2xl p-6">
<p className="text-gray-600 dark:text-gray-400 text-sm">Full Name</p>
<p className="text-xl font-bold text-gray-900 dark:text-white">{user?.fullName}</p>
</div>
<div className="bg-gradient-to-br from-purple-500/20 to-blue-500/20 rounded-2xl p-6">
<p className="text-gray-600 dark:text-gray-400 text-sm">Email</p>
<p className="text-xl font-bold text-gray-900 dark:text-white break-all">{user?.email}</p>
</div>
<div className="bg-gradient-to-br from-purple-500/20 to-blue-500/20 rounded-2xl p-6">
<p className="text-gray-600 dark:text-gray-400 text-sm">Saved Recipes</p>
<p className="text-xl font-bold text-gray-900 dark:text-white">{savedRecipes.length}</p>
</div>
</div>
<button className="mt-6 w-full py-3 bg-gradient-to-r from-purple-600 to-blue-600 hover:from-purple-700 hover:to-blue-700 text-white rounded-xl font-semibold flex items-center justify-center gap-2 transition-all">
<Settings size={20} />
Account Settings
</button>
</div>
)}
{/* Main Generator Section */}
<div className="grid lg:grid-cols-3 gap-8">
{/* Left - Ingredient Input */}
<div className="lg:col-span-1">
<div className="backdrop-blur-xl bg-white/10 dark:bg-white/5 border border-white/20 dark:border-white/10 rounded-3xl p-8 shadow-xl sticky top-24">
<h3 className="text-xl font-bold mb-6 text-gray-900 dark:text-white flex items-center gap-2">
<Plus size={24} />
Your Ingredients
</h3>
{/* Input */}
<div className="flex gap-2 mb-6">
<input
type="text"
value={currentInput}
onChange={(e) => setCurrentInput(e.target.value)}
onKeyPress={handleKeyPress}
placeholder="e.g., chicken"
className="flex-1 px-4 py-2.5 bg-white/10 border border-white/20 rounded-xl focus:outline-none focus:border-purple-500 dark:bg-white/5 dark:border-white/10 text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400"
/>
<button
onClick={addIngredient}
className="px-4 py-2.5 bg-gradient-to-r from-purple-600 to-blue-600 hover:from-purple-700 hover:to-blue-700 text-white rounded-xl font-semibold transition-all"
>
Add
</button>
</div>
{/* Ingredients List */}
{ingredients.length > 0 && (
<div className="mb-8">
<h4 className="font-semibold text-gray-900 dark:text-white mb-3">Added ({ingredients.length}):</h4>
<div className="space-y-2">
{ingredients.map((ingredient, index) => (
<div
key={index}
className="flex items-center justify-between bg-gradient-to-r from-purple-500/20 to-blue-500/20 px-4 py-2 rounded-xl"
>
<span className="text-gray-900 dark:text-white font-medium">{ingredient}</span>
<button
onClick={() => removeIngredient(index)}
className="text-red-500 hover:text-red-600 transition-colors"
>
<X size={18} />
</button>
</div>
))}
</div>
</div>
)}
{/* Generate Button */}
<button
onClick={generateRecipes}
disabled={loading || ingredients.length === 0}
className="w-full py-3 bg-gradient-to-r from-green-500 to-emerald-500 hover:from-green-600 hover:to-emerald-600 disabled:opacity-50 disabled:cursor-not-allowed text-white rounded-xl font-semibold flex items-center justify-center gap-2 transition-all group"
>
<Sparkles size={20} className="group-hover:rotate-12 transition-transform" />
{loading ? 'Generating...' : 'Generate Recipes'}
</button>
</div>
</div>
{/* Right - Recipes Display */}
<div className="lg:col-span-2">
{/* Toggle Buttons */}
<div className="flex gap-2 mb-6">
<button
onClick={() => setShowSavedOnly(false)}
className={`px-6 py-3 rounded-xl font-semibold transition-all ${
!showSavedOnly
? 'bg-gradient-to-r from-purple-600 to-blue-600 text-white'
: 'bg-white/10 dark:bg-white/5 border border-white/20 text-gray-900 dark:text-white'
}`}
>
Generated ({recipes.length})
</button>
<button
onClick={() => setShowSavedOnly(true)}
className={`px-6 py-3 rounded-xl font-semibold transition-all flex items-center gap-2 ${
showSavedOnly
? 'bg-gradient-to-r from-purple-600 to-blue-600 text-white'
: 'bg-white/10 dark:bg-white/5 border border-white/20 text-gray-900 dark:text-white'
}`}
>
<Heart size={18} />
Saved ({savedRecipes.length})
</button>
</div>
{/* Recipes Grid */}
{displayRecipes.length > 0 ? (
<div className="space-y-4">
{displayRecipes.map((recipe, index) => (
<div
key={index}
className="backdrop-blur-xl bg-white/10 dark:bg-white/5 border border-white/20 dark:border-white/10 rounded-2xl p-6 shadow-lg hover:shadow-xl transition-all group"
>
<div className="flex items-start justify-between mb-4">
<div className="flex-1">
<h4 className="text-xl font-bold text-gray-900 dark:text-white mb-2 group-hover:text-purple-600 transition-colors">
{recipe.name}
</h4>
<p className="text-gray-600 dark:text-gray-300 text-sm mb-3">
{recipe.description}
</p>
</div>
<button
onClick={() => saveRecipe(recipe)}
className="p-2 hover:bg-red-500/20 rounded-full transition-colors"
>
<Heart size={20} className={savedRecipes.some(r => r.name === recipe.name) ? 'fill-red-500 text-red-500' : 'text-gray-400'} />
</button>
</div>
<div className="grid md:grid-cols-2 gap-4 mb-4">
<div>
<h5 className="font-semibold text-gray-900 dark:text-white text-sm mb-2">Ingredients:</h5>
<ul className="space-y-1">
{recipe.ingredients?.slice(0, 4).map((ing: string, i: number) => (
<li key={i} className="text-sm text-gray-600 dark:text-gray-300 flex items-center gap-2">
<span className="w-1.5 h-1.5 bg-purple-500 rounded-full"></span>
{ing}
</li>
))}
{recipe.ingredients?.length > 4 && (
<li className="text-sm text-gray-500 dark:text-gray-400">+{recipe.ingredients.length - 4} more</li>
)}
</ul>
</div>
<div className="flex items-center justify-between text-sm bg-gradient-to-br from-purple-500/20 to-blue-500/20 rounded-xl p-3">
<div className="flex items-center gap-1 text-gray-600 dark:text-gray-300">
<Clock size={16} />
<span>{recipe.cookTime || 30} mins</span>
</div>
<div className="flex items-center gap-1 text-gray-600 dark:text-gray-300">
<Users2 size={16} />
<span>Serves {recipe.servings || 2}</span>
</div>
</div>
</div>
<p className="text-sm text-gray-600 dark:text-gray-300 line-clamp-2">
{recipe.instructions}
</p>
</div>
))}
</div>
) : (
<div className="backdrop-blur-xl bg-white/10 dark:bg-white/5 border border-white/20 dark:border-white/10 rounded-3xl p-12 text-center">
<Sparkles size={48} className="mx-auto mb-4 text-purple-400 opacity-50" />
<p className="text-gray-600 dark:text-gray-300">
{showSavedOnly
? "No saved recipes yet. Generate some and save your favorites!"
: "Add ingredients and generate recipes to get started"}
</p>
</div>
)}
</div>
</div>
</div>
</div>
<div id="footer" data-section="footer">
<FooterMedia
imageSrc="https://images.unsplash.com/photo-1495521821757-a1efb6729352?w=1920&q=80&_wi=3"
imageAlt="Footer background"
columns={[
{
title: "App", items: [
{ label: "Recipe Generator", href: "/app" },
{ label: "My Recipes", href: "/app" },
{ label: "Settings", href: "/app" }
]
},
{
title: "Account", items: [
{ label: "Profile", href: "/app" },
{ label: "Preferences", href: "/app" },
{ label: "Security", href: "/app" }
]
},
{
title: "Support", items: [
{ label: "Help Center", href: "/" },
{ label: "Privacy Policy", href: "/" },
{ label: "Terms of Service", href: "/" }
]
}
]}
logoText="EasyRecipes"
copyrightText="© 2025 EasyRecipes. All rights reserved."
/>
</div>
</ThemeProvider>
);
}

298
src/app/auth/page.tsx Normal file
View File

@@ -0,0 +1,298 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarStyleFullscreen from '@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen';
import { useState } from "react";
import Link from "next/link";
import { Mail, Lock, User, Eye, EyeOff, ArrowRight, CheckCircle, AlertCircle } from "lucide-react";
export default function AuthPage() {
const [isLogin, setIsLogin] = useState(true);
const [showPassword, setShowPassword] = useState(false);
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState<{ type: 'success' | 'error' | ''; text: string }>({ type: '', text: '' });
const [formData, setFormData] = useState({
email: '',
password: '',
confirmPassword: '',
fullName: ''
});
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setMessage({ type: '', text: '' });
try {
const endpoint = isLogin ? '/api/auth/login' : '/api/auth/signup';
const body = isLogin
? { email: formData.email, password: formData.password }
: { email: formData.email, password: formData.password, fullName: formData.fullName };
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
const data = await response.json();
if (response.ok) {
setMessage({ type: 'success', text: isLogin ? 'Login successful!' : 'Account created successfully!' });
setTimeout(() => {
window.location.href = '/app';
}, 1500);
} else {
setMessage({ type: 'error', text: data.error || 'Something went wrong' });
}
} catch (error) {
setMessage({ type: 'error', text: 'Connection error. Please try again.' });
} finally {
setLoading(false);
}
};
const handleForgotPassword = async () => {
if (!formData.email) {
setMessage({ type: 'error', text: 'Please enter your email address' });
return;
}
setLoading(true);
try {
const response = await fetch('/api/auth/forgot-password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: formData.email })
});
if (response.ok) {
setMessage({ type: 'success', text: 'Recovery email sent! Check your inbox.' });
} else {
setMessage({ type: 'error', text: 'Email not found' });
}
} catch (error) {
setMessage({ type: 'error', text: 'Failed to send recovery email' });
} finally {
setLoading(false);
}
};
return (
<ThemeProvider
defaultButtonVariant="expand-hover"
defaultTextAnimation="entrance-slide"
borderRadius="pill"
contentWidth="mediumLarge"
sizing="mediumLargeSizeLargeTitles"
background="none"
cardStyle="glass-elevated"
primaryButtonStyle="gradient"
secondaryButtonStyle="glass"
headingFontWeight="semibold"
>
<div id="nav" data-section="nav">
<NavbarStyleFullscreen
brandName="EasyRecipes"
navItems={[
{ name: "Home", id: "/" },
{ name: "Features", id: "/#features" },
{ name: "Auth", id: "/auth" },
{ name: "App", id: "/app" },
{ name: "Contact", id: "/#contact" }
]}
bottomLeftText="Secure Login"
bottomRightText="hello@easyrecipes.com"
/>
</div>
<div id="auth" data-section="auth" className="min-h-screen flex items-center justify-center py-12 px-4">
<div className="w-full max-w-md">
{/* Liquid Glass Card */}
<div className="backdrop-blur-xl bg-white/10 dark:bg-white/5 border border-white/20 dark:border-white/10 rounded-3xl p-8 shadow-2xl">
{/* Header */}
<div className="text-center mb-8">
<h1 className="text-3xl font-bold mb-2 text-transparent bg-clip-text bg-gradient-to-r from-purple-600 to-blue-600">
{isLogin ? 'Welcome Back' : 'Join EasyRecipes'}
</h1>
<p className="text-gray-600 dark:text-gray-300">
{isLogin ? 'Sign in to your account' : 'Create your account to get started'}
</p>
</div>
{/* Message Display */}
{message.text && (
<div className={`mb-6 p-4 rounded-xl flex items-center gap-3 ${
message.type === 'success'
? 'bg-green-500/20 border border-green-500/50 text-green-700 dark:text-green-300'
: 'bg-red-500/20 border border-red-500/50 text-red-700 dark:text-red-300'
}`}>
{message.type === 'success' ? (
<CheckCircle size={20} />
) : (
<AlertCircle size={20} />
)}
<span>{message.text}</span>
</div>
)}
{/* Form */}
<form onSubmit={handleSubmit} className="space-y-4">
{!isLogin && (
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Full Name
</label>
<div className="relative">
<User className="absolute left-4 top-3.5 text-gray-400" size={20} />
<input
type="text"
name="fullName"
value={formData.fullName}
onChange={handleInputChange}
placeholder="John Doe"
className="w-full pl-12 pr-4 py-3 bg-white/10 border border-white/20 rounded-xl focus:outline-none focus:border-purple-500 dark:bg-white/5 dark:border-white/10 text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400"
required
/>
</div>
</div>
)}
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Email Address
</label>
<div className="relative">
<Mail className="absolute left-4 top-3.5 text-gray-400" size={20} />
<input
type="email"
name="email"
value={formData.email}
onChange={handleInputChange}
placeholder="you@example.com"
className="w-full pl-12 pr-4 py-3 bg-white/10 border border-white/20 rounded-xl focus:outline-none focus:border-purple-500 dark:bg-white/5 dark:border-white/10 text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400"
required
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Password
</label>
<div className="relative">
<Lock className="absolute left-4 top-3.5 text-gray-400" size={20} />
<input
type={showPassword ? 'text' : 'password'}
name="password"
value={formData.password}
onChange={handleInputChange}
placeholder="Enter your password"
className="w-full pl-12 pr-12 py-3 bg-white/10 border border-white/20 rounded-xl focus:outline-none focus:border-purple-500 dark:bg-white/5 dark:border-white/10 text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400"
required
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-4 top-3.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
>
{showPassword ? <EyeOff size={20} /> : <Eye size={20} />}
</button>
</div>
</div>
{!isLogin && (
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Confirm Password
</label>
<div className="relative">
<Lock className="absolute left-4 top-3.5 text-gray-400" size={20} />
<input
type={showPassword ? 'text' : 'password'}
name="confirmPassword"
value={formData.confirmPassword}
onChange={handleInputChange}
placeholder="Confirm your password"
className="w-full pl-12 pr-12 py-3 bg-white/10 border border-white/20 rounded-xl focus:outline-none focus:border-purple-500 dark:bg-white/5 dark:border-white/10 text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400"
required
/>
</div>
</div>
)}
{/* Forgot Password */}
{isLogin && (
<div className="text-right">
<button
type="button"
onClick={handleForgotPassword}
className="text-sm text-purple-600 dark:text-purple-400 hover:text-purple-700 dark:hover:text-purple-300 transition-colors"
>
Forgot password?
</button>
</div>
)}
{/* Submit Button */}
<button
type="submit"
disabled={loading}
className="w-full py-3 bg-gradient-to-r from-purple-600 to-blue-600 hover:from-purple-700 hover:to-blue-700 disabled:opacity-50 text-white font-semibold rounded-xl flex items-center justify-center gap-2 transition-all duration-300 group"
>
{loading ? 'Processing...' : isLogin ? 'Sign In' : 'Create Account'}
{!loading && <ArrowRight size={20} className="group-hover:translate-x-1 transition-transform" />}
</button>
</form>
{/* Toggle Auth Mode */}
<div className="mt-6 text-center">
<p className="text-gray-600 dark:text-gray-400">
{isLogin ? "Don't have an account? " : 'Already have an account? '}
<button
onClick={() => setIsLogin(!isLogin)}
className="text-purple-600 dark:text-purple-400 font-semibold hover:text-purple-700 dark:hover:text-purple-300 transition-colors"
>
{isLogin ? 'Sign Up' : 'Sign In'}
</button>
</p>
</div>
{/* Divider */}
<div className="my-6 flex items-center gap-3">
<div className="flex-1 h-px bg-white/20"></div>
<span className="text-sm text-gray-500 dark:text-gray-400">or</span>
<div className="flex-1 h-px bg-white/20"></div>
</div>
{/* OAuth Buttons */}
<div className="space-y-3">
<button
type="button"
className="w-full py-2.5 bg-white/5 dark:bg-white/5 border border-white/20 hover:border-white/40 rounded-xl text-gray-900 dark:text-white font-medium transition-all duration-300 flex items-center justify-center gap-2"
>
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" />
<path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" />
<path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" />
<path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" />
</svg>
Continue with Google
</button>
</div>
</div>
{/* Security Note */}
<div className="mt-8 p-4 bg-blue-500/10 border border-blue-500/30 rounded-xl">
<p className="text-sm text-blue-700 dark:text-blue-300 text-center">
🔒 Your data is encrypted and secure. We never share your information.
</p>
</div>
</div>
</div>
</ThemeProvider>
);
}

114
src/app/contact/page.tsx Normal file
View File

@@ -0,0 +1,114 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarLayoutFloatingInline from '@/components/navbar/NavbarLayoutFloatingInline';
import ContactCenter from '@/components/sections/contact/ContactCenter';
import TextAbout from '@/components/sections/about/TextAbout';
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
import { Mail, Heart, Sparkles } from "lucide-react";
export default function ContactPage() {
return (
<ThemeProvider
defaultButtonVariant="hover-magnetic"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="mediumLarge"
sizing="mediumLargeSizeLargeTitles"
background="floatingGradient"
cardStyle="glass-elevated"
primaryButtonStyle="radial-glow"
secondaryButtonStyle="glass"
headingFontWeight="semibold"
>
<div id="nav" data-section="nav">
<NavbarLayoutFloatingInline
brandName="EasyRecipes"
navItems={[
{ name: "Home", id: "/" },
{ name: "Features", id: "/features" },
{ name: "Download", id: "/download" },
{ name: "Generate", id: "/generate" },
{ name: "Contact", id: "/contact" }
]}
button={{ text: "Get Started", href: "/download" }}
animateOnLoad={true}
/>
</div>
<div id="contact-main" data-section="contact-main">
<ContactCenter
tag="Get in Touch"
title="We'd Love to Hear From You"
description="Have feedback, questions, or feature requests? Contact our team and we'll get back to you within 24 hours. We're always excited to connect with our community!"
tagIcon={Mail}
background={{ variant: "sparkles-gradient" }}
useInvertedBackground={false}
inputPlaceholder="Enter your email"
buttonText="Send Message"
onSubmit={(email) => console.log('Contact request:', email)}
/>
</div>
<div id="about-contact" data-section="about-contact">
<TextAbout
tag="Connect With Us"
tagIcon={Heart}
title="Our support team is dedicated to helping you get the most out of EasyRecipes. Reach out anytime for assistance, feedback, or partnership inquiries."
useInvertedBackground={true}
buttons={[
{ text: "Email Us", href: "#" },
{ text: "Follow Us", href: "#" }
]}
/>
</div>
<div id="newsletter" data-section="newsletter">
<ContactCenter
tag="Stay Updated"
title="Subscribe to Our Newsletter"
description="Get weekly AI recipe ideas, cooking tips, and exclusive updates about new EasyRecipes features delivered to your inbox."
tagIcon={Sparkles}
background={{ variant: "radial-gradient" }}
useInvertedBackground={false}
inputPlaceholder="Your email address"
buttonText="Subscribe"
termsText="We respect your privacy and will never share your email. Unsubscribe anytime."
onSubmit={(email) => console.log('Newsletter signup:', email)}
/>
</div>
<div id="footer" data-section="footer">
<FooterBaseReveal
columns={[
{
title: "Product", items: [
{ label: "Features", href: "/features" },
{ label: "Download", href: "/download" },
{ label: "Pricing", href: "/" },
{ label: "Help Center", href: "#" }
]
},
{
title: "Company", items: [
{ label: "About Us", href: "/" },
{ label: "Careers", href: "#" },
{ label: "Blog", href: "#" },
{ label: "Press", href: "#" }
]
},
{
title: "Support", items: [
{ label: "Documentation", href: "#" },
{ label: "Community", href: "#" },
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" }
]
}
]}
copyrightText="© 2025 EasyRecipes | AI-Powered Cooking Made Easy"
/>
</div>
</ThemeProvider>
);
}

114
src/app/download/page.tsx Normal file
View File

@@ -0,0 +1,114 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarLayoutFloatingInline from '@/components/navbar/NavbarLayoutFloatingInline';
import HeroSignup from '@/components/sections/hero/HeroSignup';
import SocialProofOne from '@/components/sections/socialProof/SocialProofOne';
import ContactCenter from '@/components/sections/contact/ContactCenter';
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
import { Download, Users, Sparkles } from "lucide-react";
export default function DownloadPage() {
return (
<ThemeProvider
defaultButtonVariant="hover-magnetic"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="mediumLarge"
sizing="mediumLargeSizeLargeTitles"
background="floatingGradient"
cardStyle="glass-elevated"
primaryButtonStyle="radial-glow"
secondaryButtonStyle="glass"
headingFontWeight="semibold"
>
<div id="nav" data-section="nav">
<NavbarLayoutFloatingInline
brandName="EasyRecipes"
navItems={[
{ name: "Home", id: "/" },
{ name: "Features", id: "/features" },
{ name: "Download", id: "/download" },
{ name: "Generate", id: "/generate" },
{ name: "Contact", id: "/contact" }
]}
button={{ text: "Get Started", href: "/download" }}
animateOnLoad={true}
/>
</div>
<div id="hero-download" data-section="hero-download">
<HeroSignup
background={{ variant: "sparkles-gradient" }}
tag="Download Now"
tagIcon={Download}
title="Get EasyRecipes on Your Phone"
description="Download the EasyRecipes app and start creating amazing AI-powered recipes today. Available on iOS, Android, and web."
inputPlaceholder="Enter your email for download link"
buttonText="Send Download Link"
onSubmit={(email) => console.log('Download request:', email)}
/>
</div>
<div id="social-proof" data-section="social-proof">
<SocialProofOne
names={["Apple App Store", "Google Play Store", "Amazon Appstore", "Web Browser"]}
title="Available Everywhere"
description="Download EasyRecipes from your preferred platform"
tag="Multi-Platform"
tagIcon={Users}
textboxLayout="default"
useInvertedBackground={true}
showCard={true}
speed={40}
/>
</div>
<div id="contact-download" data-section="contact-download">
<ContactCenter
tag="Questions?"
title="Need Help Getting Started?"
description="Have questions about downloading or using EasyRecipes? Our support team is here to help."
tagIcon={Sparkles}
background={{ variant: "radial-gradient" }}
useInvertedBackground={false}
inputPlaceholder="Your email address"
buttonText="Contact Support"
onSubmit={(email) => console.log('Support request:', email)}
/>
</div>
<div id="footer" data-section="footer">
<FooterBaseReveal
columns={[
{
title: "Product", items: [
{ label: "Features", href: "/features" },
{ label: "Download", href: "/download" },
{ label: "Pricing", href: "/" },
{ label: "Help Center", href: "#" }
]
},
{
title: "Company", items: [
{ label: "About Us", href: "/" },
{ label: "Careers", href: "#" },
{ label: "Blog", href: "#" },
{ label: "Press", href: "#" }
]
},
{
title: "Support", items: [
{ label: "Documentation", href: "#" },
{ label: "Community", href: "#" },
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" }
]
}
]}
copyrightText="© 2025 EasyRecipes | AI-Powered Cooking Made Easy"
/>
</div>
</ThemeProvider>
);
}

143
src/app/features/page.tsx Normal file
View File

@@ -0,0 +1,143 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarLayoutFloatingInline from '@/components/navbar/NavbarLayoutFloatingInline';
import FeatureCardEight from '@/components/sections/feature/FeatureCardEight';
import MetricCardEleven from '@/components/sections/metrics/MetricCardEleven';
import ContactCenter from '@/components/sections/contact/ContactCenter';
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
import { Sparkles, TrendingUp, Zap } from "lucide-react";
export default function FeaturesPage() {
return (
<ThemeProvider
defaultButtonVariant="hover-magnetic"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="mediumLarge"
sizing="mediumLargeSizeLargeTitles"
background="floatingGradient"
cardStyle="glass-elevated"
primaryButtonStyle="radial-glow"
secondaryButtonStyle="glass"
headingFontWeight="semibold"
>
<div id="nav" data-section="nav">
<NavbarLayoutFloatingInline
brandName="EasyRecipes"
navItems={[
{ name: "Home", id: "/" },
{ name: "Features", id: "/features" },
{ name: "Download", id: "/download" },
{ name: "Generate", id: "/generate" },
{ name: "Contact", id: "/contact" }
]}
button={{ text: "Get Started", href: "/download" }}
animateOnLoad={true}
/>
</div>
<div id="features-timeline" data-section="features-timeline">
<FeatureCardEight
features={[
{
id: 1,
title: "Scan Your Ingredients", description: "Point your camera at groceries or pantry items. Our AI recognizes ingredients instantly and adds them to your smart pantry with full nutritional data.", imageSrc: "https://images.unsplash.com/photo-1559827260-dc66d52bef19?w=600&q=80&_wi=4", imageAlt: "Ingredient scanning step"
},
{
id: 2,
title: "Get AI-Powered Suggestions", description: "Based on your ingredients, diet, and taste preferences, our AI generates personalized recipe recommendations instantly. Learn why ingredients work together.", imageSrc: "https://images.unsplash.com/photo-1546069901-ba9599a7e63c?w=600&q=80&_wi=4", imageAlt: "AI recipe suggestions"
},
{
id: 3,
title: "Manage Your Smart Pantry", description: "Track ingredient quantities and expiration dates. Get smart notifications before items expire and receive shopping recommendations based on your cooking habits.", imageSrc: "https://images.unsplash.com/photo-1556740738-b6a63e27c4df?w=600&q=80&_wi=3", imageAlt: "Smart pantry management"
},
{
id: 4,
title: "Cook & Learn", description: "Follow step-by-step recipes with timing guidance, ingredient ratios, and cooking techniques. Share your creations and discover recipes from other home chefs.", imageSrc: "https://images.unsplash.com/photo-1495521821757-a1efb6729352?w=600&q=80&_wi=2", imageAlt: "Cooking and learning"
}
]}
title="How EasyRecipes Works"
description="Four simple steps to amazing meals"
tag="Step-by-Step Guide"
tagIcon={Zap}
textboxLayout="default"
useInvertedBackground={false}
buttonAnimation="slide-up"
/>
</div>
<div id="metrics" data-section="metrics">
<MetricCardEleven
metrics={[
{
id: "1", value: "500K+", title: "Recipes Generated", description: "AI-powered recipes created monthly by our users", imageSrc: "https://images.unsplash.com/photo-1546069901-ba9599a7e63c?w=600&q=80&_wi=5", imageAlt: "Recipes generated"
},
{
id: "2", value: "95%", title: "Food Waste Reduced", description: "Average reduction in household food waste", imageSrc: "https://images.unsplash.com/photo-1556740738-b6a63e27c4df?w=600&q=80&_wi=4", imageAlt: "Waste reduction"
},
{
id: "3", value: "2.5M+", title: "Ingredients Scanned", description: "Accurately identified by our scanner technology", imageSrc: "https://images.unsplash.com/photo-1559827260-dc66d52bef19?w=600&q=80&_wi=5", imageAlt: "Ingredients scanned"
},
{
id: "4", value: "4.8★", title: "User Rating", description: "Average rating across all app stores", imageSrc: "https://images.unsplash.com/photo-1495521821757-a1efb6729352?w=600&q=80&_wi=3", imageAlt: "User satisfaction"
}
]}
title="EasyRecipes by the Numbers"
description="Join millions of home chefs worldwide"
tag="Impact"
tagIcon={TrendingUp}
textboxLayout="default"
useInvertedBackground={true}
animationType="slide-up"
/>
</div>
<div id="contact-features" data-section="contact-features">
<ContactCenter
tag="Ready to Cook?"
title="Start Your AI Cooking Journey Today"
description="Get instant access to personalized recipes, smart pantry management, and culinary inspiration."
tagIcon={Sparkles}
background={{ variant: "sparkles-gradient" }}
useInvertedBackground={false}
inputPlaceholder="Enter your email"
buttonText="Get Started Free"
onSubmit={(email) => console.log('Email:', email)}
/>
</div>
<div id="footer" data-section="footer">
<FooterBaseReveal
columns={[
{
title: "Product", items: [
{ label: "Features", href: "/features" },
{ label: "Download", href: "/download" },
{ label: "Pricing", href: "/" },
{ label: "Help Center", href: "#" }
]
},
{
title: "Company", items: [
{ label: "About Us", href: "/" },
{ label: "Careers", href: "#" },
{ label: "Blog", href: "#" },
{ label: "Press", href: "#" }
]
},
{
title: "Support", items: [
{ label: "Documentation", href: "#" },
{ label: "Community", href: "#" },
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" }
]
}
]}
copyrightText="© 2025 EasyRecipes | AI-Powered Cooking Made Easy"
/>
</div>
</ThemeProvider>
);
}

266
src/app/generate/page.tsx Normal file
View File

@@ -0,0 +1,266 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarLayoutFloatingInline from '@/components/navbar/NavbarLayoutFloatingInline';
import HeroBillboardTestimonial from '@/components/sections/hero/HeroBillboardTestimonial';
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
import { Sparkles, Mail } from "lucide-react";
import { useState } from "react";
export default function GeneratePage() {
const [ingredients, setIngredients] = useState<string[]>([]);
const [currentInput, setCurrentInput] = useState("");
const [recipes, setRecipes] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [userEmail, setUserEmail] = useState("");
const handleGmailLogin = async () => {
try {
// Simulate Gmail OAuth flow
const response = await fetch("/api/auth/gmail", {
method: "POST"});
if (response.ok) {
const data = await response.json();
setUserEmail(data.email);
setIsLoggedIn(true);
}
} catch (error) {
console.error("Gmail login failed:", error);
}
};
const addIngredient = () => {
if (currentInput.trim()) {
setIngredients([...ingredients, currentInput.trim()]);
setCurrentInput("");
}
};
const removeIngredient = (index: number) => {
setIngredients(ingredients.filter((_, i) => i !== index));
};
const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === "Enter") {
e.preventDefault();
addIngredient();
}
};
const generateRecipes = async () => {
if (ingredients.length === 0) {
alert("Please add at least one ingredient");
return;
}
setLoading(true);
try {
const response = await fetch("/api/recipes/generate", {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ingredients }),
});
if (response.ok) {
const data = await response.json();
setRecipes(data.recipes || []);
}
} catch (error) {
console.error("Recipe generation failed:", error);
} finally {
setLoading(false);
}
};
return (
<ThemeProvider
defaultButtonVariant="hover-magnetic"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="mediumLarge"
sizing="mediumLargeSizeLargeTitles"
background="floatingGradient"
cardStyle="glass-elevated"
primaryButtonStyle="radial-glow"
secondaryButtonStyle="glass"
headingFontWeight="semibold"
>
<div id="nav" data-section="nav">
<NavbarLayoutFloatingInline
brandName="EasyRecipes"
navItems={[
{ name: "Home", id: "/" },
{ name: "Features", id: "/features" },
{ name: "Download", id: "/download" },
{ name: "Generate", id: "/generate" },
{ name: "Contact", id: "/contact" }
]}
button={{ text: "Get Started", href: "/download" }}
animateOnLoad={true}
/>
</div>
<div id="hero" data-section="hero">
<HeroBillboardTestimonial
title="Generate Recipes from Your Ingredients"
description="Enter the ingredients you have on hand and let our AI create delicious recipe suggestions just for you. Create amazing meals with what you already have!"
background={{ variant: "sparkles-gradient" }}
useInvertedBackground={false}
testimonials={[
{
name: "Sarah Johnson", handle: "Home Chef", testimonial: "This app changed how I cook! No more food waste.", rating: 5
}
]}
/>
</div>
<div id="generator" data-section="generator" className="w-full py-20 px-4">
<div className="max-w-4xl mx-auto">
{/* Login Section */}
{!isLoggedIn && (
<div className="mb-12 text-center">
<h2 className="text-2xl font-bold mb-4">Sign in to Get Started</h2>
<button
onClick={handleGmailLogin}
className="flex items-center justify-center gap-2 bg-blue-600 hover:bg-blue-700 text-white px-8 py-3 rounded-lg font-semibold transition-colors"
>
<Mail size={20} />
Sign in with Gmail
</button>
</div>
)}
{/* Generator Section */}
{isLoggedIn && (
<div className="space-y-8">
<div className="text-center mb-8">
<p className="text-lg text-gray-600 mb-2">Logged in as: {userEmail}</p>
</div>
{/* Ingredient Input */}
<div className="bg-white dark:bg-gray-800 rounded-lg p-8 shadow-lg">
<h3 className="text-xl font-bold mb-4">Add Your Ingredients</h3>
<div className="flex gap-2 mb-4">
<input
type="text"
value={currentInput}
onChange={(e) => setCurrentInput(e.target.value)}
onKeyPress={handleKeyPress}
placeholder="e.g., chicken, tomatoes, garlic"
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"
/>
<button
onClick={addIngredient}
className="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-semibold transition-colors"
>
Add
</button>
</div>
{/* Ingredients List */}
{ingredients.length > 0 && (
<div className="mb-6">
<h4 className="font-semibold mb-3">Your Ingredients:</h4>
<div className="flex flex-wrap gap-2">
{ingredients.map((ingredient, index) => (
<div
key={index}
className="flex items-center gap-2 bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-100 px-4 py-2 rounded-full"
>
<span>{ingredient}</span>
<button
onClick={() => removeIngredient(index)}
className="text-blue-600 dark:text-blue-300 hover:text-blue-800 font-bold"
>
×
</button>
</div>
))}
</div>
</div>
)}
{/* Generate Button */}
<button
onClick={generateRecipes}
disabled={loading || ingredients.length === 0}
className="w-full px-6 py-3 bg-green-600 hover:bg-green-700 disabled:bg-gray-400 text-white rounded-lg font-semibold transition-colors"
>
{loading ? "Generating..." : "Generate Recipes"}
</button>
</div>
{/* Recipes Results */}
{recipes.length > 0 && (
<div className="space-y-4">
<h3 className="text-2xl font-bold mb-6">AI-Generated Recipes</h3>
{recipes.map((recipe, index) => (
<div
key={index}
className="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-lg"
>
<h4 className="text-xl font-bold mb-2">{recipe.name}</h4>
<p className="text-gray-600 dark:text-gray-300 mb-4">
{recipe.description}
</p>
<div className="mb-4">
<h5 className="font-semibold mb-2">Ingredients:</h5>
<ul className="list-disc pl-5 space-y-1 text-gray-700 dark:text-gray-300">
{recipe.ingredients?.map((ing: string, i: number) => (
<li key={i}>{ing}</li>
))}
</ul>
</div>
<div className="mb-4">
<h5 className="font-semibold mb-2">Instructions:</h5>
<p className="text-gray-700 dark:text-gray-300">
{recipe.instructions}
</p>
</div>
<div className="flex justify-between text-sm text-gray-500">
<span> {recipe.cookTime} mins</span>
<span>👥 Serves {recipe.servings}</span>
</div>
</div>
))}
</div>
)}
</div>
)}
</div>
</div>
<div id="footer" data-section="footer">
<FooterBaseReveal
columns={[
{
title: "Product", items: [
{ label: "Features", href: "/features" },
{ label: "Download", href: "/download" },
{ label: "Pricing", href: "/" },
{ label: "Help Center", href: "#" }
]
},
{
title: "Company", items: [
{ label: "About Us", href: "/" },
{ label: "Careers", href: "#" },
{ label: "Blog", href: "#" },
{ label: "Press", href: "#" }
]
},
{
title: "Support", items: [
{ label: "Documentation", href: "#" },
{ label: "Community", href: "#" },
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" }
]
}
]}
copyrightText="© 2025 EasyRecipes | AI-Powered Cooking Made Easy"
/>
</div>
</ThemeProvider>
);
}

View File

@@ -1,5 +1,74 @@
@import "tailwindcss";
@import "./styles/variables.css";
@import "./styles/theme.css";
@import "./styles/utilities.css";
@import "./styles/base.css";
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
body {
@apply antialiased;
}
h1, h2, h3, h4, h5, h6 {
@apply font-bold;
}
}
@layer components {
.rounded-theme {
@apply rounded-2xl;
}
.rounded-theme-capped {
@apply rounded-3xl;
}
.glass {
@apply backdrop-blur-md bg-white/10 border border-white/20 rounded-2xl;
}
.glass-elevated {
@apply backdrop-blur-xl bg-white/10 dark:bg-white/5 border border-white/20 dark:border-white/10 rounded-3xl shadow-2xl;
}
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
.w-content-width {
width: var(--width-content-width);
}
.max-w-content-width {
max-width: var(--width-content-width);
}
.mask-fade-top-long {
mask-image: linear-gradient(to bottom, transparent 0%, black 20%);
-webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 20%);
}
.mask-fade-bottom {
mask-image: linear-gradient(to top, transparent 0%, black 20%);
-webkit-mask-image: linear-gradient(to top, transparent 0%, black 20%);
}
.mask-fade-left {
mask-image: linear-gradient(to right, transparent 0%, black 20%);
-webkit-mask-image: linear-gradient(to right, transparent 0%, black 20%);
}
.mask-fade-right {
mask-image: linear-gradient(to left, transparent 0%, black 20%);
-webkit-mask-image: linear-gradient(to left, transparent 0%, black 20%);
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
.no-scrollbar::-webkit-scrollbar {
display: none;
}
}

View File

@@ -1,48 +1,25 @@
import type { Metadata } from "next";
import { Halant } from "next/font/google";
import { Inter } from "next/font/google";
import { Inter_Tight } from "next/font/google";
import "./styles/variables.css";
import "./globals.css";
import { ServiceWrapper } from "@/components/ServiceWrapper";
import Tag from "@/tag/Tag";
const halant = Halant({
variable: "--font-halant", subsets: ["latin"],
weight: ["300", "400", "500", "600", "700"],
});
const inter = Inter({
variable: "--font-inter", subsets: ["latin"],
});
const interTight = Inter_Tight({
variable: "--font-inter-tight", subsets: ["latin"],
weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
});
export const metadata: Metadata = {
title: "FoodHub - Fast Food Delivery App", description: "Order delicious meals from top restaurants and enjoy fast delivery. Browse hundreds of restaurants, track your order in real-time, and enjoy exclusive member discounts.", keywords: "food delivery, meal ordering, restaurant app, fast delivery, online food order", openGraph: {
title: "FoodHub - Fast Food Delivery App", description: "Order delicious meals from top restaurants with fast delivery. Download FoodHub today!", siteName: "FoodHub", type: "website"},
robots: {
index: true,
follow: true,
},
};
title: "EasyRecipes - AI-Powered Recipe Generator", description: "Generate delicious recipes from your ingredients using AI"};
export default function RootLayout({
children,
}: Readonly<{
}: {
children: React.ReactNode;
}>) {
}) {
return (
<html lang="en" suppressHydrationWarning>
<ServiceWrapper>
<body
className={`${halant.variable} ${inter.variable} ${interTight.variable} antialiased`}
>
<Tag />
{children}
<html lang="en">
<body className={inter.variable}>
{children}
<script
dangerouslySetInnerHTML={{
__html: `
@@ -1410,7 +1387,6 @@ export default function RootLayout({
}}
/>
</body>
</ServiceWrapper>
</html>
);
}

View File

@@ -1,249 +1,142 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarLayoutFloatingInline from '@/components/navbar/NavbarLayoutFloatingInline';
import HeroBillboardTestimonial from '@/components/sections/hero/HeroBillboardTestimonial';
import FeatureCardMedia from '@/components/sections/feature/FeatureCardMedia';
import ProductCardThree from '@/components/sections/product/ProductCardThree';
import NavbarStyleFullscreen from '@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen';
import HeroCarouselLogo from '@/components/sections/hero/heroCarouselLogo/HeroCarouselLogo';
import TextAbout from '@/components/sections/about/TextAbout';
import TestimonialCardFive from '@/components/sections/testimonial/TestimonialCardFive';
import PricingCardThree from '@/components/sections/pricing/PricingCardThree';
import ContactText from '@/components/sections/contact/ContactText';
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
import { Zap, CheckCircle, Star, Heart, Sparkles } from "lucide-react";
import FeatureCardMedia from '@/components/sections/feature/FeatureCardMedia';
import FooterMedia from '@/components/sections/footer/FooterMedia';
import BlurBottomBackground from '@/components/background/BlurBottomBackground';
export default function LandingPage() {
export default function HomePage() {
return (
<ThemeProvider
defaultButtonVariant="elastic-effect"
defaultTextAnimation="reveal-blur"
borderRadius="soft"
contentWidth="compact"
sizing="mediumSizeLargeTitles"
background="noise"
cardStyle="layered-gradient"
primaryButtonStyle="shadow"
defaultButtonVariant="expand-hover"
defaultTextAnimation="entrance-slide"
borderRadius="pill"
contentWidth="mediumLarge"
sizing="mediumLargeSizeLargeTitles"
background="none"
cardStyle="glass-elevated"
primaryButtonStyle="gradient"
secondaryButtonStyle="glass"
headingFontWeight="light"
headingFontWeight="semibold"
>
<div id="nav" data-section="nav">
<NavbarLayoutFloatingInline
brandName="FoodHub"
<NavbarStyleFullscreen
brandName="EasyRecipes"
navItems={[
{ name: "Home", id: "hero" },
{ name: "How It Works", id: "features" },
{ name: "Restaurants", id: "product" },
{ name: "Offers", id: "pricing" }
{ name: "Home", id: "/" },
{ name: "Features", id: "#features" },
{ name: "Auth", id: "/auth" },
{ name: "App", id: "/app" },
{ name: "Contact", id: "#contact" }
]}
button={{ text: "Order Now", href: "#hero" }}
animateOnLoad={true}
bottomLeftText="AI-Powered Recipes"
bottomRightText="hello@easyrecipes.com"
/>
</div>
<div id="hero" data-section="hero">
<HeroBillboardTestimonial
title="Delicious Food, Delivered Fast"
description="Order from your favorite restaurants and enjoy fresh meals delivered right to your door. Fast, reliable, and always delicious."
tag="Quick Delivery"
tagIcon={Zap}
tagAnimation="slide-up"
imageSrc="http://img.b2bpic.net/free-photo/side-view-family-eating-together_23-2150671588.jpg"
imageAlt="Food delivery service showcase"
mediaAnimation="slide-up"
background={{ variant: "sparkles-gradient" }}
<HeroCarouselLogo
logoText="EASYRECIPES"
description="Transform your kitchen with AI-powered recipes. Discover delicious meals from ingredients you already have."
buttons={[
{ text: "Order Now", href: "#" },
{ text: "Browse Restaurants", href: "#product" }
{ text: "Get Started", href: "/auth" },
{ text: "Learn More", href: "#features" }
]}
buttonAnimation="slide-up"
testimonials={[
slides={[
{
name: "Sarah Johnson", handle: "Regular Customer", testimonial: "Amazing app! My food arrived hot and fresh within 30 minutes.", rating: 5,
imageSrc: "http://img.b2bpic.net/free-photo/closeup-young-female-professional-making-eye-contact-against-colored-background_662251-651.jpg?_wi=1"
imageSrc: "https://images.unsplash.com/photo-1495521821757-a1efb6729352?w=1920&q=80&_wi=1", imageAlt: "Fresh ingredients"
},
{
name: "Marcus Chen", handle: "Food Lover", testimonial: "Best delivery service I've used. Great selection of restaurants!", rating: 5,
imageSrc: "http://img.b2bpic.net/free-photo/closeup-young-female-professional-making-eye-contact-against-colored-background_662251-651.jpg?_wi=2"
imageSrc: "https://images.unsplash.com/photo-1495697542231-dc1d53f6f0bb?w=1920&q=80", imageAlt: "Cooking in kitchen"
},
{
name: "Emma Wilson", handle: "Busy Professional", testimonial: "Super convenient. I order lunch here every other day!", rating: 5,
imageSrc: "http://img.b2bpic.net/free-photo/closeup-young-female-professional-making-eye-contact-against-colored-background_662251-651.jpg?_wi=3"
imageSrc: "https://images.unsplash.com/photo-1495863359367-055fb6aae5e0?w=1920&q=80", imageAlt: "Finished dish"
}
]}
testimonialRotationInterval={5000}
useInvertedBackground={false}
autoplayDelay={5000}
showDimOverlay={true}
/>
</div>
<div id="features" data-section="features">
<FeatureCardMedia
title="How It Works"
description="Get delicious meals delivered in three simple steps"
tag="Simple Process"
tagIcon={CheckCircle}
textboxLayout="default"
animationType="slide-up"
useInvertedBackground={true}
features={[
{
id: "1", tag: "Step 1", title: "Browse Restaurants", description: "Explore hundreds of restaurants and cuisines in your area. Filter by ratings, cuisine type, or delivery time.", imageSrc: "http://img.b2bpic.net/free-photo/side-view-couple-eating-pizza-doner-wrapped-lavash-served-with-french-fries-sauces-table-table_140725-12112.jpg?_wi=1", imageAlt: "Browse restaurants"
id: "1", title: "Secure Authentication", description: "Create your account with email and password. Your data is encrypted and protected with industry-standard security.", tag: "Security First", imageSrc: "https://images.unsplash.com/photo-1555949519-ef32f108e557?w=600&q=80", imageAlt: "Secure lock icon"
},
{
id: "2", tag: "Step 2", title: "Select Your Meal", description: "Browse menus, read reviews, and add your favorite dishes to your cart with just a few taps.", imageSrc: "http://img.b2bpic.net/free-photo/pagliatelle-with-meat-jte-table_140725-6761.jpg?_wi=1", imageAlt: "Select meals"
id: "2", title: "Personalized Profile", description: "Save your favorite recipes and manage your ingredient preferences. Your profile grows smarter with every recipe.", tag: "Your Kitchen", imageSrc: "https://images.unsplash.com/photo-1552664730-d307ca884978?w=600&q=80", imageAlt: "User profile"
},
{
id: "3", tag: "Step 3", title: "Fast Delivery", description: "Track your order in real-time and receive your food fresh and hot at your doorstep.", imageSrc: "http://img.b2bpic.net/free-photo/homemade-mexican-taco-boats-recipe-idea_53876-95999.jpg?_wi=1", imageAlt: "Fast delivery service"
id: "3", title: "AI Recipe Generation", description: "Enter your ingredients and let AI create personalized recipes just for you. Discover new dishes instantly.", tag: "AI Powered", imageSrc: "https://images.unsplash.com/photo-1498198788026-432a562a71cc?w=600&q=80", imageAlt: "AI technology"
},
{
id: "4", title: "Session Management", description: "Seamless login experience with secure session handling. Your preferences are remembered across devices.", tag: "Always Connected", imageSrc: "https://images.unsplash.com/photo-1460925895917-aeb19be489c7?w=600&q=80", imageAlt: "Connected devices"
},
{
id: "5", title: "Password Recovery", description: "Forgot your password? Our secure recovery system gets you back into your account quickly and safely.", tag: "Peace of Mind", imageSrc: "https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=600&q=80", imageAlt: "Recovery process"
},
{
id: "6", title: "Liquid Glass Design", description: "Beautiful, modern UI with glass-morphism effects. Every interaction feels smooth and premium.", tag: "Design", imageSrc: "https://images.unsplash.com/photo-1561070791-2526d30994b5?w=600&q=80", imageAlt: "Modern design"
}
]}
/>
</div>
<div id="product" data-section="product">
<ProductCardThree
products={[
{
id: "1", name: "Pizza Palace", price: "$15.99", imageSrc: "http://img.b2bpic.net/free-photo/side-view-couple-eating-pizza-doner-wrapped-lavash-served-with-french-fries-sauces-table-table_140725-12112.jpg?_wi=2", imageAlt: "Pizza Palace restaurant", initialQuantity: 1
},
{
id: "2", name: "Sushi Express", price: "$22.50", imageSrc: "http://img.b2bpic.net/free-photo/pagliatelle-with-meat-jte-table_140725-6761.jpg?_wi=2", imageAlt: "Sushi Express restaurant", initialQuantity: 1
},
{
id: "3", name: "Fresh Bowls", price: "$12.99", imageSrc: "http://img.b2bpic.net/free-photo/homemade-mexican-taco-boats-recipe-idea_53876-95999.jpg?_wi=2", imageAlt: "Fresh Bowls restaurant", initialQuantity: 1
}
]}
title="Featured Restaurants"
description="Discover top-rated restaurants and exclusive menu items"
tag="Popular Now"
tagIcon={Star}
textboxLayout="default"
animationType="slide-up"
title="Powerful Features for Your Kitchen"
description="Everything you need to revolutionize your cooking experience with AI and secure authentication"
textboxLayout="default"
useInvertedBackground={false}
gridVariant="three-columns-all-equal-width"
tag="Features"
/>
</div>
<div id="about" data-section="about">
<TextAbout
tag="Why FoodHub"
tagIcon={Heart}
title="We bring your favorite restaurants and cuisines to your fingertips with unbeatable speed, quality, and selection."
useInvertedBackground={true}
buttons={[
{ text: "Learn More", href: "#" }
]}
/>
</div>
<div id="testimonial" data-section="testimonial">
<TestimonialCardFive
testimonials={[
{
id: "1", name: "Jessica Martinez, Food Blogger", date: "Date: 15 Jan 2025", title: "Best delivery service in town!", quote: "I've tried many delivery apps, but FoodHub stands out with their speed and quality. The restaurants are always fresh and the drivers are professional.", tag: "Premium Member", avatarSrc: "http://img.b2bpic.net/free-photo/closeup-young-female-professional-making-eye-contact-against-colored-background_662251-651.jpg", imageSrc: "http://img.b2bpic.net/free-photo/side-view-couple-eating-pizza-doner-wrapped-lavash-served-with-french-fries-sauces-table-table_140725-12112.jpg?_wi=3"
},
{
id: "2", name: "David Thompson, Corporate Worker", date: "Date: 18 Jan 2025", title: "Perfect for lunch breaks", quote: "I use FoodHub almost every day for lunch. The variety is amazing and delivery is always on time. Highly recommended!", tag: "Regular User", avatarSrc: "http://img.b2bpic.net/free-photo/closeup-young-female-professional-making-eye-contact-against-colored-background_662251-651.jpg", imageSrc: "http://img.b2bpic.net/free-photo/pagliatelle-with-meat-jte-table_140725-6761.jpg?_wi=3"
},
{
id: "3", name: "Amanda Lee, Student", date: "Date: 20 Jan 2025", title: "Affordable and delicious", quote: "Great prices, diverse restaurant selection, and lightning-fast delivery. This app has saved me so much time during exam season!", tag: "Student Discount", avatarSrc: "http://img.b2bpic.net/free-photo/closeup-young-female-professional-making-eye-contact-against-colored-background_662251-651.jpg", imageSrc: "http://img.b2bpic.net/free-photo/homemade-mexican-taco-boats-recipe-idea_53876-95999.jpg?_wi=3"
},
{
id: "4", name: "Robert Garcia, Family Dad", date: "Date: 22 Jan 2025", title: "Family favorite", quote: "My whole family loves FoodHub. Easy to use, great restaurants, and the loyalty rewards program is fantastic!", tag: "Family Plan", avatarSrc: "http://img.b2bpic.net/free-photo/closeup-young-female-professional-making-eye-contact-against-colored-background_662251-651.jpg", imageSrc: "http://img.b2bpic.net/free-photo/side-view-couple-eating-pizza-doner-wrapped-lavash-served-with-french-fries-sauces-table-table_140725-12112.jpg?_wi=4"
},
{
id: "5", name: "Sofia Patel, Foodie", date: "Date: 24 Jan 2025", title: "Incredible variety", quote: "From street food to fine dining, FoodHub has it all. Their restaurant selection and curation is top-notch!", tag: "Food Explorer", avatarSrc: "http://img.b2bpic.net/free-photo/closeup-young-female-professional-making-eye-contact-against-colored-background_662251-651.jpg", imageSrc: "http://img.b2bpic.net/free-photo/pagliatelle-with-meat-jte-table_140725-6761.jpg?_wi=4"
},
{
id: "6", name: "Michael Chen, Busy Executive", date: "Date: 25 Jan 2025", title: "Saves me hours every week", quote: "As someone with a hectic schedule, FoodHub is a lifesaver. Consistent quality and reliability every single time.", tag: "Business User", avatarSrc: "http://img.b2bpic.net/free-photo/closeup-young-female-professional-making-eye-contact-against-colored-background_662251-651.jpg", imageSrc: "http://img.b2bpic.net/free-photo/homemade-mexican-taco-boats-recipe-idea_53876-95999.jpg?_wi=4"
}
]}
title="What Our Customers Say"
description="Thousands of happy customers enjoy fresh meals delivered daily"
tag="Reviews"
textboxLayout="default"
title="EasyRecipes: Your AI Kitchen Assistant with Secure Authentication"
useInvertedBackground={false}
/>
</div>
<div id="pricing" data-section="pricing">
<PricingCardThree
plans={[
{
id: "1", price: "Free", name: "Casual Diner", buttons: [
{ text: "Get Started", href: "#" }
],
features: [
"Full restaurant access", "Standard delivery", "Real-time tracking", "Multiple payment methods"
]
},
{
id: "2", badge: "Most Popular", badgeIcon: Sparkles,
price: "$9.99/mo", name: "Premium Member", buttons: [
{ text: "Subscribe Now", href: "#" }
],
features: [
"$2 off each order", "Free delivery on all orders", "Priority customer support", "Exclusive member restaurants", "Birthday bonus credit"
]
},
{
id: "3", price: "$19.99/mo", name: "VIP Plus", buttons: [
{ text: "Get VIP Access", href: "#" }
],
features: [
"Everything in Premium", "$5 off each order", "Free premium restaurant access", "Dedicated concierge support", "Monthly reward points"
]
}
]}
title="Special Offers & Promotions"
description="Save more with our exclusive membership plans"
tag="Limited Time"
textboxLayout="default"
animationType="slide-up"
useInvertedBackground={true}
/>
</div>
<div id="contact" data-section="contact">
<ContactText
text="Ready to satisfy your cravings? Download FoodHub today and enjoy delicious meals delivered to your door. Join thousands of happy customers!"
animationType="entrance-slide"
background={{ variant: "radial-gradient" }}
buttons={[
{ text: "Download App", href: "#" },
{ text: "Contact Us", href: "#" }
{ text: "Create Account", href: "/auth" },
{ text: "Try the App", href: "/app" }
]}
useInvertedBackground={false}
/>
</div>
<BlurBottomBackground />
<div id="footer" data-section="footer">
<FooterBaseReveal
<FooterMedia
imageSrc="https://images.unsplash.com/photo-1495521821757-a1efb6729352?w=1920&q=80&_wi=2"
imageAlt="Footer background"
columns={[
{
title: "Product", items: [
{ label: "How It Works", href: "#features" },
{ label: "Browse Restaurants", href: "#product" },
{ label: "Pricing Plans", href: "#pricing" },
{ label: "Download App", href: "#" }
{ label: "Features", href: "#features" },
{ label: "Pricing", href: "/" },
{ label: "Security", href: "/" },
{ label: "FAQ", href: "/" }
]
},
{
title: "Company", items: [
{ label: "About Us", href: "#about" },
{ label: "Careers", href: "#" },
{ label: "Blog", href: "#" },
{ label: "Press", href: "#" }
{ label: "About Us", href: "/" },
{ label: "Blog", href: "/" },
{ label: "Careers", href: "/" },
{ label: "Press", href: "/" }
]
},
{
title: "Support", items: [
{ label: "Help Center", href: "#" },
{ label: "Contact Us", href: "#contact" },
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" }
{ label: "Documentation", href: "/" },
{ label: "Contact Us", href: "/" },
{ label: "Privacy Policy", href: "/" },
{ label: "Terms of Service", href: "/" }
]
}
]}
copyrightText="© 2025 FoodHub | Delicious meals delivered fast"
logoText="EasyRecipes"
copyrightText="© 2025 EasyRecipes. All rights reserved."
/>
</div>
</ThemeProvider>

View File

@@ -10,15 +10,15 @@
--accent: #ffffff;
--background-accent: #ffffff; */
--background: #ffffff;
--card: #f9f9f9;
--foreground: #120a00e6;
--primary-cta: #ff8c42;
--background: #f8f5ff;
--card: #f1ecff;
--foreground: #1a0f3f;
--primary-cta: #8b5cf6;
--primary-cta-text: #ffffff;
--secondary-cta: #f9f9f9;
--secondary-cta: #ffffff;
--secondary-cta-text: #120a00e6;
--accent: #e2e2e2;
--background-accent: #c4c4c4;
--accent: #c4a8f9;
--background-accent: #ddd6fe;
/* text sizing - set by ThemeProvider */
/* --text-2xs: clamp(0.465rem, 0.62vw, 0.62rem);