fix(recept): bakverk ur mellanmal + sub-kategorier, bladdra pa forstasidan, relevantare forslag
Kategorisering (din notis - bakverk hor till Baka, inte mellanmal): - Sub-typer bread/bun/pie/cake/cookie i RECIPE_TAGS. - Bullar/kakor/pajer/chokladbollar -> dessert (inte snack) + sub-tagg; brod -> breakfast. Befintliga lussekatter/saffransbullar taggas 'bun'. - Browse: sub-chips under Baka (Brod/Bullar/Paj/Tartor & kakor/Smakakor). Bladdra pa forstasidan (din onskan): - Kategori-genvagar pa 'Vad ska vi ata' -> oppnar bladdraren forvald (/recipes?cat=). recipes.tsx laser ?cat=. Relevantare 'Vad ska vi ata' (snurrar samma triviala): - view=pantry -> view=default (tackning vager tungt men inte allenaradande, ger variation), limit 15 -> 30 (storre pool sa 'Visa fler' upprepar senare). Felsokning inkopslista: - Tydligare felmeddelande (HTTP-status vs natverksfel) sa root cause syns. Full typecheck 20/20, invariant-test gront.
This commit is contained in:
@@ -50,6 +50,22 @@ interface WhatToEatResponse {
|
|||||||
context: { activeHolidays: string[]; remainingKcal: number; remainingProteinG: number };
|
context: { activeHolidays: string[]; remainingKcal: number; remainingProteinG: number };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bläddra-genvägar direkt på förstasidan (öppnar recept-bläddraren förvald på
|
||||||
|
// kategorin). Etiketter återanvänder myday.mealType.* där de finns.
|
||||||
|
const BROWSE_CATS: ReadonlyArray<{
|
||||||
|
key: string;
|
||||||
|
labelKey: string | null;
|
||||||
|
label?: string;
|
||||||
|
glyph: string;
|
||||||
|
}> = [
|
||||||
|
{ key: "breakfast", labelKey: "myday.mealType.breakfast", glyph: "🥣" },
|
||||||
|
{ key: "lunch", labelKey: "myday.mealType.lunch", glyph: "🥗" },
|
||||||
|
{ key: "dinner", labelKey: "myday.mealType.dinner", glyph: "🍽️" },
|
||||||
|
{ key: "snack", labelKey: "myday.mealType.snack", glyph: "🍎" },
|
||||||
|
{ key: "dessert", labelKey: "myday.mealType.dessert", glyph: "🍰" },
|
||||||
|
{ key: "baking", labelKey: null, label: "Baka", glyph: "🥐" },
|
||||||
|
];
|
||||||
|
|
||||||
export default function WhatToEatScreen() {
|
export default function WhatToEatScreen() {
|
||||||
const [craving, setCraving] = useState("");
|
const [craving, setCraving] = useState("");
|
||||||
const [submittedCraving, setSubmittedCraving] = useState("");
|
const [submittedCraving, setSubmittedCraving] = useState("");
|
||||||
@@ -59,17 +75,24 @@ export default function WhatToEatScreen() {
|
|||||||
const hour = new Date().getHours();
|
const hour = new Date().getHours();
|
||||||
const currentMeal = hour < 10 ? "breakfast" : hour < 14 ? "lunch" : "dinner";
|
const currentMeal = hour < 10 ? "breakfast" : hour < 14 ? "lunch" : "dinner";
|
||||||
|
|
||||||
|
// view=default ger en balanserad rankning (täckning väger tungt men inte
|
||||||
|
// allenarådande som i pantry-vyn) → mer varierade, relevanta förslag i stället
|
||||||
|
// för samma triviala högtäckningsrätter. Större pool (30) så "Visa fler"
|
||||||
|
// bläddrar längre innan den upprepar.
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
queryKey: ["what-to-eat", submittedCraving, currentMeal],
|
queryKey: ["what-to-eat", submittedCraving, currentMeal],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
api<WhatToEatResponse>(
|
api<WhatToEatResponse>(
|
||||||
`/v1/recommendations/what-to-eat?limit=15&view=pantry&mealType=${currentMeal}${submittedCraving ? `&craving=${encodeURIComponent(submittedCraving)}` : ""}`,
|
`/v1/recommendations/what-to-eat?limit=30&view=default&mealType=${currentMeal}${submittedCraving ? `&craving=${encodeURIComponent(submittedCraving)}` : ""}`,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
const allRecs = query.data?.recommendations ?? [];
|
const allRecs = query.data?.recommendations ?? [];
|
||||||
const shownRecs: Recommendation[] = allRecs.length
|
const shownRecs: Recommendation[] = allRecs.length
|
||||||
? Array.from({ length: Math.min(5, allRecs.length) }, (_, i) => allRecs[(page * 5 + i) % allRecs.length]).filter((r): r is Recommendation => r != null)
|
? Array.from(
|
||||||
|
{ length: Math.min(5, allRecs.length) },
|
||||||
|
(_, i) => allRecs[(page * 5 + i) % allRecs.length],
|
||||||
|
).filter((r): r is Recommendation => r != null)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -98,13 +121,30 @@ export default function WhatToEatScreen() {
|
|||||||
placeholder={t("wte.cravingPlaceholder")}
|
placeholder={t("wte.cravingPlaceholder")}
|
||||||
value={craving}
|
value={craving}
|
||||||
onChangeText={setCraving}
|
onChangeText={setCraving}
|
||||||
onSubmitEditing={() => { setSubmittedCraving(craving); setPage(0); }}
|
onSubmitEditing={() => {
|
||||||
|
setSubmittedCraving(craving);
|
||||||
|
setPage(0);
|
||||||
|
}}
|
||||||
returnKeyType="search"
|
returnKeyType="search"
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</Row>
|
</Row>
|
||||||
<Spacer size={spacing.sm} />
|
<Spacer size={spacing.sm} />
|
||||||
|
|
||||||
|
{/* Bläddra bland recept per kategori direkt från förstasidan. */}
|
||||||
|
<Row style={{ flexWrap: "wrap" }}>
|
||||||
|
{BROWSE_CATS.map((c) => (
|
||||||
|
<Button
|
||||||
|
key={c.key}
|
||||||
|
label={`${c.glyph} ${c.labelKey ? t(c.labelKey as never) : (c.label ?? "")}`}
|
||||||
|
variant="ghost"
|
||||||
|
onPress={() => router.push(`/recipes?cat=${c.key}`)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<Button label="Alla recept" variant="secondary" onPress={() => router.push("/recipes")} />
|
||||||
|
</Row>
|
||||||
|
<Spacer size={spacing.sm} />
|
||||||
|
|
||||||
{query.isLoading && <LoadingView />}
|
{query.isLoading && <LoadingView />}
|
||||||
{query.isError && <ErrorView onRetry={() => void query.refetch()} />}
|
{query.isError && <ErrorView onRetry={() => void query.refetch()} />}
|
||||||
|
|
||||||
@@ -156,7 +196,10 @@ export default function WhatToEatScreen() {
|
|||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
{rec.ratingCount > 0 && rec.ratingAverage != null && (
|
{rec.ratingCount > 0 && rec.ratingAverage != null && (
|
||||||
<Tag label={`★ ${rec.ratingAverage.toFixed(1).replace(".", ",")} · ${rec.ratingCount}`} tone="accent" />
|
<Tag
|
||||||
|
label={`★ ${rec.ratingAverage.toFixed(1).replace(".", ",")} · ${rec.ratingCount}`}
|
||||||
|
tone="accent"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<Tag
|
<Tag
|
||||||
label={t("wte.coverage", { pct: rec.coveragePercent })}
|
label={t("wte.coverage", { pct: rec.coveragePercent })}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useState } from "react";
|
|||||||
import { Alert, Pressable, View } from "react-native";
|
import { Alert, Pressable, View } from "react-native";
|
||||||
import { router, useLocalSearchParams } from "expo-router";
|
import { router, useLocalSearchParams } from "expo-router";
|
||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { api } from "@/lib/api";
|
import { api, ApiError } from "@/lib/api";
|
||||||
import { t } from "@/lib/i18n";
|
import { t } from "@/lib/i18n";
|
||||||
import { formatMinor } from "@/lib/money";
|
import { formatMinor } from "@/lib/money";
|
||||||
import {
|
import {
|
||||||
@@ -162,8 +162,16 @@ export default function RecipeScreen() {
|
|||||||
`${count} ${count === 1 ? "vara" : "varor"} lades till.`,
|
`${count} ${count === 1 ? "vara" : "varor"} lades till.`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onError: (err) =>
|
onError: (err) => {
|
||||||
Alert.alert(t("common.oops"), err instanceof Error ? err.message : t("common.error")),
|
// Visa tydlig diagnostik: HTTP-status vs nätverksfel (hjälper felsökning).
|
||||||
|
const detail =
|
||||||
|
err instanceof ApiError
|
||||||
|
? `[${err.status}] ${err.message}`
|
||||||
|
: err instanceof Error
|
||||||
|
? err.message
|
||||||
|
: t("common.error");
|
||||||
|
Alert.alert(t("common.oops"), detail);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (query.isLoading) return <LoadingView />;
|
if (query.isLoading) return <LoadingView />;
|
||||||
@@ -269,7 +277,10 @@ export default function RecipeScreen() {
|
|||||||
</Row>
|
</Row>
|
||||||
</Row>
|
</Row>
|
||||||
{ingredients.map((ing) => (
|
{ingredients.map((ing) => (
|
||||||
<Row key={ing.id ?? (ing.displayName ?? ing.displayNameSv)} style={{ justifyContent: "space-between" }}>
|
<Row
|
||||||
|
key={ing.id ?? ing.displayName ?? ing.displayNameSv}
|
||||||
|
style={{ justifyContent: "space-between" }}
|
||||||
|
>
|
||||||
<Body>
|
<Body>
|
||||||
{ing.displayName ?? ing.displayNameSv}
|
{ing.displayName ?? ing.displayNameSv}
|
||||||
{ing.optional ? " (valfritt)" : ""}
|
{ing.optional ? " (valfritt)" : ""}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { router } from "expo-router";
|
import { router, useLocalSearchParams } from "expo-router";
|
||||||
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
||||||
import { api } from "@/lib/api";
|
import { api } from "@/lib/api";
|
||||||
import { t } from "@/lib/i18n";
|
import { t } from "@/lib/i18n";
|
||||||
@@ -63,19 +63,44 @@ const CATEGORIES: ReadonlyArray<{
|
|||||||
{ key: "baking", labelKey: null, label: "Baka", tag: "baking", glyph: "🥐" },
|
{ key: "baking", labelKey: null, label: "Baka", tag: "baking", glyph: "🥐" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Under-kategorier som visas när "Baka" är vald. Varje bakverk bär både taggen
|
||||||
|
// "baking" och en under-typ, så vi kan filtrera på under-typen direkt.
|
||||||
|
const BAKING_SUBS: ReadonlyArray<{ key: string; label: string; tag?: string }> = [
|
||||||
|
{ key: "all", label: "Alla" },
|
||||||
|
{ key: "bread", label: "Bröd", tag: "bread" },
|
||||||
|
{ key: "bun", label: "Bullar", tag: "bun" },
|
||||||
|
{ key: "pie", label: "Paj", tag: "pie" },
|
||||||
|
{ key: "cake", label: "Tårtor & kakor", tag: "cake" },
|
||||||
|
{ key: "cookie", label: "Småkakor", tag: "cookie" },
|
||||||
|
];
|
||||||
|
|
||||||
export default function BrowseRecipesScreen() {
|
export default function BrowseRecipesScreen() {
|
||||||
const [category, setCategory] = useState<string>("all");
|
// Förvald kategori via ?cat= (från förstasidans genvägar); annars "Alla".
|
||||||
|
const { cat } = useLocalSearchParams<{ cat?: string }>();
|
||||||
|
const initialCategory = CATEGORIES.some((c) => c.key === cat) ? (cat as string) : "all";
|
||||||
|
const [category, setCategory] = useState<string>(initialCategory);
|
||||||
|
const [sub, setSub] = useState<string>("all"); // under-kategori, bara relevant för Baka
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const term = search.trim();
|
const term = search.trim();
|
||||||
|
|
||||||
|
const selectCategory = (key: string) => {
|
||||||
|
setCategory(key);
|
||||||
|
if (key !== "baking") setSub("all"); // nollställ under-val när man lämnar Baka
|
||||||
|
};
|
||||||
|
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
queryKey: ["browse-recipes", category, term],
|
queryKey: ["browse-recipes", category, sub, term],
|
||||||
queryFn: () => {
|
queryFn: () => {
|
||||||
// Bygg query-strängen som resten av appen (template + encodeURIComponent).
|
// Bygg query-strängen som resten av appen (template + encodeURIComponent).
|
||||||
const cat = CATEGORIES.find((c) => c.key === category);
|
const cat = CATEGORIES.find((c) => c.key === category);
|
||||||
let path = "/v1/recipes?limit=50";
|
let path = "/v1/recipes?limit=50";
|
||||||
if (cat?.mealType) path += `&mealType=${cat.mealType}`;
|
if (cat?.mealType) path += `&mealType=${cat.mealType}`;
|
||||||
if (cat?.tag) path += `&tags=${cat.tag}`;
|
if (cat?.tag) path += `&tags=${cat.tag}`;
|
||||||
|
// Under Baka: filtrera på vald under-typ (bullar/bröd/…) i stället för "baking".
|
||||||
|
if (category === "baking" && sub !== "all") {
|
||||||
|
const subTag = BAKING_SUBS.find((s) => s.key === sub)?.tag;
|
||||||
|
if (subTag) path = `/v1/recipes?limit=50&tags=${subTag}`;
|
||||||
|
}
|
||||||
if (term) path += `&search=${encodeURIComponent(term)}`;
|
if (term) path += `&search=${encodeURIComponent(term)}`;
|
||||||
return api<{ recipes: BrowseRecipe[] }>(path);
|
return api<{ recipes: BrowseRecipe[] }>(path);
|
||||||
},
|
},
|
||||||
@@ -101,11 +126,25 @@ export default function BrowseRecipesScreen() {
|
|||||||
key={c.key}
|
key={c.key}
|
||||||
label={`${c.glyph} ${c.labelKey ? t(c.labelKey as never) : (c.label ?? "Alla")}`}
|
label={`${c.glyph} ${c.labelKey ? t(c.labelKey as never) : (c.label ?? "Alla")}`}
|
||||||
variant={category === c.key ? "secondary" : "ghost"}
|
variant={category === c.key ? "secondary" : "ghost"}
|
||||||
onPress={() => setCategory(c.key)}
|
onPress={() => selectCategory(c.key)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
|
{/* Under-kategorier: visas bara när Baka är valt (bröd/bullar/paj/…). */}
|
||||||
|
{category === "baking" && (
|
||||||
|
<Row style={{ flexWrap: "wrap" }}>
|
||||||
|
{BAKING_SUBS.map((s) => (
|
||||||
|
<Button
|
||||||
|
key={s.key}
|
||||||
|
label={s.label}
|
||||||
|
variant={sub === s.key ? "secondary" : "ghost"}
|
||||||
|
onPress={() => setSub(s.key)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Row>
|
||||||
|
)}
|
||||||
|
|
||||||
{query.isLoading ? (
|
{query.isLoading ? (
|
||||||
<LoadingView />
|
<LoadingView />
|
||||||
) : query.isError ? (
|
) : query.isError ? (
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ export const EXTRA_RECIPES: SeedRecipe[] = [
|
|||||||
descriptionSv:
|
descriptionSv:
|
||||||
"Mjuka, saftiga bullar med smörig kanelfyllning – den självklara fikan att baka en söndag.",
|
"Mjuka, saftiga bullar med smörig kanelfyllning – den självklara fikan att baka en söndag.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["snack"],
|
mealTypes: ["dessert"],
|
||||||
tags: ["baking", "vegetarian", "kid_friendly"],
|
tags: ["baking", "bun", "vegetarian", "kid_friendly"],
|
||||||
methods: ["oven"],
|
methods: ["oven"],
|
||||||
equipment: ["oven"],
|
equipment: ["oven"],
|
||||||
difficulty: "medium",
|
difficulty: "medium",
|
||||||
@@ -74,8 +74,8 @@ export const EXTRA_RECIPES: SeedRecipe[] = [
|
|||||||
titleSv: "Kardemummabullar",
|
titleSv: "Kardemummabullar",
|
||||||
descriptionSv: "Doftande bullar där kardemumman får ta plats både i degen och i fyllningen.",
|
descriptionSv: "Doftande bullar där kardemumman får ta plats både i degen och i fyllningen.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["snack"],
|
mealTypes: ["dessert"],
|
||||||
tags: ["baking", "vegetarian", "kid_friendly"],
|
tags: ["baking", "bun", "vegetarian", "kid_friendly"],
|
||||||
methods: ["oven"],
|
methods: ["oven"],
|
||||||
equipment: ["oven"],
|
equipment: ["oven"],
|
||||||
difficulty: "medium",
|
difficulty: "medium",
|
||||||
@@ -121,7 +121,7 @@ export const EXTRA_RECIPES: SeedRecipe[] = [
|
|||||||
"Syrliga äpplen under ett gyllene lock av havregryn och smör – ljummen med grädde är den oslagbar.",
|
"Syrliga äpplen under ett gyllene lock av havregryn och smör – ljummen med grädde är den oslagbar.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["dessert"],
|
mealTypes: ["dessert"],
|
||||||
tags: ["baking", "vegetarian"],
|
tags: ["baking", "pie", "vegetarian"],
|
||||||
methods: ["oven"],
|
methods: ["oven"],
|
||||||
equipment: ["oven"],
|
equipment: ["oven"],
|
||||||
difficulty: "beginner",
|
difficulty: "beginner",
|
||||||
@@ -165,7 +165,7 @@ export const EXTRA_RECIPES: SeedRecipe[] = [
|
|||||||
"Nygräddade frallor med krispig skorpa och luftigt inkråm – perfekta till frukostbordet.",
|
"Nygräddade frallor med krispig skorpa och luftigt inkråm – perfekta till frukostbordet.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["breakfast"],
|
mealTypes: ["breakfast"],
|
||||||
tags: ["baking", "vegetarian"],
|
tags: ["baking", "bread", "vegetarian"],
|
||||||
methods: ["oven"],
|
methods: ["oven"],
|
||||||
equipment: ["oven"],
|
equipment: ["oven"],
|
||||||
difficulty: "medium",
|
difficulty: "medium",
|
||||||
@@ -690,7 +690,7 @@ export const EXTRA_RECIPES: SeedRecipe[] = [
|
|||||||
"Seg, kladdig chokladkaka med krispig yta – klar på en kvart plus ugnstid. Godast lite kladdig i mitten.",
|
"Seg, kladdig chokladkaka med krispig yta – klar på en kvart plus ugnstid. Godast lite kladdig i mitten.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["dessert"],
|
mealTypes: ["dessert"],
|
||||||
tags: ["baking", "vegetarian", "kid_friendly"],
|
tags: ["baking", "cake", "vegetarian", "kid_friendly"],
|
||||||
methods: ["oven"],
|
methods: ["oven"],
|
||||||
equipment: ["oven"],
|
equipment: ["oven"],
|
||||||
difficulty: "beginner",
|
difficulty: "beginner",
|
||||||
@@ -734,8 +734,8 @@ export const EXTRA_RECIPES: SeedRecipe[] = [
|
|||||||
descriptionSv:
|
descriptionSv:
|
||||||
"Klassiska, snabba chokladbollar rullade i kokos – inget bak, bara att röra ihop.",
|
"Klassiska, snabba chokladbollar rullade i kokos – inget bak, bara att röra ihop.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["snack"],
|
mealTypes: ["dessert"],
|
||||||
tags: ["baking", "vegetarian", "kid_friendly"],
|
tags: ["baking", "cookie", "vegetarian", "kid_friendly"],
|
||||||
methods: ["no_cook"],
|
methods: ["no_cook"],
|
||||||
equipment: [],
|
equipment: [],
|
||||||
difficulty: "beginner",
|
difficulty: "beginner",
|
||||||
@@ -773,7 +773,7 @@ export const EXTRA_RECIPES: SeedRecipe[] = [
|
|||||||
"Söta blåbär under ett gyllene smul av smör och havregryn – sommarens självklara paj.",
|
"Söta blåbär under ett gyllene smul av smör och havregryn – sommarens självklara paj.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["dessert"],
|
mealTypes: ["dessert"],
|
||||||
tags: ["baking", "vegetarian"],
|
tags: ["baking", "pie", "vegetarian"],
|
||||||
methods: ["oven"],
|
methods: ["oven"],
|
||||||
equipment: ["oven"],
|
equipment: ["oven"],
|
||||||
difficulty: "beginner",
|
difficulty: "beginner",
|
||||||
@@ -816,8 +816,8 @@ export const EXTRA_RECIPES: SeedRecipe[] = [
|
|||||||
descriptionSv:
|
descriptionSv:
|
||||||
"Luftig, saftig sockerkaka – den enklaste kakan att baka och alltid lika uppskattad till fikat.",
|
"Luftig, saftig sockerkaka – den enklaste kakan att baka och alltid lika uppskattad till fikat.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["snack"],
|
mealTypes: ["dessert"],
|
||||||
tags: ["baking", "vegetarian", "kid_friendly"],
|
tags: ["baking", "cake", "vegetarian", "kid_friendly"],
|
||||||
methods: ["oven"],
|
methods: ["oven"],
|
||||||
equipment: ["oven"],
|
equipment: ["oven"],
|
||||||
difficulty: "beginner",
|
difficulty: "beginner",
|
||||||
@@ -861,7 +861,7 @@ export const EXTRA_RECIPES: SeedRecipe[] = [
|
|||||||
descriptionSv: "Saftig, kryddig morotskaka med valnötter – mumsig till kaffet.",
|
descriptionSv: "Saftig, kryddig morotskaka med valnötter – mumsig till kaffet.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["dessert"],
|
mealTypes: ["dessert"],
|
||||||
tags: ["baking", "vegetarian"],
|
tags: ["baking", "cake", "vegetarian"],
|
||||||
methods: ["oven"],
|
methods: ["oven"],
|
||||||
equipment: ["oven"],
|
equipment: ["oven"],
|
||||||
difficulty: "medium",
|
difficulty: "medium",
|
||||||
@@ -905,8 +905,8 @@ export const EXTRA_RECIPES: SeedRecipe[] = [
|
|||||||
titleSv: "Vaniljbullar",
|
titleSv: "Vaniljbullar",
|
||||||
descriptionSv: "Mjuka bullar med vaniljfyllning och pärlsocker – ett annat namn på söndagsmys.",
|
descriptionSv: "Mjuka bullar med vaniljfyllning och pärlsocker – ett annat namn på söndagsmys.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["snack"],
|
mealTypes: ["dessert"],
|
||||||
tags: ["baking", "vegetarian", "kid_friendly"],
|
tags: ["baking", "bun", "vegetarian", "kid_friendly"],
|
||||||
methods: ["oven"],
|
methods: ["oven"],
|
||||||
equipment: ["oven"],
|
equipment: ["oven"],
|
||||||
difficulty: "medium",
|
difficulty: "medium",
|
||||||
|
|||||||
@@ -35097,7 +35097,7 @@ export const VERIFIED_RECIPES: SeedRecipe[] = [
|
|||||||
"Saftiga saffransbullar formade som S, med russin som ögon. Hör Lucia och advent till.",
|
"Saftiga saffransbullar formade som S, med russin som ögon. Hör Lucia och advent till.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["dessert", "breakfast"],
|
mealTypes: ["dessert", "breakfast"],
|
||||||
tags: ["baking", "vegetarian", "kid_friendly"],
|
tags: ["baking", "bun", "vegetarian", "kid_friendly"],
|
||||||
methods: ["oven"],
|
methods: ["oven"],
|
||||||
equipment: ["oven"],
|
equipment: ["oven"],
|
||||||
difficulty: "medium",
|
difficulty: "medium",
|
||||||
@@ -35213,7 +35213,7 @@ export const VERIFIED_RECIPES: SeedRecipe[] = [
|
|||||||
"Saftiga saffrans- och kardemummabullar fyllda med mandelmassa. Ett festligt bakverk till Lucia och advent.",
|
"Saftiga saffrans- och kardemummabullar fyllda med mandelmassa. Ett festligt bakverk till Lucia och advent.",
|
||||||
cuisine: "swedish",
|
cuisine: "swedish",
|
||||||
mealTypes: ["dessert", "breakfast"],
|
mealTypes: ["dessert", "breakfast"],
|
||||||
tags: ["baking", "vegetarian", "kid_friendly"],
|
tags: ["baking", "bun", "vegetarian", "kid_friendly"],
|
||||||
methods: ["oven"],
|
methods: ["oven"],
|
||||||
equipment: ["oven"],
|
equipment: ["oven"],
|
||||||
difficulty: "medium",
|
difficulty: "medium",
|
||||||
|
|||||||
@@ -250,6 +250,13 @@ export const RECIPE_TAGS = [
|
|||||||
// Tillagd (spec §14, browse): bakverk – bullar, bröd, pajer, kakor. text[]-
|
// Tillagd (spec §14, browse): bakverk – bullar, bröd, pajer, kakor. text[]-
|
||||||
// kolumn, ingen migration. Driver "Baka"-kategorin i bläddra-vyn.
|
// kolumn, ingen migration. Driver "Baka"-kategorin i bläddra-vyn.
|
||||||
"baking",
|
"baking",
|
||||||
|
// Under-typer till "baking" (driver sub-kategorierna under Baka). Ett bakverk
|
||||||
|
// bär både "baking" och exakt en av dessa, t.ex. ["baking", "bun"].
|
||||||
|
"bread",
|
||||||
|
"bun",
|
||||||
|
"pie",
|
||||||
|
"cake",
|
||||||
|
"cookie",
|
||||||
] as const;
|
] as const;
|
||||||
export type RecipeTag = (typeof RECIPE_TAGS)[number];
|
export type RecipeTag = (typeof RECIPE_TAGS)[number];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user