Merge version_5 into main #13

Merged
bender merged 1 commits from version_5 into main 2026-03-04 19:56:21 +00:00

View File

@@ -25,16 +25,27 @@ import {
User,
Users,
Zap,
ChefHat,
Flame,
Music,
Settings,
LogOut,
} from "lucide-react";
export default function LandingPage() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [showOnboarding, setShowOnboarding] = useState(false);
const [ingredients, setIngredients] = useState<string[]>([]);
const [currentInput, setCurrentInput] = useState("");
const [recipes, setRecipes] = useState<any[]>([]);
const [selectedRecipe, setSelectedRecipe] = useState<any>(null);
const [showDashboard, setShowDashboard] = useState(false);
const handleCompleteOnboarding = () => {
try {
localStorage.setItem("hasCompletedOnboarding", "true");
setShowOnboarding(false);
setShowDashboard(true);
} catch (error) {
console.error("Onboarding completion error:", error);
}
@@ -47,6 +58,10 @@ export default function LandingPage() {
localStorage.removeItem("hasCompletedOnboarding");
setIsAuthenticated(false);
setShowOnboarding(false);
setShowDashboard(false);
setIngredients([]);
setRecipes([]);
setSelectedRecipe(null);
} catch (error) {
console.error("Sign out error:", error);
}
@@ -57,7 +72,34 @@ export default function LandingPage() {
setShowOnboarding(true);
};
if (isAuthenticated && showOnboarding) {
const addIngredient = () => {
if (currentInput.trim()) {
setIngredients([...ingredients, currentInput.trim()]);
setCurrentInput("");
}
};
const removeIngredient = (index: number) => {
setIngredients(ingredients.filter((_, i) => i !== index));
};
const generateRecipes = () => {
if (ingredients.length === 0) return;
// Simulated recipe generation based on ingredients
const mockRecipes = [
{
id: "recipe1", name: "Classic Pasta Dish", cookTime: "20 min", difficulty: "Beginner", calories: "450 cal", cuisine: "Italian", instructions: "1. Boil water and add pasta\n2. Cook until al dente\n3. Add sauce and mix\n4. Serve hot", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AUcMfqJIbBXtBhmBEoWXMLyB4X/beautiful-recipe-result-cards-with-glass-1772651576068-e357f495.png"},
{
id: "recipe2", name: "Stir-Fry Vegetables", cookTime: "15 min", difficulty: "Intermediate", calories: "320 cal", cuisine: "Asian", instructions: "1. Heat oil in wok\n2. Add vegetables\n3. Stir frequently\n4. Season and serve", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AUcMfqJIbBXtBhmBEoWXMLyB4X/beautiful-recipe-result-cards-with-glass-1772651576068-e357f495.png"},
{
id: "recipe3", name: "Garden Fresh Salad", cookTime: "10 min", difficulty: "Beginner", calories: "180 cal", cuisine: "Mediterranean", instructions: "1. Wash vegetables\n2. Chop finely\n3. Mix with dressing\n4. Serve immediately", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AUcMfqJIbBXtBhmBEoWXMLyB4X/beautiful-recipe-result-cards-with-glass-1772651576068-e357f495.png"},
];
setRecipes(mockRecipes);
};
if (isAuthenticated && showOnboarding && !showDashboard) {
return (
<ThemeProvider
defaultButtonVariant="hover-bubble"
@@ -117,6 +159,223 @@ export default function LandingPage() {
);
}
if (isAuthenticated && showDashboard) {
return (
<ThemeProvider
defaultButtonVariant="hover-bubble"
defaultTextAnimation="reveal-blur"
borderRadius="soft"
contentWidth="smallMedium"
sizing="largeSmallSizeLargeTitles"
background="circleGradient"
cardStyle="glass-elevated"
primaryButtonStyle="shadow"
secondaryButtonStyle="radial-glow"
headingFontWeight="light"
>
<div id="nav" data-section="nav" className="sticky top-0 z-50">
<NavbarLayoutFloatingInline
brandName="EasyRecipes"
navItems={[
{ name: "Dashboard", id: "dashboard" },
{ name: "Recipes", id: "recipes" },
{ name: "Pantry", id: "pantry" },
{ name: "Settings", id: "settings" },
]}
button={{
text: "Sign Out", href: "#", onClick: handleSignOut,
}}
animateOnLoad={true}
className="backdrop-blur-md bg-white/30 border border-white/20"
/>
</div>
<div className="min-h-screen bg-gradient-to-br from-indigo-50 via-white to-purple-50">
{!selectedRecipe ? (
<>
{/* Ingredient Input Section */}
<div id="ingredient-input" data-section="ingredient-input" className="py-12 px-4">
<div className="max-w-4xl mx-auto">
<div className="bg-white/80 backdrop-blur-md rounded-2xl shadow-xl p-8 border border-white/20">
<div className="flex items-center gap-3 mb-6">
<ChefHat className="w-8 h-8 text-indigo-600" />
<h2 className="text-3xl font-bold text-gray-900">What ingredients do you have?</h2>
</div>
<p className="text-gray-600 mb-6">Enter your available ingredients and we'll generate personalized recipes for you.</p>
{/* Input Field */}
<div className="flex gap-3 mb-6">
<input
type="text"
value={currentInput}
onChange={(e) => setCurrentInput(e.target.value)}
onKeyPress={(e) => e.key === "Enter" && addIngredient()}
placeholder="Add an ingredient (e.g., chicken, tomato, garlic)"
className="flex-1 px-4 py-3 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 bg-white/50 backdrop-blur-sm"
/>
<button
onClick={addIngredient}
className="px-6 py-3 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors font-semibold flex items-center gap-2"
>
<Sparkles className="w-5 h-5" />
Add
</button>
</div>
{/* Ingredient Bubbles */}
{ingredients.length > 0 && (
<div className="mb-6">
<p className="text-sm text-gray-600 mb-3">Your ingredients:</p>
<div className="flex flex-wrap gap-3">
{ingredients.map((ingredient, index) => (
<div
key={index}
className="px-4 py-2 bg-gradient-to-r from-indigo-100 to-purple-100 rounded-full text-gray-800 font-medium flex items-center gap-2 border border-indigo-200 backdrop-blur-sm"
>
{ingredient}
<button
onClick={() => removeIngredient(index)}
className="ml-2 text-gray-500 hover:text-gray-700 transition-colors"
>
×
</button>
</div>
))}
</div>
</div>
)}
{/* Generate Button */}
{ingredients.length > 0 && (
<button
onClick={generateRecipes}
className="w-full py-4 bg-gradient-to-r from-indigo-600 to-purple-600 text-white rounded-lg hover:from-indigo-700 hover:to-purple-700 transition-all font-bold text-lg flex items-center justify-center gap-2 shadow-lg"
>
<Flame className="w-5 h-5" />
Generate Recipes
</button>
)}
</div>
</div>
</div>
{/* Recipes Section */}
{recipes.length > 0 && (
<div id="recipes" data-section="recipes" className="py-12 px-4">
<div className="max-w-6xl mx-auto">
<h2 className="text-3xl font-bold text-gray-900 mb-8">Your Generated Recipes</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{recipes.map((recipe) => (
<div
key={recipe.id}
onClick={() => setSelectedRecipe(recipe)}
className="bg-white/80 backdrop-blur-md rounded-xl shadow-lg overflow-hidden border border-white/20 hover:shadow-2xl transition-all cursor-pointer group"
>
<div className="relative overflow-hidden h-48">
<img
src={recipe.imageSrc}
alt={recipe.name}
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-300"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/40 to-transparent" />
</div>
<div className="p-6">
<h3 className="text-xl font-bold text-gray-900 mb-2">{recipe.name}</h3>
<div className="flex flex-wrap gap-2 mb-4">
<span className="px-3 py-1 bg-indigo-100 text-indigo-700 rounded-full text-sm font-medium">
{recipe.cookTime}
</span>
<span className="px-3 py-1 bg-purple-100 text-purple-700 rounded-full text-sm font-medium">
{recipe.difficulty}
</span>
<span className="px-3 py-1 bg-pink-100 text-pink-700 rounded-full text-sm font-medium">
{recipe.calories}
</span>
</div>
<p className="text-gray-600 text-sm mb-4">{recipe.cuisine} Cuisine</p>
<button className="w-full py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors font-semibold">
View Recipe
</button>
</div>
</div>
))}
</div>
</div>
</div>
)}
{/* Empty State */}
{recipes.length === 0 && ingredients.length === 0 && (
<div className="py-20 px-4">
<div className="max-w-2xl mx-auto text-center">
<Music className="w-16 h-16 text-indigo-300 mx-auto mb-4" />
<h3 className="text-2xl font-bold text-gray-900 mb-2">Start Your Culinary Journey</h3>
<p className="text-gray-600">Add ingredients above to discover delicious recipes powered by AI</p>
</div>
</div>
)}
</>
) : (
/* Recipe Detail View */
<div className="py-12 px-4">
<div className="max-w-3xl mx-auto">
<button
onClick={() => setSelectedRecipe(null)}
className="mb-6 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors font-semibold"
>
Back to Recipes
</button>
<div className="bg-white/80 backdrop-blur-md rounded-xl shadow-lg overflow-hidden border border-white/20">
<div className="relative h-80 overflow-hidden">
<img
src={selectedRecipe.imageSrc}
alt={selectedRecipe.name}
className="w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
<div className="absolute bottom-6 left-6 right-6">
<h1 className="text-4xl font-bold text-white mb-2">{selectedRecipe.name}</h1>
<p className="text-gray-200">{selectedRecipe.cuisine} Cuisine</p>
</div>
</div>
<div className="p-8">
<div className="grid grid-cols-3 gap-4 mb-8">
<div className="bg-indigo-50 rounded-lg p-4 text-center">
<p className="text-gray-600 text-sm mb-1">Cooking Time</p>
<p className="text-2xl font-bold text-indigo-600">{selectedRecipe.cookTime}</p>
</div>
<div className="bg-purple-50 rounded-lg p-4 text-center">
<p className="text-gray-600 text-sm mb-1">Difficulty</p>
<p className="text-2xl font-bold text-purple-600">{selectedRecipe.difficulty}</p>
</div>
<div className="bg-pink-50 rounded-lg p-4 text-center">
<p className="text-gray-600 text-sm mb-1">Calories</p>
<p className="text-2xl font-bold text-pink-600">{selectedRecipe.calories}</p>
</div>
</div>
<div className="bg-gray-50 rounded-lg p-6 border border-gray-200">
<h2 className="text-2xl font-bold text-gray-900 mb-4">Instructions</h2>
<div className="space-y-3">
{selectedRecipe.instructions.split("\n").map((instruction, idx) => (
<p key={idx} className="text-gray-700 leading-relaxed">
{instruction}
</p>
))}
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
</ThemeProvider>
);
}
return (
<ThemeProvider
defaultButtonVariant="hover-bubble"
@@ -414,22 +673,7 @@ export default function LandingPage() {
/>
</div>
</>
) : (
<div className="min-h-screen flex items-center justify-center">
<div className="text-center">
<h1 className="text-4xl font-bold mb-4">Welcome to EasyRecipes</h1>
<p className="text-lg text-gray-600 mb-8">
Dashboard content coming soon
</p>
<button
onClick={handleSignOut}
className="px-6 py-3 bg-red-500 text-white rounded-lg hover:bg-red-600"
>
Sign Out
</button>
</div>
</div>
)}
) : null}
<div id="footer" data-section="footer">
<FooterLogoEmphasis