955c4bd9dd
Replaces the single flat emoji-on-muted-bg fallback (same 🍽️/🍹 everywhere) with a deterministic gradient + food/drink icon per recipe id — pulled from a small curated palette/icon pool via a string hash, so it's stable across re-renders but visually varied across a grid of photo-less recipes. New shared lib/recipe-placeholder.ts + components/recipe/recipe-cover- placeholder.tsx, applied everywhere the old inline emoji fallback lived: recipe-grid-card.tsx, recipe-card.tsx, recipes-grid.tsx, and the public profile page's recipe grid. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
48 lines
1.8 KiB
TypeScript
48 lines
1.8 KiB
TypeScript
import {
|
|
Soup, Salad, Pizza, Sandwich, IceCream, Cookie, Beef, Fish, Cherry,
|
|
Carrot, Egg, Drumstick, Croissant, Donut, Cake, ChefHat,
|
|
Coffee, Wine, Beer, GlassWater, Martini, CupSoda,
|
|
type LucideIcon,
|
|
} from "lucide-react";
|
|
|
|
const GRADIENTS = [
|
|
"from-orange-200 to-rose-200 dark:from-orange-950 dark:to-rose-950",
|
|
"from-amber-200 to-lime-200 dark:from-amber-950 dark:to-lime-950",
|
|
"from-sky-200 to-indigo-200 dark:from-sky-950 dark:to-indigo-950",
|
|
"from-emerald-200 to-teal-200 dark:from-emerald-950 dark:to-teal-950",
|
|
"from-fuchsia-200 to-purple-200 dark:from-fuchsia-950 dark:to-purple-950",
|
|
"from-yellow-200 to-orange-200 dark:from-yellow-950 dark:to-orange-950",
|
|
"from-rose-200 to-pink-200 dark:from-rose-950 dark:to-pink-950",
|
|
"from-teal-200 to-cyan-200 dark:from-teal-950 dark:to-cyan-950",
|
|
];
|
|
|
|
const DISH_ICONS: LucideIcon[] = [
|
|
ChefHat, Soup, Salad, Pizza, Sandwich, IceCream, Cookie, Beef, Fish,
|
|
Cherry, Carrot, Egg, Drumstick, Croissant, Donut, Cake,
|
|
];
|
|
|
|
const DRINK_ICONS: LucideIcon[] = [Coffee, Wine, Beer, GlassWater, Martini, CupSoda];
|
|
|
|
/** Small, fast, deterministic string hash (djb2) — same recipe always gets the same placeholder. */
|
|
function hashString(s: string): number {
|
|
let hash = 5381;
|
|
for (let i = 0; i < s.length; i++) {
|
|
hash = (hash * 33) ^ s.charCodeAt(i);
|
|
}
|
|
return hash >>> 0;
|
|
}
|
|
|
|
export function getRecipePlaceholder(recipe: { id: string; recipeType?: "dish" | "drink" }): {
|
|
gradient: string;
|
|
Icon: LucideIcon;
|
|
} {
|
|
const hash = hashString(recipe.id);
|
|
const icons = recipe.recipeType === "drink" ? DRINK_ICONS : DISH_ICONS;
|
|
return {
|
|
gradient: GRADIENTS[hash % GRADIENTS.length]!,
|
|
// Different modulus base than gradient's so icon/color pairing doesn't
|
|
// repeat in lockstep across ids that happen to share a gradient.
|
|
Icon: icons[Math.floor(hash / GRADIENTS.length) % icons.length]!,
|
|
};
|
|
}
|