recipes: add shared "to try" list for external recipes

Household-shared list of external recipes to try, with name, multiple
links, and optional notes. Includes add/edit/delete with confirmation.
Linked from the favorites page via a styled pill button.
This commit is contained in:
2026-02-18 21:01:16 +01:00
parent f7d2d993e3
commit e2e3cc4adf
6 changed files with 680 additions and 1 deletions
+162
View File
@@ -0,0 +1,162 @@
<script>
let { item, ondelete, onedit, isEnglish = false } = $props();
function getDomain(url) {
try {
return new URL(url).hostname.replace(/^www\./, '');
} catch {
return url;
}
}
</script>
<style>
.card {
position: relative;
display: flex;
flex-direction: column;
border-radius: var(--radius-card);
overflow: hidden;
background: var(--color-surface);
box-shadow: 0 1px 4px rgba(0,0,0,0.08);
transition: transform var(--transition-normal), box-shadow var(--transition-normal);
}
.card:hover,
.card:focus-within {
transform: translateY(-5px);
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}
.accent {
height: 6px;
background: linear-gradient(90deg, var(--nord10), var(--nord9));
}
.body {
padding: 0.8em 0.9em 0.6em;
flex: 1;
display: flex;
flex-direction: column;
gap: 0.5em;
}
.name {
font-size: 1.1rem;
font-weight: 600;
line-height: 1.3;
margin: 0;
}
.links {
display: flex;
flex-wrap: wrap;
gap: 0.35em;
}
.link-pill {
font-size: 0.78rem;
padding: 0.15rem 0.55rem;
border-radius: var(--radius-pill);
background-color: var(--nord5);
color: var(--nord3);
text-decoration: none;
box-shadow: var(--shadow-sm);
transition: transform var(--transition-fast), background-color var(--transition-fast), box-shadow var(--transition-fast), color var(--transition-fast);
}
.link-pill:hover,
.link-pill:focus-visible {
transform: scale(1.05);
background-color: var(--nord8);
box-shadow: var(--shadow-hover);
color: var(--nord0);
}
@media (prefers-color-scheme: dark) {
.link-pill {
background-color: var(--nord0);
color: var(--nord4);
}
.link-pill:hover,
.link-pill:focus-visible {
background-color: var(--nord8);
color: var(--nord0);
}
}
.notes {
font-size: 0.85rem;
color: var(--nord3);
margin: 0;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
@media (prefers-color-scheme: dark) {
.notes {
color: var(--nord4);
}
}
.footer {
font-size: 0.72rem;
color: var(--nord3);
margin-top: auto;
padding-top: 0.3em;
}
@media (prefers-color-scheme: dark) {
.footer {
color: var(--nord4);
}
}
.card-btn {
position: absolute;
top: 0.5em;
background: var(--nord11);
color: white;
border: none;
border-radius: var(--radius-pill);
width: 1.6em;
height: 1.6em;
font-size: 0.85rem;
cursor: pointer;
display: grid;
place-items: center;
opacity: 0;
transition: opacity var(--transition-fast);
z-index: 2;
}
.card:hover .card-btn,
.card:focus-within .card-btn {
opacity: 1;
}
.delete-btn {
right: 0.5em;
}
.delete-btn:hover {
background: var(--nord12);
}
.edit-btn {
right: 2.4em;
background: var(--nord10);
}
.edit-btn:hover {
background: var(--nord9);
}
</style>
<div class="card">
<div class="accent"></div>
<button class="card-btn edit-btn" onclick={() => onedit(item)} aria-label={isEnglish ? 'Edit' : 'Bearbeiten'}></button>
<button class="card-btn delete-btn" onclick={() => ondelete(item._id)} aria-label={isEnglish ? 'Delete' : 'Löschen'}></button>
<div class="body">
<p class="name">{item.name}</p>
{#if item.links?.length}
<div class="links">
{#each item.links as link (link.url)}
<a class="link-pill g-pill" href={link.url} target="_blank" rel="noopener noreferrer">
{link.label || getDomain(link.url)}
</a>
{/each}
</div>
{/if}
{#if item.notes}
<p class="notes">{item.notes}</p>
{/if}
<div class="footer">
{isEnglish ? 'Added by' : 'Hinzugefügt von'} {item.addedBy}
</div>
</div>
</div>