feat(ui): wishlist page, recipe toggle button, header link
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 54s

- /wishlist renders cards with avatar-badge of who added it, like count,
  heart toggle for active profile, delete button. Sort dropdown switches
  between popular / newest / oldest.
- /recipes/[id] gets 'Auf Wunschliste (setzen)' button alongside favorite.
- Layout header shows 🍽️ link to /wishlist next to the admin ⚙️.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-17 17:08:22 +02:00
parent 28e40d763d
commit 3b1950713f
3 changed files with 298 additions and 3 deletions

View File

@@ -13,6 +13,7 @@
let comments = $state<CommentRow[]>([]);
let cookingLog = $state<typeof data.cooking_log>([]);
let isFav = $state(false);
let onWishlist = $state(false);
let newComment = $state('');
$effect(() => {
@@ -124,6 +125,31 @@
location.reload();
}
async function toggleWishlist() {
if (onWishlist) {
await fetch(`/api/wishlist/${data.recipe.id}`, { method: 'DELETE' });
onWishlist = false;
} else {
await fetch('/api/wishlist', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
recipe_id: data.recipe.id,
profile_id: profileStore.active?.id ?? null
})
});
onWishlist = true;
}
}
async function refreshWishlistState() {
// No dedicated GET for a single entry; scan the list and check.
const res = await fetch('/api/wishlist?sort=newest');
if (!res.ok) return;
const body = await res.json();
onWishlist = body.entries.some((e: { recipe_id: number }) => e.recipe_id === data.recipe.id);
}
// Wake-Lock
let wakeLock: WakeLockSentinel | null = null;
async function requestWakeLock() {
@@ -139,6 +165,7 @@
onMount(() => {
void requestWakeLock();
void checkFavorite();
void refreshWishlistState();
const onVisibility = () => {
if (document.visibilityState === 'visible' && !wakeLock) void requestWakeLock();
};
@@ -171,6 +198,9 @@
<button class="btn" class:heart={isFav} onclick={toggleFavorite}>
{isFav ? '♥' : '♡'} Favorit
</button>
<button class="btn" class:wish={onWishlist} onclick={toggleWishlist}>
{onWishlist ? '✓' : '🍽️'} {onWishlist ? 'Auf Wunschliste' : 'Auf Wunschliste setzen'}
</button>
<button class="btn" onclick={() => window.print()}>🖨 Drucken</button>
<button class="btn" onclick={renameRecipe}> Umbenennen</button>
<button class="btn danger" onclick={deleteRecipe}>🗑 Löschen</button>
@@ -267,6 +297,11 @@
border-color: #f1b4b4;
background: #fdf3f3;
}
.btn.wish {
color: #2b6a3d;
border-color: #b7d6c2;
background: #eaf4ed;
}
.btn.primary {
background: #2b6a3d;
color: white;