feat(ui): wishlist page, recipe toggle button, header link
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 54s
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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user