feat(planner): align tile design with spec
Front face: - Full dual gradient overlay (dark top 32% → transparent → dark bottom 55%) - Day abbreviation + date number pill at top of each tile - Recipe name 13px/weight-300 with text-shadow - Meta line (cookTimeMin · effort) below name - Glassmorphism tag pills (protein + cuisine only) - State rings via box-shadow (yellow for today, green for selected) - Dimming (opacity 0.42) on non-selected filled tiles Back face: - Koch-Modus as green primary button - Entfernen as red outline (transparent bg) - All buttons 11px / weight 500 EmptyDayTile: add day header + spec-aligned suggestion list layout Page: remove external column header (now rendered inside each tile) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import EmptyDayTile from './EmptyDayTile.svelte';
|
import EmptyDayTile from './EmptyDayTile.svelte';
|
||||||
|
import { formatDayAbbr } from '$lib/planner/week';
|
||||||
|
|
||||||
interface TagItem {
|
interface TagItem {
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -57,10 +58,23 @@
|
|||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
const slotId = $derived(slot.id ?? '');
|
const slotId = $derived(slot.id ?? '');
|
||||||
|
|
||||||
const isFlipped = $derived(activeSlotId === slot.id && !!slot.recipe);
|
const isFlipped = $derived(activeSlotId === slot.id && !!slot.recipe);
|
||||||
const isDimmed = $derived(activeSlotId !== null && activeSlotId !== slot.id && !!slot.recipe);
|
const isDimmed = $derived(activeSlotId !== null && activeSlotId !== slot.id && !!slot.recipe);
|
||||||
|
|
||||||
|
const dayAbbr = $derived(slot.slotDate ? formatDayAbbr(slot.slotDate, 'short') : '');
|
||||||
|
const dateNum = $derived(slot.slotDate ? slot.slotDate.slice(-2).replace(/^0/, '') : '');
|
||||||
|
|
||||||
|
const visibleTags = $derived(
|
||||||
|
(slot.recipe?.tags ?? []).filter((t) => t.tagType === 'protein' || t.tagType === 'cuisine')
|
||||||
|
);
|
||||||
|
|
||||||
|
const metaLine = $derived((() => {
|
||||||
|
const parts: string[] = [];
|
||||||
|
if (slot.recipe?.cookTimeMin) parts.push(`${slot.recipe.cookTimeMin} Min`);
|
||||||
|
if (slot.recipe?.effort) parts.push(slot.recipe.effort);
|
||||||
|
return parts.join(' · ');
|
||||||
|
})());
|
||||||
|
|
||||||
function handleFlip() {
|
function handleFlip() {
|
||||||
onflip?.(slotId);
|
onflip?.(slotId);
|
||||||
}
|
}
|
||||||
@@ -103,21 +117,49 @@
|
|||||||
data-flipped={isFlipped}
|
data-flipped={isFlipped}
|
||||||
data-dimmed={isDimmed}
|
data-dimmed={isDimmed}
|
||||||
class="scene"
|
class="scene"
|
||||||
|
class:scene-today={isToday && !isFlipped}
|
||||||
|
class:scene-selected={isFlipped}
|
||||||
|
class:scene-dimmed={isDimmed}
|
||||||
onclick={handleFlip}
|
onclick={handleFlip}
|
||||||
onkeydown={handleKeydown}
|
onkeydown={handleKeydown}
|
||||||
>
|
>
|
||||||
<div class="card" class:flipped={isFlipped}>
|
<div class="card" class:flipped={isFlipped}>
|
||||||
|
|
||||||
|
<!-- FRONT -->
|
||||||
<div
|
<div
|
||||||
class="card-front"
|
class="card-front"
|
||||||
style="background: {gradientBackground}; background-size: cover; background-position: center;"
|
style="background: {gradientBackground}; background-size: cover; background-position: center;"
|
||||||
>
|
>
|
||||||
<div class="card-front-scrim">
|
<!-- Full-tile dual gradient overlay -->
|
||||||
<p style="font-family: var(--font-display); font-size: 15px; margin: 0; color: #fff;">
|
<div class="tile-overlay"></div>
|
||||||
{slot.recipe.name}
|
|
||||||
</p>
|
<!-- Day header -->
|
||||||
|
<div class="tile-head">
|
||||||
|
<span class="tile-day-abbr">{dayAbbr}</span>
|
||||||
|
<span class="tile-day-num" class:dn-today={isToday} class:dn-selected={isFlipped}>
|
||||||
|
{dateNum}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recipe info at bottom -->
|
||||||
|
<div class="tile-info">
|
||||||
|
<p class="tile-name">{slot.recipe.name}</p>
|
||||||
|
{#if metaLine}
|
||||||
|
<p class="tile-meta">{metaLine}</p>
|
||||||
|
{/if}
|
||||||
|
{#if visibleTags.length > 0}
|
||||||
|
<div class="tile-tags">
|
||||||
|
{#each visibleTags as tag (tag.id)}
|
||||||
|
<span class="tile-tag" class:tag-today={isToday} class:tag-selected={isFlipped}>
|
||||||
|
{tag.name}
|
||||||
|
</span>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- BACK -->
|
||||||
<div class="card-back" aria-hidden={!isFlipped}>
|
<div class="card-back" aria-hidden={!isFlipped}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -128,24 +170,16 @@
|
|||||||
×
|
×
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{#if slot.recipe.cookTimeMin || slot.recipe.effort}
|
<p class="back-name">{slot.recipe.name}</p>
|
||||||
<div style="display: flex; gap: 6px; margin-bottom: 8px; flex-wrap: wrap;">
|
{#if metaLine}
|
||||||
{#if slot.recipe.cookTimeMin}
|
<p class="back-meta">{metaLine}</p>
|
||||||
<span class="meta-chip">{slot.recipe.cookTimeMin} min</span>
|
|
||||||
{/if}
|
|
||||||
{#if slot.recipe.effort}
|
|
||||||
<span class="meta-chip">{slot.recipe.effort}</span>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div style="display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px;">
|
<div class="back-actions">
|
||||||
<a class="btn-action" href="/recipes/{slot.recipe.id}/cook" onclick={(e) => e.stopPropagation()}>Koch-Modus</a>
|
<a class="btn-action btn-primary" href="/recipes/{slot.recipe.id}/cook" onclick={(e) => e.stopPropagation()}>Koch-Modus</a>
|
||||||
<a class="btn-action" href="/recipes/{slot.recipe.id}" onclick={(e) => e.stopPropagation()}>Rezept ansehen</a>
|
<a class="btn-action" href="/recipes/{slot.recipe.id}" onclick={(e) => e.stopPropagation()}>Rezept ansehen</a>
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if isPlanner}
|
{#if isPlanner}
|
||||||
<div style="display: flex; flex-direction: column; gap: 4px;">
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn-action"
|
class="btn-action"
|
||||||
@@ -163,9 +197,10 @@
|
|||||||
Entfernen
|
Entfernen
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -180,12 +215,34 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
/* ── Scene (outermost positioned element) ── */
|
||||||
.scene {
|
.scene {
|
||||||
perspective: 900px;
|
perspective: 900px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 1px 3px rgba(28,28,24,.06), 0 1px 2px rgba(28,28,24,.04);
|
||||||
|
transition: box-shadow .15s, opacity .15s;
|
||||||
}
|
}
|
||||||
|
.scene:hover {
|
||||||
|
box-shadow: 0 6px 18px rgba(28,28,24,.14), 0 2px 6px rgba(28,28,24,.08);
|
||||||
|
}
|
||||||
|
.scene-today {
|
||||||
|
box-shadow: 0 0 0 2px var(--yellow), 0 1px 3px rgba(28,28,24,.06);
|
||||||
|
}
|
||||||
|
.scene-today:hover {
|
||||||
|
box-shadow: 0 0 0 2px var(--yellow), 0 6px 18px rgba(28,28,24,.14);
|
||||||
|
}
|
||||||
|
.scene-selected {
|
||||||
|
box-shadow: 0 0 0 2px var(--green-dark), 0 6px 18px rgba(28,28,24,.14);
|
||||||
|
}
|
||||||
|
.scene-dimmed {
|
||||||
|
opacity: 0.42;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Card flip ── */
|
||||||
.card {
|
.card {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -205,21 +262,101 @@
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Front face ── */
|
||||||
|
.tile-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
rgba(0,0,0,.32) 0%,
|
||||||
|
rgba(0,0,0,0) 30%,
|
||||||
|
rgba(0,0,0,0) 45%,
|
||||||
|
rgba(0,0,0,.55) 100%
|
||||||
|
);
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
|
.tile-head {
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0; right: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 7px 8px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.tile-day-abbr {
|
||||||
|
font-size: 9px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: .06em;
|
||||||
|
color: rgba(255,255,255,.85);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.tile-day-num {
|
||||||
|
width: 20px; height: 20px;
|
||||||
|
border-radius: 9999px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(255,255,255,.9);
|
||||||
|
background: rgba(255,255,255,.22);
|
||||||
|
}
|
||||||
|
.dn-today {
|
||||||
|
background: var(--yellow) !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
.dn-selected {
|
||||||
|
background: var(--green-dark) !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
.tile-info {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0; left: 0; right: 0;
|
||||||
|
padding: 8px 9px 9px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.tile-name {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 300;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 1.3;
|
||||||
|
margin: 0;
|
||||||
|
text-shadow: 0 1px 3px rgba(0,0,0,.4);
|
||||||
|
}
|
||||||
|
.tile-meta {
|
||||||
|
font-size: 10px;
|
||||||
|
color: rgba(255,255,255,.75);
|
||||||
|
margin: 2px 0 0;
|
||||||
|
}
|
||||||
|
.tile-tags {
|
||||||
|
display: flex;
|
||||||
|
gap: 3px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
.tile-tag {
|
||||||
|
font-size: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 2px 5px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: rgba(255,255,255,.2);
|
||||||
|
color: rgba(255,255,255,.92);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
.tag-today { background: rgba(242,193,46,.35); }
|
||||||
|
.tag-selected { background: rgba(46,110,57,.45); }
|
||||||
|
|
||||||
|
/* ── Back face ── */
|
||||||
.card-back {
|
.card-back {
|
||||||
transform: rotateY(180deg);
|
transform: rotateY(180deg);
|
||||||
background: var(--color-page);
|
background: var(--color-page);
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
display: flex;
|
||||||
.card-front-scrim {
|
flex-direction: column;
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
padding: 20px 8px 8px;
|
|
||||||
background: linear-gradient(to bottom, transparent 0%, rgba(0, 0, 0, 0.55) 100%);
|
|
||||||
border-radius: 0 0 10px 10px;
|
|
||||||
}
|
}
|
||||||
.btn-close {
|
.btn-close {
|
||||||
background: none;
|
background: none;
|
||||||
@@ -229,47 +366,61 @@
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
color: var(--color-text-muted);
|
color: var(--color-text-muted);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
float: right;
|
align-self: flex-end;
|
||||||
margin: -4px -4px 4px 4px;
|
margin: -4px -4px 2px 0;
|
||||||
}
|
}
|
||||||
.btn-close:hover {
|
.btn-close:hover { color: var(--color-text); }
|
||||||
|
.back-name {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 300;
|
||||||
|
margin: 0 0 2px;
|
||||||
|
line-height: 1.3;
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
.meta-chip {
|
.back-meta {
|
||||||
font-size: 11px;
|
font-size: 10px;
|
||||||
padding: 2px 7px;
|
|
||||||
border-radius: 99px;
|
|
||||||
background: var(--color-surface);
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
color: var(--color-text-muted);
|
color: var(--color-text-muted);
|
||||||
|
margin: 0 0 10px;
|
||||||
|
}
|
||||||
|
.back-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
.btn-action {
|
.btn-action {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 6px 10px;
|
padding: 7px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
background: var(--color-surface);
|
background: #fff;
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
font-size: 12px;
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: .04em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
.btn-action:hover {
|
.btn-action:hover { background: var(--color-surface); }
|
||||||
background: var(--color-border);
|
.btn-primary {
|
||||||
|
background: var(--green-dark);
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
.btn-primary:hover { background: var(--green-dark); filter: brightness(1.1); }
|
||||||
.btn-danger {
|
.btn-danger {
|
||||||
color: var(--color-destructive, #dc2626);
|
color: #dc4c3e;
|
||||||
border-color: var(--color-destructive, #dc2626);
|
border-color: #dc4c3e;
|
||||||
}
|
background: transparent;
|
||||||
.btn-danger:hover {
|
|
||||||
background: color-mix(in srgb, var(--color-destructive, #dc2626) 10%, transparent);
|
|
||||||
}
|
}
|
||||||
|
.btn-danger:hover { background: rgba(220,76,62,.08); }
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.card {
|
.card { transition: none; }
|
||||||
transition: none;
|
.scene { transition: none; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ describe('DesktopDayTile — filled slot', () => {
|
|||||||
describe('front face', () => {
|
describe('front face', () => {
|
||||||
it('renders recipe name on front face', () => {
|
it('renders recipe name on front face', () => {
|
||||||
render(DesktopDayTile, { props: { slot: filledSlot, isToday: false, activeSlotId: null, isPlanner: true, slotMap: {}, suggestions: [] } });
|
render(DesktopDayTile, { props: { slot: filledSlot, isToday: false, activeSlotId: null, isPlanner: true, slotMap: {}, suggestions: [] } });
|
||||||
expect(screen.getByText('Pasta Bolognese')).toBeTruthy();
|
expect(screen.getAllByText('Pasta Bolognese').length).toBeGreaterThanOrEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has data-testid="day-meal-card" on the scene element', () => {
|
it('has data-testid="day-meal-card" on the scene element', () => {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computeReasoningTags } from './reasoningTags';
|
import { computeReasoningTags } from './reasoningTags';
|
||||||
|
import { formatDayAbbr } from '$lib/planner/week';
|
||||||
|
|
||||||
interface TagItem {
|
interface TagItem {
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -46,44 +47,52 @@
|
|||||||
let reasoningTags = $derived(
|
let reasoningTags = $derived(
|
||||||
topSuggestion ? computeReasoningTags(slotMap, topSuggestion.recipe) : []
|
topSuggestion ? computeReasoningTags(slotMap, topSuggestion.recipe) : []
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const dayAbbr = $derived(slotDate ? formatDayAbbr(slotDate, 'short') : '');
|
||||||
|
const dateNum = $derived(slotDate ? slotDate.slice(-2).replace(/^0/, '') : '');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
data-testid="empty-day-tile"
|
data-testid="empty-day-tile"
|
||||||
role="group"
|
role="group"
|
||||||
class="h-full flex flex-col gap-2 p-3"
|
class="h-full flex flex-col overflow-hidden"
|
||||||
style="border: 1px dashed var(--color-border);"
|
style="border: 1.5px dashed var(--color-border); border-radius: 10px; background: var(--color-surface); box-shadow: 0 1px 3px rgba(28,28,24,.06);"
|
||||||
>
|
>
|
||||||
|
<!-- Day header -->
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; padding: 7px 8px 0; flex-shrink: 0;">
|
||||||
|
<span style="font-size: 9px; text-transform: uppercase; letter-spacing: .06em; color: var(--color-text-muted); font-weight: 500;">{dayAbbr}</span>
|
||||||
|
<span style="font-size: 10px; font-weight: 500; color: var(--color-text-muted);">{dateNum}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CTA -->
|
||||||
{#if isPlanner}
|
{#if isPlanner}
|
||||||
<button
|
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 8px 6px 6px; gap: 2px; flex-shrink: 0; border-bottom: 1px solid var(--color-border);">
|
||||||
type="button"
|
<button
|
||||||
aria-label="Gericht wählen"
|
type="button"
|
||||||
onclick={() => onaddrecipe?.()}
|
aria-label="Gericht wählen"
|
||||||
class="self-start font-[var(--font-sans)] text-[13px] text-[var(--color-text-muted)] hover:text-[var(--color-text)] transition-colors"
|
onclick={() => onaddrecipe?.()}
|
||||||
>
|
style="background: none; border: none; cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: 2px;"
|
||||||
+ Gericht wählen
|
>
|
||||||
</button>
|
<span style="font-size: 18px; color: var(--color-border); line-height: 1;">+</span>
|
||||||
|
<span style="font-size: 9px; color: var(--color-text-muted); font-family: var(--font-sans);">Gericht wählen</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if topSuggestion}
|
{#if topSuggestion}
|
||||||
<p class="font-[var(--font-display)] text-[12px] text-[var(--color-text-muted)] leading-snug">
|
<div style="display: flex; flex-direction: column; padding: 5px 7px 6px; flex: 1; overflow: hidden;">
|
||||||
{topSuggestion.recipe.name}
|
<div style="font-size: 8px; font-weight: 500; letter-spacing: .07em; text-transform: uppercase; color: var(--color-text-muted); padding: 3px 0 5px; border-bottom: 1px solid var(--color-subtle, var(--color-border)); margin-bottom: 2px;">Vorschlag</div>
|
||||||
</p>
|
<div style="display: flex; align-items: center; gap: 4px; padding: 5px 0;">
|
||||||
|
<span style="font-family: var(--font-display); font-size: 11px; font-weight: 300; color: var(--color-text); flex: 1; line-height: 1.2;">{topSuggestion.recipe.name}</span>
|
||||||
{#if reasoningTags.length > 0}
|
|
||||||
<div class="flex flex-wrap gap-1">
|
|
||||||
{#each reasoningTags as tag (tag.id)}
|
{#each reasoningTags as tag (tag.id)}
|
||||||
<span
|
<span
|
||||||
data-testid="reasoning-tag"
|
data-testid="reasoning-tag"
|
||||||
class="inline-block rounded px-1.5 py-0.5 font-[var(--font-sans)] text-[11px] font-medium"
|
style="font-size: 8px; font-weight: 500; padding: 1px 4px; border-radius: 2px; white-space: nowrap; flex-shrink: 0; {tag.color === 'green' ? 'background: var(--green-tint); color: var(--green-dark);' : 'background: var(--yellow-tint); color: var(--yellow-text);'}"
|
||||||
style={tag.color === 'green'
|
|
||||||
? 'background: var(--green-tint); color: var(--green-dark);'
|
|
||||||
: 'background: var(--yellow-tint); color: var(--yellow-text);'}
|
|
||||||
>
|
>
|
||||||
{tag.label}
|
{tag.label}
|
||||||
</span>
|
</span>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -477,26 +477,9 @@
|
|||||||
{#each days as day (day)}
|
{#each days as day (day)}
|
||||||
{@const slot = slotMap[day] ?? { id: null, slotDate: day, recipe: null }}
|
{@const slot = slotMap[day] ?? { id: null, slotDate: day, recipe: null }}
|
||||||
{@const isTodayDay = day === today}
|
{@const isTodayDay = day === today}
|
||||||
{@const dateNum = day.slice(-2).replace(/^0/, '')}
|
|
||||||
{@const dayAbbr = formatDayAbbr(day, 'narrow')}
|
|
||||||
{@const isThisTileActive = drawerSlotId === day}
|
{@const isThisTileActive = drawerSlotId === day}
|
||||||
|
|
||||||
<div class="flex h-full flex-col">
|
<div class="h-full">
|
||||||
<!-- Column header -->
|
|
||||||
<div class="mb-2 flex flex-col items-center gap-1">
|
|
||||||
<p class="font-[var(--font-sans)] text-[9px] uppercase tracking-wide text-[var(--color-text-muted)]">
|
|
||||||
{dayAbbr}
|
|
||||||
</p>
|
|
||||||
<div
|
|
||||||
class="flex h-6 w-6 items-center justify-center rounded-full text-[11px] font-medium
|
|
||||||
{isTodayDay ? 'bg-[var(--yellow)] text-white' : 'bg-transparent text-[var(--color-text)]'}"
|
|
||||||
>
|
|
||||||
{dateNum}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Flip tile -->
|
|
||||||
<div class="min-h-0 flex-1">
|
|
||||||
<DesktopDayTile
|
<DesktopDayTile
|
||||||
{slot}
|
{slot}
|
||||||
isToday={isTodayDay}
|
isToday={isTodayDay}
|
||||||
@@ -511,7 +494,6 @@
|
|||||||
onremove={() => handleTileRemove(slot)}
|
onremove={() => handleTileRemove(slot)}
|
||||||
onaddrecipe={() => handleEmptyTileAdd(day)}
|
onaddrecipe={() => handleEmptyTileAdd(day)}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user