feat(recipes): M5.b — recipes adopt the unified visibility system

Seventh consumer of @mana/shared-privacy. Recipes now carry a
VisibilityLevel; the recipes.recipes embed powers "my cookbook" /
"tested recipes" sections on the owner's website.

Changes:
- recipes/types: visibility + unlistedToken + visibilityChangedAt +
  visibilityChangedBy on LocalRecipe; Recipe (UI) requires visibility
- recipes/queries: toRecipe forwards visibility with 'space' fallback
- recipes/stores/recipes: createRecipe stamps
  defaultVisibilityFor(activeSpace.type); duplicateRecipe resets to
  the space default (copies don't inherit public status — same rule
  as picture boards); new setVisibility(id, level) emits
  cross-module VisibilityChanged
- recipes/ListView: <VisibilityPicker> as the first row of the
  detail-panel when a card is expanded. Recipes has no dedicated
  detail route so inline-expand is the canonical surface

website embed:
- website-blocks/moduleEmbed/schema: 'recipes.recipes' added to
  EmbedSourceSchema
- website/embeds: resolveRecipes gates hard on canEmbedOnWebsite,
  optional isFavorite + tagIds filters, favourites-first then newest,
  inlines { title, subtitle ('30 Min · 4 Port.'), imageUrl }.
  Ingredients + steps + internal tag labels stay out of the snapshot —
  the embed is a teaser; full recipes are a later M8 unlisted-page
  feature.

Verified:
- pnpm check (web): 7450 files, 0 errors

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-24 14:04:14 +02:00
parent 2af2a4d5c0
commit 0e0d48acec
6 changed files with 118 additions and 0 deletions

View file

@ -33,6 +33,7 @@ export const EmbedSourceSchema = z.enum([
'todo.tasks',
'goals.goals',
'places.places',
'recipes.recipes',
]);
export type EmbedSource = z.infer<typeof EmbedSourceSchema>;