Merge version_3 into main #4

Merged
bender merged 5 commits from version_3 into main 2026-03-04 18:11:14 +00:00
5 changed files with 276 additions and 9 deletions

View File

@@ -28,6 +28,7 @@ export default function ContactPage() {
{ 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" }}
@@ -84,13 +85,13 @@ export default function ContactPage() {
title: "Product", items: [
{ label: "Features", href: "/features" },
{ label: "Download", href: "/download" },
{ label: "Pricing", href: "#pricing" },
{ label: "Pricing", href: "/" },
{ label: "Help Center", href: "#" }
]
},
{
title: "Company", items: [
{ label: "About Us", href: "#about" },
{ label: "About Us", href: "/" },
{ label: "Careers", href: "#" },
{ label: "Blog", href: "#" },
{ label: "Press", href: "#" }

View File

@@ -29,6 +29,7 @@ export default function DownloadPage() {
{ 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" }}
@@ -84,13 +85,13 @@ export default function DownloadPage() {
title: "Product", items: [
{ label: "Features", href: "/features" },
{ label: "Download", href: "/download" },
{ label: "Pricing", href: "#pricing" },
{ label: "Pricing", href: "/" },
{ label: "Help Center", href: "#" }
]
},
{
title: "Company", items: [
{ label: "About Us", href: "#about" },
{ label: "About Us", href: "/" },
{ label: "Careers", href: "#" },
{ label: "Blog", href: "#" },
{ label: "Press", href: "#" }

View File

@@ -29,6 +29,7 @@ export default function FeaturesPage() {
{ 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" }}
@@ -113,13 +114,13 @@ export default function FeaturesPage() {
title: "Product", items: [
{ label: "Features", href: "/features" },
{ label: "Download", href: "/download" },
{ label: "Pricing", href: "#pricing" },
{ label: "Pricing", href: "/" },
{ label: "Help Center", href: "#" }
]
},
{
title: "Company", items: [
{ label: "About Us", href: "#about" },
{ label: "About Us", href: "/" },
{ label: "Careers", href: "#" },
{ label: "Blog", href: "#" },
{ label: "Press", href: "#" }

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

@@ -0,0 +1,263 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarLayoutFloatingInline from '@/components/navbar/NavbarLayoutFloatingInline';
import HeroCentered from '@/components/sections/hero/HeroCentered';
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
import { Sparkles, Mail, LogIn } 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">
<HeroCentered
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!"
tag="AI Recipe Generator"
tagIcon={Sparkles}
background={{ variant: "sparkles-gradient" }}
useInvertedBackground={false}
/>
</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

@@ -33,6 +33,7 @@ export default function LandingPage() {
{ 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" }}
@@ -209,7 +210,7 @@ export default function LandingPage() {
background={{ variant: "radial-gradient" }}
buttons={[
{ text: "Download App", href: "/download" },
{ text: "Contact Support", href: "#" }
{ text: "Contact Support", href: "/contact" }
]}
useInvertedBackground={false}
/>
@@ -222,13 +223,13 @@ export default function LandingPage() {
title: "Product", items: [
{ label: "Features", href: "/features" },
{ label: "Download", href: "/download" },
{ label: "Pricing", href: "#pricing" },
{ label: "Pricing", href: "/" },
{ label: "Help Center", href: "#" }
]
},
{
title: "Company", items: [
{ label: "About Us", href: "#about" },
{ label: "About Us", href: "/" },
{ label: "Careers", href: "#" },
{ label: "Blog", href: "#" },
{ label: "Press", href: "#" }