feat(ux): kontextuelle Onboarding-Tipps in Empty-States aller Module
This commit is contained in:
@@ -892,6 +892,17 @@
|
|||||||
"offline": {
|
"offline": {
|
||||||
"banner": "Offline – Verbindung wird wiederhergestellt…"
|
"banner": "Offline – Verbindung wird wiederhergestellt…"
|
||||||
},
|
},
|
||||||
|
"emptyHint": {
|
||||||
|
"tasks": "Tippe auf + um deine erste Aufgabe zu erstellen. Wische eine Karte nach links zum Löschen.",
|
||||||
|
"calendar": "Verbinde Google Kalender unter Einstellungen → Integrationen für automatische Synchronisation.",
|
||||||
|
"shopping": "Füge Artikel hinzu und wische zum Abhaken oder Löschen.",
|
||||||
|
"notes": "Tippe auf + für eine neue Notiz. Notizen werden im Volltext durchsucht.",
|
||||||
|
"contacts": "Lege wichtige Kontakte an — Arzt, Schule, Notfall — für Schnellzugriff.",
|
||||||
|
"budget": "Erstelle Kategorien und trage Einnahmen und Ausgaben ein.",
|
||||||
|
"meals": "Plane Mahlzeiten für die Woche und verknüpfe Rezepte.",
|
||||||
|
"birthdays": "Trage Geburtstage ein — du erhältst eine Erinnerung rechtzeitig.",
|
||||||
|
"recipes": "Lege Rezepte an und verknüpfe sie mit deiner Mahlzeitenplanung."
|
||||||
|
},
|
||||||
"shortcuts": {
|
"shortcuts": {
|
||||||
"search": "Suche öffnen",
|
"search": "Suche öffnen",
|
||||||
"new": "Neuen Eintrag erstellen",
|
"new": "Neuen Eintrag erstellen",
|
||||||
|
|||||||
@@ -882,5 +882,16 @@
|
|||||||
"goCal": "Calendar",
|
"goCal": "Calendar",
|
||||||
"goShop": "Shopping list",
|
"goShop": "Shopping list",
|
||||||
"goNotes": "Notes"
|
"goNotes": "Notes"
|
||||||
|
},
|
||||||
|
"emptyHint": {
|
||||||
|
"tasks": "Tap + to create your first task. Swipe a card left to delete.",
|
||||||
|
"calendar": "Connect Google Calendar under Settings → Integrations for automatic sync.",
|
||||||
|
"shopping": "Add items and swipe to check off or delete.",
|
||||||
|
"notes": "Tap + for a new note. Notes are full-text searchable.",
|
||||||
|
"contacts": "Add important contacts — doctor, school, emergency — for quick access.",
|
||||||
|
"budget": "Create categories and track income and expenses.",
|
||||||
|
"meals": "Plan meals for the week and link recipes.",
|
||||||
|
"birthdays": "Add birthdays — you will receive a reminder in time.",
|
||||||
|
"recipes": "Create recipes and link them to your meal planner."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,6 +121,7 @@ function renderList() {
|
|||||||
host.insertAdjacentHTML('beforeend', `<div class="empty-state">
|
host.insertAdjacentHTML('beforeend', `<div class="empty-state">
|
||||||
<div class="empty-state__title">${t('birthdays.emptyTitle')}</div>
|
<div class="empty-state__title">${t('birthdays.emptyTitle')}</div>
|
||||||
<div class="empty-state__description">${t('birthdays.emptyDescription')}</div>
|
<div class="empty-state__description">${t('birthdays.emptyDescription')}</div>
|
||||||
|
<p class="empty-state__hint">${t('emptyHint.birthdays')}</p>
|
||||||
</div>`);
|
</div>`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -377,6 +377,7 @@ function renderEntries() {
|
|||||||
</svg>
|
</svg>
|
||||||
<div class="empty-state__title">${t('budget.emptyTitle')}</div>
|
<div class="empty-state__title">${t('budget.emptyTitle')}</div>
|
||||||
<div class="empty-state__description">${t('budget.emptyDescription')}</div>
|
<div class="empty-state__description">${t('budget.emptyDescription')}</div>
|
||||||
|
<p class="empty-state__hint">${t('emptyHint.budget')}</p>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ function renderList() {
|
|||||||
</svg>
|
</svg>
|
||||||
<div class="empty-state__title">${t('contacts.emptyTitle')}</div>
|
<div class="empty-state__title">${t('contacts.emptyTitle')}</div>
|
||||||
<div class="empty-state__description">${t('contacts.emptyDescription')}</div>
|
<div class="empty-state__description">${t('contacts.emptyDescription')}</div>
|
||||||
|
<p class="empty-state__hint">${t('emptyHint.contacts')}</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
if (window.lucide) lucide.createIcons();
|
if (window.lucide) lucide.createIcons();
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ function renderGrid() {
|
|||||||
</svg>
|
</svg>
|
||||||
<div class="empty-state__title">${isFiltered ? t('notes.noResultsTitle') : t('notes.emptyTitle')}</div>
|
<div class="empty-state__title">${isFiltered ? t('notes.noResultsTitle') : t('notes.emptyTitle')}</div>
|
||||||
<div class="empty-state__description">${isFiltered ? t('notes.noResultsDescription', { query: state.filterQuery }) : t('notes.emptyDescription')}</div>
|
<div class="empty-state__description">${isFiltered ? t('notes.noResultsDescription', { query: state.filterQuery }) : t('notes.emptyDescription')}</div>
|
||||||
|
${!isFiltered ? `<p class="empty-state__hint">${t('emptyHint.notes')}</p>` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
if (window.lucide) lucide.createIcons();
|
if (window.lucide) lucide.createIcons();
|
||||||
|
|||||||
@@ -126,7 +126,10 @@ function renderRecipeList() {
|
|||||||
emptyDesc.className = 'empty-state__description';
|
emptyDesc.className = 'empty-state__description';
|
||||||
emptyDesc.textContent = t('recipes.emptyDescription');
|
emptyDesc.textContent = t('recipes.emptyDescription');
|
||||||
|
|
||||||
empty.append(emptyTitle, emptyDesc);
|
const emptyHint = document.createElement('p');
|
||||||
|
emptyHint.className = 'empty-state__hint';
|
||||||
|
emptyHint.textContent = t('emptyHint.recipes');
|
||||||
|
empty.append(emptyTitle, emptyDesc, emptyHint);
|
||||||
list.appendChild(empty);
|
list.appendChild(empty);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ function renderItems() {
|
|||||||
</svg>
|
</svg>
|
||||||
<div class="empty-state__title">${t('shopping.emptyList')}</div>
|
<div class="empty-state__title">${t('shopping.emptyList')}</div>
|
||||||
<div class="empty-state__description">${t('shopping.emptyListDescription')}</div>
|
<div class="empty-state__description">${t('shopping.emptyListDescription')}</div>
|
||||||
|
<p class="empty-state__hint">${t('emptyHint.shopping')}</p>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -261,6 +261,7 @@ function renderTaskGroups(tasks, groupMode) {
|
|||||||
</svg>
|
</svg>
|
||||||
<div class="empty-state__title">${t('tasks.emptyTitle')}</div>
|
<div class="empty-state__title">${t('tasks.emptyTitle')}</div>
|
||||||
<div class="empty-state__description">${t('tasks.emptyDescription')}</div>
|
<div class="empty-state__description">${t('tasks.emptyDescription')}</div>
|
||||||
|
<p class="empty-state__hint">${t('emptyHint.tasks')}</p>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1370,6 +1370,18 @@
|
|||||||
line-height: var(--line-height-base);
|
line-height: var(--line-height-base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.empty-state__hint {
|
||||||
|
font-size: var(--text-xs);
|
||||||
|
color: var(--color-text-tertiary);
|
||||||
|
max-width: 280px;
|
||||||
|
line-height: var(--line-height-relaxed);
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
background-color: var(--color-surface-2);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
border: 1px solid var(--color-border-subtle);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.empty-state--compact {
|
.empty-state--compact {
|
||||||
padding: var(--space-4) var(--space-3);
|
padding: var(--space-4) var(--space-3);
|
||||||
gap: var(--space-2);
|
gap: var(--space-2);
|
||||||
|
|||||||
Reference in New Issue
Block a user