style(recipes): swap heart emoji for lucide icon

Replaces heart/black-heart emoji on the favorite button and the
card favorite indicators with the lucide Heart icon. Favorited
state uses a vivid #ff2d55 fill with layered drop-shadows so the
mark reads against colorful recipe photos; unfavorited button
shows an outlined white heart.
This commit is contained in:
2026-04-23 16:05:19 +02:00
parent b8e5155e2d
commit a8b0d3c722
4 changed files with 38 additions and 17 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "homepage", "name": "homepage",
"version": "1.46.27", "version": "1.46.28",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
+17 -7
View File
@@ -2,6 +2,7 @@
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import { enhance } from '$app/forms'; import { enhance } from '$app/forms';
import { page } from '$app/stores'; import { page } from '$app/stores';
import Heart from '@lucide/svelte/icons/heart';
let { recipeId, isFavorite = $bindable(false), isLoggedIn = false } = $props<{ recipeId: string, isFavorite?: boolean, isLoggedIn?: boolean }>(); let { recipeId, isFavorite = $bindable(false), isLoggedIn = false } = $props<{ recipeId: string, isFavorite?: boolean, isLoggedIn?: boolean }>();
@@ -44,21 +45,28 @@
<style> <style>
.favorite-button { .favorite-button {
all: unset; all: unset;
font-family: "Noto Color Emoji", "Noto Color Emoji Subset", emoji, sans-serif; display: flex;
font-size: 1.5rem; align-items: center;
justify-content: center;
cursor: pointer; cursor: pointer;
transition: var(--transition-fast); transition: var(--transition-fast);
filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5)); filter:
drop-shadow(0 1px 1px rgba(0, 0, 0, 0.6))
drop-shadow(0 0 3px rgba(0, 0, 0, 0.45));
position: absolute; position: absolute;
bottom: 0.5em; bottom: 0.5em;
right: 0.5em; right: 0.5em;
color: white;
} }
.favorite-button.is-favorite {
color: #ff2d55;
}
.favorite-button:disabled { .favorite-button:disabled {
opacity: 0.6; opacity: 0.6;
cursor: not-allowed; cursor: not-allowed;
} }
.favorite-button:hover, .favorite-button:hover,
.favorite-button:focus-visible { .favorite-button:focus-visible {
transform: scale(1.2); transform: scale(1.2);
@@ -69,14 +77,16 @@
<form method="post" action="?/toggleFavorite" style="display: inline;" use:enhance> <form method="post" action="?/toggleFavorite" style="display: inline;" use:enhance>
<input type="hidden" name="recipeId" value={recipeId} /> <input type="hidden" name="recipeId" value={recipeId} />
<input type="hidden" name="isFavorite" value={isFavorite} /> <input type="hidden" name="isFavorite" value={isFavorite} />
<button <button
type="submit" type="submit"
class="favorite-button" class="favorite-button"
class:is-favorite={isFavorite}
disabled={isLoading} disabled={isLoading}
onclick={toggleFavorite} onclick={toggleFavorite}
aria-label={isFavorite ? 'Favorit entfernen' : 'Als Favorit speichern'}
title={isFavorite ? 'Favorit entfernen' : 'Als Favorit speichern'} title={isFavorite ? 'Favorit entfernen' : 'Als Favorit speichern'}
> >
{isFavorite ? '❤️' : '🖤'} <Heart size={24} strokeWidth={2} fill={isFavorite ? 'currentColor' : 'none'} />
</button> </button>
</form> </form>
{/if} {/if}
+11 -5
View File
@@ -2,6 +2,7 @@
import "$lib/css/shake.css"; import "$lib/css/shake.css";
import "$lib/css/icon.css"; import "$lib/css/icon.css";
import { onMount } from "svelte"; import { onMount } from "svelte";
import Heart from '@lucide/svelte/icons/heart';
let { let {
recipe, recipe,
@@ -182,10 +183,13 @@ function preloadHeroImage() {
.favorite-indicator{ .favorite-indicator{
position: absolute; position: absolute;
font-size: 2rem; top: 0.4em;
top: 0.1em; left: 0.4em;
left: 0.1em; display: flex;
filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.8)); color: #ff2d55;
filter:
drop-shadow(0 1px 1px rgba(0, 0, 0, 0.7))
drop-shadow(0 0 4px rgba(0, 0, 0, 0.5));
} }
.translation-badge{ .translation-badge{
@@ -240,7 +244,9 @@ function preloadHeroImage() {
<img class="image" class:loaded={isloaded} src={'https://bocken.org/static/rezepte/thumb/' + img_name} loading={loading_strat} alt="{img_alt}" onload={() => isloaded=true}/> <img class="image" class:loaded={isloaded} src={'https://bocken.org/static/rezepte/thumb/' + img_name} loading={loading_strat} alt="{img_alt}" onload={() => isloaded=true}/>
</div> </div>
{#if showFavoriteIndicator && isFavorite} {#if showFavoriteIndicator && isFavorite}
<div class="favorite-indicator">❤️</div> <div class="favorite-indicator" aria-label="Favorit">
<Heart size={28} strokeWidth={2} fill="currentColor" />
</div>
{/if} {/if}
{#if translationStatus !== undefined} {#if translationStatus !== undefined}
<div class="translation-badge {translationStatus || 'none'}"> <div class="translation-badge {translationStatus || 'none'}">
@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import "$lib/css/shake.css"; import "$lib/css/shake.css";
import Heart from '@lucide/svelte/icons/heart';
let { let {
recipe, recipe,
@@ -143,9 +144,11 @@
position: absolute; position: absolute;
top: 0.5em; top: 0.5em;
left: 0.5em; left: 0.5em;
font-size: 1.1rem; display: flex;
font-family: "Noto Color Emoji", "Noto Color Emoji Subset", emoji, sans-serif; color: #ff2d55;
filter: drop-shadow(0 0 3px rgba(0,0,0,0.8)); filter:
drop-shadow(0 1px 1px rgba(0, 0, 0, 0.7))
drop-shadow(0 0 4px rgba(0, 0, 0, 0.5));
z-index: 2; z-index: 2;
pointer-events: none; pointer-events: none;
} }
@@ -156,7 +159,9 @@
<div class="compact-card" onclick={activateTransitions}> <div class="compact-card" onclick={activateTransitions}>
<a href="{routePrefix}/{recipe.short_name}" class="card-link" aria-label={recipe.name}></a> <a href="{routePrefix}/{recipe.short_name}" class="card-link" aria-label={recipe.name}></a>
{#if showFavoriteIndicator && isFavorite} {#if showFavoriteIndicator && isFavorite}
<span class="favorite">❤️</span> <span class="favorite" aria-label="Favorit">
<Heart size={18} strokeWidth={2} fill="currentColor" />
</span>
{/if} {/if}
<div class="img-wrap" style:background-color={img_color}> <div class="img-wrap" style:background-color={img_color}>
<img <img