// src/shared.jsx — small components, data, helpers shared across artboards // Exposes to window so other Babel script files can use them. // ───────────────────────────────────────────────────────────── // Icons — Lucide-style line, hand-traced as SVG so we don't pull a library. // All 24×24, currentColor. // ───────────────────────────────────────────────────────────── const LC_Icon = ({ d, size = 20, stroke = 1.6, className, style }) => ( {typeof d === 'string' ? : d} ); const Icon = { search: (p) => , plus: (p) => , edit: (p) => , trash: (p) => , share: (p) => , sun: (p) => , bulb: (p) => , camera: (p) => , link: (p) => , upload: (p) => , list: (p) => , grid: (p) => , chevD: (p) => , chevR: (p) => , check: (p) => , x: (p) => , filter: (p) => , sort: (p) => , user: (p) => , bookmark:(p)=> , clock: (p) => , flame: (p) => , arrow: (p) => , more: (p) => , eye: (p) => , sparkle:(p) => , expand: (p) => , undo: (p) => , }; // ───────────────────────────────────────────────────────────── // Stars — fractional via overlaying filled over empty // ───────────────────────────────────────────────────────────── const Star = ({ size = 14 }) => ( ); const Stars = ({ value = 0, size = 14 }) => { const stars = []; for (let i = 0; i < 5; i++) { const filled = i < Math.round(value); stars.push( ); } return {stars}; }; // ───────────────────────────────────────────────────────────── // Wordmark — Name + italic "Cooks." // ───────────────────────────────────────────────────────────── const Wordmark = ({ name = 'Luis', size = 22, color }) => ( {name} Cooks. ); // ───────────────────────────────────────────────────────────── // Cost-per-serving chip // ───────────────────────────────────────────────────────────── const CostPerServing = ({ amount = '4.20', estimated = true, size = 'm' }) => { const big = size === 'l'; return ( ${amount} / serving {estimated && ( EST )} ); }; // ───────────────────────────────────────────────────────────── // Recipe Card — used in library grid // width is the card width; height auto. Photo is a square. // ───────────────────────────────────────────────────────────── const RecipeCard = ({ recipe, width = 260, showHover = false }) => { const r = recipe; return (

{r.name}

{r.rating > 0 ? : ( Unrated )} ${r.cost} / serv
{r.categories.slice(0, 2).map((c, i) => ( {c}{i < Math.min(r.categories.length, 2) - 1 ? ' ·' : ''} ))}
); }; // Thumbnail — either an image-slot for hero recipes, or a CSS placeholder const Thumbnail = ({ recipe, size = 260, showHover = false }) => { const r = recipe; if (r.photo === 'slot') { return ( ); } // CSS placeholder — warm, monochrome, monospace label return (
{/* faint stripes pattern */}
{r.placeholder || r.name.toLowerCase()}
); }; // ───────────────────────────────────────────────────────────── // Recipe data — real-feeling, not lorem // `photo` is 'slot' (drop your own), 'placeholder' (CSS), or 'none' // ───────────────────────────────────────────────────────────── const RECIPES = [ { id: 'sichuan-chicken', name: 'Sichuan-style cold chicken with chilli oil', description: 'A weeknight standby — poach, shock in ice water, dress in the chilli oil while everything\'s cold. Better the next day.', rating: 5, cost: '4.20', categories: ['Mains', 'Asian', 'Chicken', 'Quick'], photo: 'slot', placeholder: 'sichuan chicken w/ chilli oil', bg: '#b85a3a', prep: '15 mins', cook: '20 mins', total: '35 mins', servings: 'serves 4', difficulty: 'easy', source: 'adapted from Fuchsia Dunlop', ingredients: [ 'For the chicken:', '1 whole chicken (about 1.5 kg)', '6 spring onions, white parts only', '2 thumbs of ginger, smashed', '2 tbsp Shaoxing wine', '', 'For the chilli oil:', '½ cup neutral oil', '3 tbsp Sichuan chilli flakes', '1 tsp Sichuan peppercorns, lightly toasted and ground', '3 cloves garlic, finely grated', '1 tbsp light soy sauce', '2 tsp Chinkiang vinegar', '½ tsp sugar', '1 tbsp toasted sesame seeds', 'Coriander and spring onion greens to finish', ], directions: [ 'Bring a large pot of water to the boil with the spring onion whites, ginger and Shaoxing. Lower the chicken in, breast down. Bring back to a bare simmer, cover, and turn off the heat. Leave for 45 minutes — do not lift the lid.', 'Lift the chicken out and plunge into a big bowl of iced water. Leave 10 minutes. Pat dry, joint into pieces, then slice off the bone into bite-sized chunks. Arrange on a plate.', 'For the oil: heat the neutral oil until it shimmers. Combine the chilli flakes, ground peppercorns and garlic in a heatproof bowl. Pour the hot oil over and stand back — it will bloom violently for 30 seconds. Stir in the soy, vinegar and sugar.', 'Spoon the chilli oil generously over the chicken. Scatter with sesame, coriander and the green tops of the spring onions. Serve cold or at room temperature — never hot.', ], notes: 'Doubled the garlic last time, better. Save the poaching liquid for noodles — it\'s practically stock.', }, { id: 'lamb-shoulder', name: 'Slow-roast lamb shoulder with white beans', description: 'Sunday lunch food. Goes in the oven mid-morning and you forget about it until the kitchen smells like a restaurant.', rating: 5, cost: '6.80', categories: ['Mains', 'Sunday', 'Lamb'], photo: 'slot', placeholder: 'lamb shoulder, white beans', bg: '#8c6a4a', prep: '20 mins', cook: '4 hrs', total: '4 hrs 20', servings: 'serves 6', difficulty: 'easy', source: 'Diana Henry, A Bird in the Hand', ingredients: [ '1 lamb shoulder, bone-in (~2 kg)', '6 cloves garlic, sliced', '2 sprigs rosemary', '2 anchovies, finely chopped', 'Olive oil, salt, pepper', '500g dried cannellini, soaked overnight', '1 onion, halved', '2 bay leaves', '300ml white wine', '500ml chicken stock', 'Lemon, for serving', ], directions: [ 'Heat oven to 220°C. Make small incisions all over the lamb and push slivers of garlic, rosemary leaves and anchovy into them. Rub all over with oil, salt, pepper.', 'Roast for 30 minutes to colour. Drop the oven to 140°C.', 'Meanwhile, drain the beans and put them in a deep roasting tin with the onion, bay, wine and stock. Set the lamb on top, cover tightly with foil, and roast for 3½ hours.', 'Uncover for the last 30 minutes to brown again. Rest 15 minutes. Pull the meat apart at the table with two forks.', 'Serve with the beans, a squeeze of lemon, and a green salad sharp with vinegar.', ], notes: 'The Chinese fermented chilli paste in the back of the fridge is genuinely brilliant stirred through the beans at the end.', }, { id: 'pumpkin-freekeh', name: 'Roast pumpkin, freekeh, burnt-butter yoghurt', description: '', rating: 4, cost: '3.10', categories: ['Mains', 'Vegetarian'], photo: 'placeholder', placeholder: 'roast pumpkin, freekeh', bg: '#c08a3a', angle: 28, prep: '15 mins', cook: '45 mins', total: '1 hr', servings: 'serves 4', difficulty: 'easy', }, { id: 'tom-yum', name: 'Tom yum noodle soup', rating: 5, cost: '3.40', categories: ['Mains', 'Asian', 'Soup'], photo: 'placeholder', placeholder: 'tom yum, prawn, lime', bg: '#a83a22', angle: 50, prep: '10 mins', cook: '20 mins', }, { id: 'tomato-sauce', name: 'Marcella Hazan\'s tomato sauce', rating: 5, cost: '1.20', categories: ['Pantry', 'Italian', 'Vegetarian'], photo: 'placeholder', placeholder: 'butter + tomato + onion', bg: '#c8533a', angle: 65, }, { id: 'broccoli-anchovy', name: 'Charred broccoli with anchovy crumbs', rating: 4, cost: '2.40', categories: ['Sides', 'Vegetarian'], photo: 'placeholder', placeholder: 'charred broccoli + crumbs', bg: '#5a6b3a', angle: 18, }, { id: 'cauliflower', name: 'Whole roast cauliflower, tahini, pomegranate', rating: 5, cost: '2.90', categories: ['Mains', 'Vegetarian'], photo: 'placeholder', placeholder: 'whole roast cauliflower', bg: '#d1a85a', angle: 75, }, { id: 'pancakes', name: 'Buttermilk pancakes', rating: 5, cost: '1.10', categories: ['Breakfast', 'Sunday'], photo: 'placeholder', placeholder: 'pancakes, syrup', bg: '#cf9b50', angle: 42, }, { id: 'black-beans', name: 'Smoky black beans with charred onion', rating: 4, cost: '1.80', categories: ['Mains', 'Vegetarian', 'Mexican'], photo: 'placeholder', placeholder: 'black beans, smoky', bg: '#3a2e22', angle: 12, }, { id: 'miso-eggplant', name: 'Miso-glazed eggplant', rating: 5, cost: '2.20', categories: ['Mains', 'Asian', 'Vegetarian'], photo: 'placeholder', placeholder: 'miso eggplant, halves', bg: '#6b5d2e', angle: 60, }, { id: 'pizza-dough', name: 'Saturday-night pizza dough', rating: 5, cost: '0.80', categories: ['Pantry', 'Italian', 'Saturday'], photo: 'placeholder', placeholder: 'pizza dough, semolina', bg: '#e3d0a0', angle: 25, }, { id: 'soda-bread', name: 'Brown soda bread', rating: 0, cost: '0.60', categories: ['Baking', 'Pantry'], photo: 'placeholder', placeholder: 'soda bread loaf', bg: '#9c7d54', angle: 38, }, ]; Object.assign(window, { LC_Icon, Icon, Star, Stars, Wordmark, CostPerServing, RecipeCard, Thumbnail, RECIPES, });