-
+
{$_('dashboard.widgets.activity_feed.empty', { default: 'Noch keine Aktivität' })}
diff --git a/apps/mana/apps/web/src/lib/components/dashboard/widgets/ClockTimersWidget.svelte b/apps/mana/apps/web/src/lib/components/dashboard/widgets/ClockTimersWidget.svelte
index 3f0302025..4fa75b6f7 100644
--- a/apps/mana/apps/web/src/lib/components/dashboard/widgets/ClockTimersWidget.svelte
+++ b/apps/mana/apps/web/src/lib/components/dashboard/widgets/ClockTimersWidget.svelte
@@ -11,14 +11,15 @@
const DAY_NAMES = ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'];
- function formatRepeatDays(days?: number[]): string {
+ function formatRepeatDays(days?: number[] | null): string {
if (!days || days.length === 0) return 'Einmalig';
if (days.length === 7) return 'Täglich';
if (days.length === 5 && !days.includes(0) && !days.includes(6)) return 'Werktags';
return days.map((d) => DAY_NAMES[d]).join(', ');
}
- function formatRemaining(seconds: number): string {
+ function formatRemaining(seconds: number | null | undefined): string {
+ if (seconds == null) return '—';
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
const s = seconds % 60;
diff --git a/apps/mana/apps/web/src/lib/components/dashboard/widgets/ContextDocsWidget.svelte b/apps/mana/apps/web/src/lib/components/dashboard/widgets/ContextDocsWidget.svelte
index d1154b7eb..479bc0bc7 100644
--- a/apps/mana/apps/web/src/lib/components/dashboard/widgets/ContextDocsWidget.svelte
+++ b/apps/mana/apps/web/src/lib/components/dashboard/widgets/ContextDocsWidget.svelte
@@ -9,7 +9,8 @@
const docs = useRecentDocuments(5);
const spaces = useSpaces();
- function getSpaceName(spaceId: string): string {
+ function getSpaceName(spaceId: string | null | undefined): string {
+ if (!spaceId) return '';
const space = (spaces.value ?? []).find((s) => s.id === spaceId);
return space?.name ?? '';
}
diff --git a/apps/mana/apps/web/src/lib/components/onboarding/OnboardingWizard.svelte b/apps/mana/apps/web/src/lib/components/onboarding/OnboardingWizard.svelte
index 071e7d92b..db36577c1 100644
--- a/apps/mana/apps/web/src/lib/components/onboarding/OnboardingWizard.svelte
+++ b/apps/mana/apps/web/src/lib/components/onboarding/OnboardingWizard.svelte
@@ -12,9 +12,16 @@
interface Props {
onComplete: () => void;
+ /**
+ * Optional callback fired when the user explicitly skips the wizard
+ * (vs. completing it normally). Layout consumers use it to track
+ * skip-rate analytics; the default skip path still calls onComplete
+ * so the modal closes either way.
+ */
+ onSkip?: () => void;
}
- let { onComplete }: Props = $props();
+ let { onComplete, onSkip }: Props = $props();
// Reference to profile name for auto-save on step transition
let profileNameRef = $state('');
@@ -60,6 +67,7 @@
function handleSkip() {
onboardingStore.skip();
+ onSkip?.();
onComplete();
}
diff --git a/apps/mana/apps/web/src/lib/content/help/index.test.ts b/apps/mana/apps/web/src/lib/content/help/index.test.ts
index aa39cd863..a6692ec6f 100644
--- a/apps/mana/apps/web/src/lib/content/help/index.test.ts
+++ b/apps/mana/apps/web/src/lib/content/help/index.test.ts
@@ -30,7 +30,7 @@ describe('Mana Help Content', () => {
expect(content.features).toBeDefined();
expect(content.contact).toBeDefined();
- expect(content.contact.supportEmail).toBe('support@mana.how');
+ expect(content.contact!.supportEmail).toBe('support@mana.how');
});
it('returns valid English content', () => {
diff --git a/apps/mana/apps/web/src/lib/modules/calendar/components/EventForm.svelte b/apps/mana/apps/web/src/lib/modules/calendar/components/EventForm.svelte
index 4a80f7ffa..590cc79e4 100644
--- a/apps/mana/apps/web/src/lib/modules/calendar/components/EventForm.svelte
+++ b/apps/mana/apps/web/src/lib/modules/calendar/components/EventForm.svelte
@@ -30,7 +30,7 @@
let calendarId = $state(event?.calendarId || '');
let recurrenceRule = $state(event?.recurrenceRule || '');
let selectedTagIds = $state
(
- ((event as Record)?.tagIds as string[]) ?? []
+ ((event as unknown as Record)?.tagIds as string[]) ?? []
);
const allTags = useAllTags();
diff --git a/apps/mana/apps/web/src/lib/modules/context/index.ts b/apps/mana/apps/web/src/lib/modules/context/index.ts
index e3774a443..2df026bee 100644
--- a/apps/mana/apps/web/src/lib/modules/context/index.ts
+++ b/apps/mana/apps/web/src/lib/modules/context/index.ts
@@ -2,7 +2,7 @@
* Context module — barrel exports.
*/
-export { contextSpaceTable, contextDocumentTable, CONTEXT_GUEST_SEED } from './collections';
+export { contextSpaceTable, documentTable, CONTEXT_GUEST_SEED } from './collections';
export * from './queries';
export type {
LocalContextSpace,
diff --git a/apps/mana/apps/web/src/lib/modules/memoro/queries.ts b/apps/mana/apps/web/src/lib/modules/memoro/queries.ts
index cc1baeb93..f10a84d07 100644
--- a/apps/mana/apps/web/src/lib/modules/memoro/queries.ts
+++ b/apps/mana/apps/web/src/lib/modules/memoro/queries.ts
@@ -5,6 +5,12 @@
import { useLiveQueryWithDefault } from '@mana/local-store/svelte';
import { db } from '$lib/data/database';
import { decryptRecords } from '$lib/data/crypto';
+// `useAllTags` re-exports the shared-tags hook below; the actual tag
+// objects flowing through this module are the shared shape, not the
+// memoro/types.Tag declared next to LocalMemoTag. Importing the shared
+// type here keeps `getTagsForMemo` and friends in sync with what the
+// hook actually returns.
+import type { Tag } from '@mana/shared-tags';
import type {
LocalMemo,
LocalMemory,
diff --git a/apps/mana/apps/web/src/lib/modules/memoro/views/DetailView.svelte b/apps/mana/apps/web/src/lib/modules/memoro/views/DetailView.svelte
index 6ece01255..7ace49162 100644
--- a/apps/mana/apps/web/src/lib/modules/memoro/views/DetailView.svelte
+++ b/apps/mana/apps/web/src/lib/modules/memoro/views/DetailView.svelte
@@ -8,6 +8,7 @@
import DetailViewShell from '$lib/components/DetailViewShell.svelte';
import { memosStore } from '../stores/memos.svelte';
import { llmQueueDb } from '$lib/llm-queue';
+ import type { QueuedTask } from '@mana/shared-llm';
import type { LlmTier } from '@mana/shared-llm';
import { PushPin } from '@mana/shared-icons';
import type { ViewProps } from '$lib/app-registry';
@@ -97,19 +98,16 @@
// Reactive lookup of any LLM queue task tagged with this memo, so the
// UI can show "Titel wird generiert..." while a generateTitleTask is
// pending or running. Returns the most recent task row (any state).
- const titleQueueRow = useLiveQueryWithDefault(
- async () => {
- if (!memoId) return null;
- const rows = await llmQueueDb.tasks
- .where('[refType+refId]')
- .equals(['memo', memoId])
- .and((t) => t.taskName === 'common.generateTitle')
- .reverse()
- .sortBy('enqueuedAt');
- return rows[0] ?? null;
- },
- null as Awaited>[number] | null
- );
+ const titleQueueRow = useLiveQueryWithDefault(async () => {
+ if (!memoId) return null;
+ const rows = await llmQueueDb.tasks
+ .where('[refType+refId]')
+ .equals(['memo', memoId])
+ .and((t) => t.taskName === 'common.generateTitle')
+ .reverse()
+ .sortBy('enqueuedAt');
+ return rows[0] ?? null;
+ }, null);
const titleIsGenerating = $derived(
titleQueueRow.value?.state === 'pending' || titleQueueRow.value?.state === 'running'
diff --git a/apps/mana/apps/web/src/lib/modules/picture/stores/images.svelte.ts b/apps/mana/apps/web/src/lib/modules/picture/stores/images.svelte.ts
index 409b9cacf..59fb2c84d 100644
--- a/apps/mana/apps/web/src/lib/modules/picture/stores/images.svelte.ts
+++ b/apps/mana/apps/web/src/lib/modules/picture/stores/images.svelte.ts
@@ -43,7 +43,14 @@ export const imagesStore = {
async toggleFavorite(id: string) {
error = null;
try {
- await toggleField(imageTable(), id, 'isFavorite');
+ // Cast: toggleField expects a string-keyed Table, but db.table()
+ // returns the generic IndexableType-keyed shape. The runtime keys
+ // for `images` are all strings (UUIDs).
+ await toggleField(
+ imageTable() as unknown as Parameters[0],
+ id,
+ 'isFavorite'
+ );
PictureEvents.imageFavorited();
return { success: true };
} catch (e) {
diff --git a/apps/mana/apps/web/src/lib/modules/presi/views/DetailView.svelte b/apps/mana/apps/web/src/lib/modules/presi/views/DetailView.svelte
index 65ae67eb3..137094136 100644
--- a/apps/mana/apps/web/src/lib/modules/presi/views/DetailView.svelte
+++ b/apps/mana/apps/web/src/lib/modules/presi/views/DetailView.svelte
@@ -69,7 +69,11 @@
onConfirmDelete={() =>
detail.deleteWithUndo({
label: 'Präsentation gelöscht',
- delete: () => decksStore.deleteDeck(deckId),
+ // deleteDeck returns Promise; the deleteWithUndo helper
+ // expects Promise, so we discard the result.
+ delete: async () => {
+ await decksStore.deleteDeck(deckId);
+ },
goBack,
})}
>
diff --git a/apps/mana/apps/web/src/lib/modules/questions/index.ts b/apps/mana/apps/web/src/lib/modules/questions/index.ts
index 69fddd446..d88aea9f8 100644
--- a/apps/mana/apps/web/src/lib/modules/questions/index.ts
+++ b/apps/mana/apps/web/src/lib/modules/questions/index.ts
@@ -2,12 +2,7 @@
* Questions module — barrel exports.
*/
-export {
- questionCollectionTable,
- questionTable,
- answerTable,
- QUESTIONS_GUEST_SEED,
-} from './collections';
+export { qCollectionTable, questionTable, answerTable, QUESTIONS_GUEST_SEED } from './collections';
export * from './queries';
export type {
LocalCollection,
diff --git a/apps/mana/apps/web/src/lib/modules/times/components/EntryItem.svelte b/apps/mana/apps/web/src/lib/modules/times/components/EntryItem.svelte
index 9f7223b43..ef195740c 100644
--- a/apps/mana/apps/web/src/lib/modules/times/components/EntryItem.svelte
+++ b/apps/mana/apps/web/src/lib/modules/times/components/EntryItem.svelte
@@ -4,7 +4,7 @@
import { timeEntryTable } from '$lib/modules/times/collections';
import { formatDurationCompact } from '$lib/modules/times/queries';
import { CurrencyDollar } from '@mana/shared-icons';
- import type { TimeEntry, Project, Client } from '$lib/modules/times/types';
+ import type { TimeEntry, Project, Client, LocalTimeEntry } from '$lib/modules/times/types';
import { ConfirmationModal } from '@mana/shared-ui';
let {
@@ -46,7 +46,7 @@
let saveDebounce: ReturnType | null = null;
- function autoSave(updates: Record) {
+ function autoSave(updates: Partial) {
if (saveDebounce) clearTimeout(saveDebounce);
saveDebounce = setTimeout(async () => {
await timeEntryTable.update(entry.id, updates);
diff --git a/apps/mana/apps/web/src/lib/modules/todo/components/QuickAddTask.svelte b/apps/mana/apps/web/src/lib/modules/todo/components/QuickAddTask.svelte
index b0a5fc626..de4594fd9 100644
--- a/apps/mana/apps/web/src/lib/modules/todo/components/QuickAddTask.svelte
+++ b/apps/mana/apps/web/src/lib/modules/todo/components/QuickAddTask.svelte
@@ -10,11 +10,12 @@
import type { ParsedTask } from '../utils/task-parser';
import type { TaskTag } from '../types';
import { getPriorityColor } from '../queries';
+ import type { ParserLocale } from '@mana/shared-utils';
import { Plus, CalendarBlank, Flag, ArrowsClockwise, Timer, Tag, Info } from '@mana/shared-icons';
interface Props {
labels?: TaskTag[];
- locale?: string;
+ locale?: ParserLocale;
onShowSyntaxHelp?: () => void;
}
diff --git a/apps/mana/apps/web/src/lib/modules/todo/components/pages/TodoPage.svelte b/apps/mana/apps/web/src/lib/modules/todo/components/pages/TodoPage.svelte
index 4ab4dfeba..4a757a4bf 100644
--- a/apps/mana/apps/web/src/lib/modules/todo/components/pages/TodoPage.svelte
+++ b/apps/mana/apps/web/src/lib/modules/todo/components/pages/TodoPage.svelte
@@ -285,7 +285,9 @@
onOpenTask(task) : undefined}
+ onToggleComplete={() => tasksStore.toggleComplete(task.id)}
+ onClick={() => onOpenTask?.(task)}
+ onContextMenu={() => {}}
/>
{/each}
diff --git a/apps/mana/apps/web/src/lib/modules/zitare/components/QuoteCard.svelte b/apps/mana/apps/web/src/lib/modules/zitare/components/QuoteCard.svelte
index 4c1bbc2c1..2cbdffff0 100644
--- a/apps/mana/apps/web/src/lib/modules/zitare/components/QuoteCard.svelte
+++ b/apps/mana/apps/web/src/lib/modules/zitare/components/QuoteCard.svelte
@@ -25,8 +25,11 @@
let quoteText = $derived(quotesStore.getText(quote));
let showBio = $state(false);
- // Get author bio in current language
- let authorBioText = $derived(() => {
+ // Get author bio in current language. `$derived.by` is the variant
+ // that takes a thunk; plain `$derived(expr)` would have stored the
+ // arrow function itself, making `authorBioText` always truthy and
+ // the {#if} below dead.
+ let authorBioText = $derived.by(() => {
if (!quote.authorBio) return '';
const lang = quotesStore.language === 'original' ? 'de' : quotesStore.language;
return quote.authorBio[lang] || quote.authorBio.de || '';
diff --git a/apps/mana/apps/web/src/routes/(app)/+layout.svelte b/apps/mana/apps/web/src/routes/(app)/+layout.svelte
index bfc1518b5..e42fd6837 100644
--- a/apps/mana/apps/web/src/routes/(app)/+layout.svelte
+++ b/apps/mana/apps/web/src/routes/(app)/+layout.svelte
@@ -293,7 +293,7 @@
// ── Sync ────────────────────────────────────────────────
const SYNC_SERVER_URL =
(typeof window !== 'undefined' &&
- (window as Record