feat(editor): Sektionsueberschriften in IngredientRow + Insert-Button

DraftIng bekommt section_heading: string | null. IngredientRow
rendert davor einen Fade-in-Insert-Button (null) oder ein Heading-
Input mit Entfernen-Button (string). Props onaddSection/onremoveSection
ergaenzt; Styles an bestehendem Block angehaengt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-19 15:03:29 +02:00
parent 96cb55495e
commit 526c7433f4
2 changed files with 93 additions and 2 deletions

View File

@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { Trash2, ChevronUp, ChevronDown } from 'lucide-svelte'; import { Trash2, ChevronUp, ChevronDown, Plus, X } from 'lucide-svelte';
import type { DraftIng } from './recipe-editor-types'; import type { DraftIng } from './recipe-editor-types';
type Props = { type Props = {
@@ -8,11 +8,39 @@
total: number; total: number;
onmove: (dir: -1 | 1) => void; onmove: (dir: -1 | 1) => void;
onremove: () => void; onremove: () => void;
onaddSection: () => void;
onremoveSection: () => void;
}; };
let { ing, idx, total, onmove, onremove }: Props = $props(); let { ing, idx, total, onmove, onremove, onaddSection, onremoveSection }: Props = $props();
</script> </script>
{#if ing.section_heading === null}
<li class="section-insert">
<button type="button" class="add-section" onclick={onaddSection}>
<Plus size={12} strokeWidth={2.5} />
<span>Abschnitt hinzufügen</span>
</button>
</li>
{:else}
<li class="section-heading-row">
<input
class="section-heading"
type="text"
bind:value={ing.section_heading}
placeholder='Sektion, z. B. Für den Teig"'
aria-label="Sektionsüberschrift"
/>
<button
type="button"
class="section-remove"
aria-label="Sektion entfernen"
onclick={onremoveSection}
>
<X size={14} strokeWidth={2.5} />
</button>
</li>
{/if}
<li class="ing-row"> <li class="ing-row">
<div class="move"> <div class="move">
<button <button
@@ -126,4 +154,66 @@
grid-area: del; grid-area: del;
} }
} }
.section-insert {
display: flex;
justify-content: center;
list-style: none;
margin: -0.2rem 0 0.1rem;
opacity: 0;
transition: opacity 0.15s;
}
.ing-list:hover .section-insert,
.section-insert:focus-within {
opacity: 1;
}
.add-section {
display: inline-flex;
align-items: center;
gap: 0.25rem;
padding: 0.2rem 0.55rem;
border: 1px dashed #cfd9d1;
background: white;
color: #2b6a3d;
border-radius: 999px;
cursor: pointer;
font-size: 0.75rem;
font-family: inherit;
}
.add-section:hover {
background: #f4f8f5;
}
.section-heading-row {
display: grid;
grid-template-columns: 1fr 32px;
gap: 0.35rem;
list-style: none;
margin-top: 0.4rem;
}
.section-heading {
padding: 0.45rem 0.7rem;
border: 1px solid #cfd9d1;
border-radius: 8px;
font-size: 0.95rem;
font-weight: 600;
color: #2b6a3d;
font-family: inherit;
background: #f4f8f5;
}
.section-remove {
width: 32px;
height: 38px;
border: 1px solid #cfd9d1;
background: white;
border-radius: 8px;
color: #666;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
}
.section-remove:hover {
background: #fdf3f3;
border-color: #f1b4b4;
color: #c53030;
}
</style> </style>

View File

@@ -3,6 +3,7 @@ export type DraftIng = {
unit: string; unit: string;
name: string; name: string;
note: string; note: string;
section_heading: string | null;
}; };
export type DraftStep = { text: string }; export type DraftStep = { text: string };