feat: stabilization + recipe edit/create UI
This commit is contained in:
58
frontend/src/components/recipe/RecipeCard.tsx
Normal file
58
frontend/src/components/recipe/RecipeCard.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { Link } from 'react-router'
|
||||
import { Heart, Clock } from 'lucide-react'
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { toggleFavorite } from '../../api/recipes'
|
||||
import type { Recipe } from '../../api/types'
|
||||
|
||||
const gradients = [
|
||||
'from-primary/60 to-secondary/60',
|
||||
'from-secondary/60 to-sage/60',
|
||||
'from-primary-light to-primary/40',
|
||||
'from-sage/40 to-secondary/60',
|
||||
]
|
||||
|
||||
export function RecipeCard({ recipe }: { recipe: Recipe }) {
|
||||
const qc = useQueryClient()
|
||||
const favMutation = useMutation({
|
||||
mutationFn: () => toggleFavorite(recipe.id),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ['recipes'] }),
|
||||
})
|
||||
|
||||
const gradient = gradients[recipe.title.length % gradients.length]
|
||||
const totalTime = recipe.total_time_min || ((recipe.prep_time_min || 0) + (recipe.cook_time_min || 0))
|
||||
|
||||
return (
|
||||
<div className="bg-surface rounded-2xl overflow-hidden shadow-sm break-inside-avoid mb-4">
|
||||
<Link to={`/recipe/${recipe.slug}`}>
|
||||
{recipe.image_url ? (
|
||||
<img src={recipe.image_url} alt={recipe.title} className="w-full h-auto object-cover" loading="lazy" />
|
||||
) : (
|
||||
<div className={`w-full aspect-[3/4] bg-gradient-to-br ${gradient} flex items-center justify-center`}>
|
||||
<span className="text-4xl">🍰</span>
|
||||
</div>
|
||||
)}
|
||||
</Link>
|
||||
<div className="p-3">
|
||||
<Link to={`/recipe/${recipe.slug}`}>
|
||||
<h3 className="font-display text-base text-espresso line-clamp-2">{recipe.title}</h3>
|
||||
</Link>
|
||||
<div className="flex items-center justify-between mt-2">
|
||||
{totalTime > 0 && (
|
||||
<span className="flex items-center gap-1 text-warm-grey text-xs">
|
||||
<Clock size={14} /> {totalTime} min
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
onClick={(e) => { e.preventDefault(); favMutation.mutate() }}
|
||||
className="ml-auto"
|
||||
>
|
||||
<Heart
|
||||
size={20}
|
||||
className={recipe.is_favorite ? 'fill-primary text-primary' : 'text-warm-grey'}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user