feat(recipe): Wake-Lock-Schalter + Profil-Chip nur Lucide + Save-Text
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m16s

1) ProfileSwitcher-Chip: Profil-Emoji (avatar_emoji) ist jetzt aus dem
   Header-Badge raus — immer CircleUser-Icon vor dem Namen. Im Profil-
   Auswahl-Modal bleiben die individuellen Emojis erhalten, damit User
   ihr Profil dort weiterhin erkennen. Unused .emoji CSS entfernt.

2) Preview-Button: "In meine Sammlung speichern" → "Rezept in Kochwas
   speichern". Klarer, was die App heißt.

3) Wake-Lock-Schalter:
   - Erklärung: navigator.wakeLock.request('screen') hindert Android/iOS
     daran, das Display zu dimmen/zu sperren, solange der Tab sichtbar
     ist. Beim Kochen sehr nützlich — Hände sind klebrig.
   - Neuer Toggle-Button im Rezept-Detail, zweite Aktion-Zeile zwischen
     "Heute gekocht" und "Löschen": Lightbulb (an, gelb-gehighlighted)
     oder LightbulbOff (aus).
   - Preference wird in localStorage persistiert (kochwas.wakeLock),
     Default an. Gilt für alle Rezepte.
   - visibilitychange-Handler re-requestet den Sentinel, wenn User den
     Tab wieder nach vorne holt und die Pref an ist.
   - release-Event räumt wakeLock-Variable sauber auf.
This commit is contained in:
hsiegeln
2026-04-17 19:21:28 +02:00
parent 60021b879f
commit 018fc987cd
3 changed files with 65 additions and 13 deletions

View File

@@ -24,11 +24,10 @@
</script>
<button class="chip" onclick={() => (showModal = true)} aria-label="Profil wechseln">
<span class="icon"><CircleUser size={20} strokeWidth={1.75} /></span>
{#if profileStore.active}
<span class="emoji">{profileStore.active.avatar_emoji ?? '🙂'}</span>
<span class="name">{profileStore.active.name}</span>
{:else}
<span class="icon"><CircleUser size={20} strokeWidth={1.75} /></span>
<span class="name">Profil wählen</span>
{/if}
</button>
@@ -105,9 +104,6 @@
.chip:hover {
background: #f4f8f5;
}
.emoji {
font-size: 1.1rem;
}
.icon {
display: inline-flex;
align-items: center;

View File

@@ -90,7 +90,7 @@
<span>Speichern…</span>
{:else}
<BookmarkPlus size={18} strokeWidth={2} />
<span>In meine Sammlung speichern</span>
<span>Rezept in Kochwas speichern</span>
{/if}
</button>
<button type="button" class="btn ghost" onclick={() => history.back()}>Zurück</button>

View File

@@ -9,7 +9,9 @@
Trash2,
ChefHat,
Check,
X
X,
Lightbulb,
LightbulbOff
} from 'lucide-svelte';
import RecipeView from '$lib/components/RecipeView.svelte';
import StarRating from '$lib/components/StarRating.svelte';
@@ -225,29 +227,62 @@
void wishlistStore.refresh();
}
// Wake-Lock
// Wake-Lock — Bildschirm beim Kochen nicht dimmen lassen.
// Browser-API navigator.wakeLock.request('screen') verhindert auto-lock
// und -dimmen, solange der Tab sichtbar ist. Sobald der Tab in den
// Hintergrund geht, verliert der Sentinel seine Wirkung von selbst; wir
// re-requesten bei visibilitychange.
let wakeLockEnabled = $state(true);
let wakeLock: WakeLockSentinel | null = null;
async function requestWakeLock() {
async function acquireWakeLock() {
if (wakeLock || !wakeLockEnabled) return;
try {
if ('wakeLock' in navigator) {
wakeLock = await navigator.wakeLock.request('screen');
wakeLock.addEventListener('release', () => {
wakeLock = null;
});
}
} catch {
// silently ignore
// User hat es gecancelt oder Browser unterstützt es nicht — ignorieren
}
}
async function releaseWakeLock() {
if (!wakeLock) return;
try {
await wakeLock.release();
} catch {
// ignore
}
wakeLock = null;
}
function toggleWakeLock() {
wakeLockEnabled = !wakeLockEnabled;
if (typeof window !== 'undefined') {
localStorage.setItem('kochwas.wakeLock', wakeLockEnabled ? '1' : '0');
}
if (wakeLockEnabled) void acquireWakeLock();
else void releaseWakeLock();
}
onMount(() => {
void requestWakeLock();
const stored = localStorage.getItem('kochwas.wakeLock');
if (stored !== null) wakeLockEnabled = stored === '1';
if (wakeLockEnabled) void acquireWakeLock();
const onVisibility = () => {
if (document.visibilityState === 'visible' && !wakeLock) void requestWakeLock();
if (document.visibilityState === 'visible' && wakeLockEnabled && !wakeLock) {
void acquireWakeLock();
}
};
document.addEventListener('visibilitychange', onVisibility);
return () => document.removeEventListener('visibilitychange', onVisibility);
});
onDestroy(() => {
if (wakeLock) void wakeLock.release();
void releaseWakeLock();
});
</script>
@@ -314,6 +349,22 @@
<span class="count">({cookingLog.length})</span>
{/if}
</button>
<button
class="btn"
class:screen-on={wakeLockEnabled}
onclick={toggleWakeLock}
aria-label={wakeLockEnabled
? 'Bildschirm bleibt an — zum Deaktivieren klicken'
: 'Bildschirm darf dimmen — zum Aktivieren klicken'}
>
{#if wakeLockEnabled}
<Lightbulb size={18} strokeWidth={2} />
<span>Bildschirm an</span>
{:else}
<LightbulbOff size={18} strokeWidth={2} />
<span>Bildschirm aus</span>
{/if}
</button>
<button class="btn danger" onclick={deleteRecipe}>
<Trash2 size={18} strokeWidth={2} />
<span>Löschen</span>
@@ -476,6 +527,11 @@
border-color: #b7d6c2;
background: #eaf4ed;
}
.btn.screen-on {
color: #b07e00;
border-color: #e6d48a;
background: #fff6d7;
}
.btn.primary {
background: #2b6a3d;
color: white;