diff --git a/apps/todo/apps/web/src/routes/(app)/+page.svelte b/apps/todo/apps/web/src/routes/(app)/+page.svelte index 01b88780c..5921fd03a 100644 --- a/apps/todo/apps/web/src/routes/(app)/+page.svelte +++ b/apps/todo/apps/web/src/routes/(app)/+page.svelte @@ -2,7 +2,7 @@ import { onMount } from 'svelte'; import { format, addDays, subDays, startOfDay } from 'date-fns'; import { de } from 'date-fns/locale'; - import { ListChecks } from '@manacore/shared-icons'; + import { ListChecks, Sparkle, ArrowDown } from '@manacore/shared-icons'; import { tasksStore } from '$lib/stores/tasks.svelte'; import { viewStore } from '$lib/stores/view.svelte'; import TaskList from '$lib/components/TaskList.svelte'; @@ -80,6 +80,30 @@ completedTasks.length === 0 ); + // Section visibility logic - show only sections with tasks (except "Today" which is always shown when not all empty) + let showTodaySection = $derived(todayTasks.length > 0 || !allEmpty); + let showTomorrowSection = $derived(tomorrowTasks.length > 0); + let showUpcomingSection = $derived(upcomingCount > 0); + let showCompletedSection = $derived(completedTasks.length > 0); + + // Onboarding tip: show when user has 1-3 active tasks + let totalActiveTasks = $derived( + overdueTasks.length + todayTasks.length + tomorrowTasks.length + upcomingCount + ); + let showOnboardingTip = $derived(totalActiveTasks > 0 && totalActiveTasks <= 3); + + // Syntax example snippets for empty state + const syntaxExamples = [ + { text: 'Meeting morgen 14 Uhr', description: 'Datum & Uhrzeit' }, + { text: 'Einkaufen #privat', description: 'Mit Label' }, + { text: 'Wichtig erledigen !hoch', description: 'Mit Priorität' }, + ]; + + // Handle clicking a syntax example + function handleExampleClick(text: string) { + window.dispatchEvent(new CustomEvent('quick-input-set', { detail: { text } })); + } + // Modal handlers function openEditModal(task: Task) { editingTask = task; @@ -152,11 +176,6 @@
-
-

Meine Aufgaben

-

Alle deine Aufgaben auf einen Blick

-
- {#if isLoading || tasksStore.loading} {:else if tasksStore.error} @@ -164,12 +183,42 @@ {tasksStore.error}
{:else if allEmpty} -
-
- + +
+
+ +
+ +
+ + +

Bereit für einen produktiven Tag

+ + +
+

Tippe unten um loszulegen...

+
+ +
+
+ + +
+

Schnellstart-Tipps

+
+ {#each syntaxExamples as example} + + {/each} +
+
-

Noch keine Aufgaben

-

Erstelle deine erste Aufgabe mit dem Eingabefeld oben.

{:else}
@@ -192,92 +241,101 @@ {/if} - - - - + + {#if showTodaySection} + + + + {/if} - - - - + + {#if showTomorrowSection} + + + + {/if} - - -
- {#each groupedUpcomingTasks() as group} -
-

- {group.label} ({group.tasks.length}) -

- -
- {/each} - {#if upcomingCount === 0} - - - {/if} + + {#if showUpcomingSection} + +
+ {#each groupedUpcomingTasks() as group} +
+

+ {group.label} ({group.tasks.length}) +

+ +
+ {/each} +
+
+ {/if} + + + {#if showCompletedSection} + + + + {/if} + + + {#if showOnboardingTip} +
+ 💡 + + Tipp: Nutze #tags und !priorität für bessere Organisation +
- - - - - - + {/if}
{/if}
@@ -297,4 +355,148 @@ .unified-view { padding-bottom: 100px; } + + /* Empty state container */ + .empty-state-container { + display: flex; + justify-content: center; + align-items: center; + min-height: 60vh; + padding: 2rem; + } + + .empty-state-content { + text-align: center; + max-width: 400px; + } + + .empty-state-icon { + display: flex; + justify-content: center; + margin-bottom: 1.5rem; + color: hsl(var(--color-primary)); + animation: float 3s ease-in-out infinite; + } + + @keyframes float { + 0%, + 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-8px); + } + } + + .empty-state-title { + font-size: 1.5rem; + font-weight: 600; + color: hsl(var(--color-foreground)); + margin-bottom: 1.5rem; + } + + .empty-state-cta { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + padding: 1rem 1.5rem; + background: hsl(var(--color-surface-hover)); + border-radius: 0.75rem; + margin-bottom: 2rem; + } + + .empty-state-cta-text { + color: hsl(var(--color-muted-foreground)); + font-size: 0.9375rem; + } + + .empty-state-arrow { + color: hsl(var(--color-primary)); + animation: bounce 2s ease-in-out infinite; + } + + @keyframes bounce { + 0%, + 100% { + transform: translateY(0); + } + 50% { + transform: translateY(4px); + } + } + + .empty-state-examples { + display: flex; + flex-direction: column; + gap: 0.75rem; + } + + .examples-label { + font-size: 0.75rem; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.05em; + color: hsl(var(--color-muted-foreground)); + } + + .examples-grid { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.5rem; + } + + .example-chip { + padding: 0.5rem 0.875rem; + font-size: 0.875rem; + font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Monaco, Consolas, monospace; + background: hsl(var(--color-surface)); + border: 1px solid hsl(var(--color-border)); + border-radius: 9999px; + color: hsl(var(--color-foreground)); + cursor: pointer; + transition: all 0.15s ease; + } + + .example-chip:hover { + background: hsl(var(--color-primary) / 0.1); + border-color: hsl(var(--color-primary)); + color: hsl(var(--color-primary)); + transform: translateY(-1px); + } + + .example-chip:active { + transform: translateY(0); + } + + /* Onboarding tip */ + .onboarding-tip { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.875rem 1rem; + margin-top: 1rem; + background: hsl(var(--color-primary) / 0.08); + border: 1px solid hsl(var(--color-primary) / 0.2); + border-radius: 0.75rem; + font-size: 0.875rem; + } + + .onboarding-tip-icon { + flex-shrink: 0; + } + + .onboarding-tip-text { + color: hsl(var(--color-muted-foreground)); + } + + .onboarding-tip-text code { + padding: 0.125rem 0.375rem; + font-size: 0.8125rem; + font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Monaco, Consolas, monospace; + background: hsl(var(--color-primary) / 0.15); + border-radius: 0.25rem; + color: hsl(var(--color-primary)); + } diff --git a/packages/shared-ui/src/quick-input/InputBar.svelte b/packages/shared-ui/src/quick-input/InputBar.svelte index 707a9acad..941533a88 100644 --- a/packages/shared-ui/src/quick-input/InputBar.svelte +++ b/packages/shared-ui/src/quick-input/InputBar.svelte @@ -153,6 +153,26 @@ } }); + // Listen for external quick-input-set events (e.g., from empty state examples) + $effect(() => { + const handler = (e: Event) => { + const customEvent = e as CustomEvent<{ text: string }>; + if (customEvent.detail?.text) { + searchQuery = customEvent.detail.text; + // Trigger search for the new text + handleSearch(); + // Focus the input after a short delay + setTimeout(() => inputElement?.focus(), 50); + } + }; + + window.addEventListener('quick-input-set', handler); + + return () => { + window.removeEventListener('quick-input-set', handler); + }; + }); + // Handler for settings changes (to trigger re-render) function handleSettingsChange() { // Force reactivity update by accessing the store