fix: make recipe ingredinets interactive

This commit is contained in:
Max Richter
2025-11-02 20:01:01 +01:00
parent d4a7763b15
commit 098da12ac4
10 changed files with 29 additions and 23 deletions

View File

@@ -1,5 +1,5 @@
import { asset } from "$fresh/runtime.ts";
import * as CSS from "https://esm.sh/csstype@3.1.2";
import * as CSS from "csstype";
interface ResponsiveAttributes {
srcset: string;

View File

@@ -26,11 +26,14 @@
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.1",
"@std/http": "jsr:@std/http@^1.0.12",
"@std/yaml": "jsr:@std/yaml@^1.0.5",
"csstype": "npm:csstype@^3.1.3",
"defuddle": "npm:defuddle@^0.6.6",
"drizzle-kit": "npm:drizzle-kit@^0.30.1",
"drizzle-orm": "npm:drizzle-orm@^0.38.3",
"fuzzysort": "npm:fuzzysort@^3.1.0",
"jsdom": "npm:jsdom@^24.1.3",
"moviedb-promise": "npm:moviedb-promise@^4.0.7",
"parse-ingredient": "npm:parse-ingredient@^1.3.1",
"playwright": "npm:playwright@^1.49.1",
"playwright-extra": "npm:playwright-extra@^4.3.6",
"preact": "https://esm.sh/preact@10.22.0",
@@ -42,6 +45,7 @@
"tailwindcss/": "npm:/tailwindcss@^3.4.17/",
"tailwindcss/plugin": "npm:/tailwindcss@^3.4.17/plugin.js",
"camelcase-css": "npm:camelcase-css",
"thumbhash": "npm:thumbhash@^0.1.1",
"tsx": "npm:tsx@^4.19.2",
"yaml": "https://deno.land/std@0.197.0/yaml/mod.ts",
"zod": "npm:zod@^3.24.1",

View File

@@ -43,13 +43,13 @@ const Ingredient = (
return (
<tr key={key}>
<td class="pr-4 py-2">
<td class="pr-4 py-1">
{formatAmount(finalAmount || 0)}
<span class="ml-0.5 opacity-50">
{formatUnit(unit, finalAmount || 0)}
</span>
</td>
<td class="px-4 py-2">{name}</td>
<td class="px-4 py-1">{name}</td>
</tr>
);
};
@@ -66,14 +66,10 @@ export const IngredientsList: FunctionalComponent<
return (
<table class="w-full border-collapse table-auto">
<tbody>
{ingredients.filter((s) => !!s?.length).map((item) => {
{ingredients.map((item) => {
return (
<div dangerouslySetInnerHTML={{ __html: renderMarkdown(item) }}>
</div>
<Ingredient ingredient={item} amount={amount} portion={portion} />
);
// return (
// <Ingredient ingredient={item} amount={amount} portion={portion} />
// );
})}
</tbody>
</table>

View File

@@ -69,7 +69,6 @@ export const SearchResultItem = (
) => {
const resourceType = resources[item?.content._type];
const href = item?.path.replace("/resources", "").replace(/\.md$/, "");
console.log({ item, href });
return (
<a
href={href}

View File

@@ -1,7 +1,7 @@
import {
parseIngredient,
unitsOfMeasure as _unitsOfMeasure,
} from "https://esm.sh/parse-ingredient@1.2.1";
} from "npm:parse-ingredient";
import { Ingredient, IngredientGroup } from "@lib/recipeSchema.ts";
import { removeMarkdownFormatting } from "@lib/string.ts";

View File

@@ -1,4 +1,4 @@
import * as thumbhash from "https://esm.sh/thumbhash@0.1.1";
import * as thumbhash from "thumbhash";
export function generateThumbhash(buffer: Uint8Array, w: number, h: number) {
const hash = thumbhash.rgbaToThumbHash(w, h, buffer);

View File

@@ -5,7 +5,7 @@ import {
MovieResultsResponse,
ShowResponse,
TvResultsResponse,
} from "https://esm.sh/moviedb-promise@3.4.1";
} from "moviedb-promise";
import { createCache } from "@lib/cache.ts";
const moviedb = new MovieDb(Deno.env.get("TMDB_API_KEY") || "");

View File

@@ -24,10 +24,10 @@ export default async function Greet(
return ctx.renderNotFound();
}
const { author = "", datePublished = "" } = movie.content;
const { author = "", datePublished = "",reviewBody } = movie.content;
const content = renderMarkdown(
removeImage(movie.content.reviewBody || "", movie.content.image),
removeImage(reviewBody || "", movie.content.image),
);
return (
@@ -57,7 +57,7 @@ export default async function Greet(
title: author?.name,
href: `/?q=${encodeURIComponent(author?.name)}`,
},
datePublished.toString(),
date.toString(),
]}
>
{movie.content.reviewRating && (

View File

@@ -3,7 +3,6 @@ import { IngredientsList } from "@islands/IngredientsList.tsx";
import { MainLayout } from "@components/layouts/main.tsx";
import Counter from "@islands/Counter.tsx";
import { Signal, useSignal } from "@preact/signals";
import { Recipe } from "@lib/recipeSchema.ts";
import { RedirectSearchHandler } from "@islands/Search.tsx";
import { KMenu } from "@islands/KMenu.tsx";
import PageHero from "@components/PageHero.tsx";
@@ -12,8 +11,12 @@ import { renderMarkdown } from "@lib/markdown.ts";
import { isValidRecipe } from "@lib/recipeSchema.ts";
import { MetaTags } from "@components/MetaTags.tsx";
import { fetchResource } from "@lib/marka/index.ts";
import { RecipeResource } from "@lib/marka/schema.ts";
import { parseIngredients } from "@lib/parseIngredient.ts";
export const handler: Handlers<{ recipe: Recipe; session: unknown } | null> = {
export const handler: Handlers<
{ recipe: RecipeResource; session: unknown } | null
> = {
async GET(_, ctx) {
try {
const recipe = await fetchResource(`recipes/${ctx.params.name}.md`);
@@ -31,7 +34,11 @@ function ValidRecipe({
recipe,
amount,
portion,
}: { recipe: Recipe; amount: Signal<number>; portion: number }) {
}: { recipe: RecipeResource; amount: Signal<number>; portion: number }) {
const ingredients = parseIngredients(
recipe.content.recipeIngredient?.join("\n"),
);
return (
<>
<div class="flex items-center gap-8">
@@ -39,7 +46,7 @@ function ValidRecipe({
{portion && <Counter count={amount} />}
</div>
<IngredientsList
ingredients={recipe.content.recipeIngredient}
ingredients={ingredients}
amount={amount}
portion={portion}
/>

View File

@@ -23,14 +23,14 @@ export const handler: Handlers<{ serie: ReviewResource; session: unknown }> = {
};
export default function Greet(
props: PageProps<{ serie: Series; session: Record<string, string> }>,
props: PageProps<{ serie: ReviewResource; session: Record<string, string> }>,
) {
const { serie, session } = props.data;
const { author = "", date = "" } = serie?.content || {};
const { author = "", date = "", reviewBody } = serie?.content || {};
const content = renderMarkdown(
removeImage(serie.description || "", serie.content?.image),
removeImage(reviewBody, serie.image?.url),
);
return (