diff --git a/apps/mana/apps/web/src/lib/components/dashboard/widget-registry.ts b/apps/mana/apps/web/src/lib/components/dashboard/widget-registry.ts index 13a0a5769..535212b38 100644 --- a/apps/mana/apps/web/src/lib/components/dashboard/widget-registry.ts +++ b/apps/mana/apps/web/src/lib/components/dashboard/widget-registry.ts @@ -32,6 +32,7 @@ import NutritionProgressWidget from '$lib/modules/core/widgets/NutritionProgress import PlantWateringWidget from '$lib/modules/core/widgets/PlantWateringWidget.svelte'; import PeriodWidget from '$lib/modules/core/widgets/PeriodWidget.svelte'; import NewsUnreadWidget from '$lib/modules/news/widgets/NewsUnreadWidget.svelte'; +import ArticlesUnreadWidget from '$lib/modules/articles/widgets/ArticlesUnreadWidget.svelte'; import BodyStatsWidget from '$lib/modules/body/widgets/BodyStatsWidget.svelte'; import InvoicesOpenWidget from '$lib/modules/invoices/widgets/InvoicesOpenWidget.svelte'; import BroadcastsWidget from '$lib/modules/broadcast/widgets/BroadcastsWidget.svelte'; @@ -63,6 +64,7 @@ export const widgetComponents: Record = { 'activity-feed': ActivityFeedWidget, period: PeriodWidget, 'news-unread': NewsUnreadWidget, + 'articles-unread': ArticlesUnreadWidget, 'body-stats': BodyStatsWidget, 'invoices-open': InvoicesOpenWidget, broadcasts: BroadcastsWidget, diff --git a/apps/mana/apps/web/src/lib/i18n/locales/dashboard/de.json b/apps/mana/apps/web/src/lib/i18n/locales/dashboard/de.json index 32f7ed796..d5395af40 100644 --- a/apps/mana/apps/web/src/lib/i18n/locales/dashboard/de.json +++ b/apps/mana/apps/web/src/lib/i18n/locales/dashboard/de.json @@ -155,6 +155,10 @@ "title": "News", "description": "Top-Artikel aus deinem kuratierten Feed" }, + "articles_unread": { + "title": "Artikel", + "description": "Ungelesene Artikel aus deiner Leseliste" + }, "body_stats": { "title": "Body", "description": "Aktuelles Gewicht und Trainings-Status" diff --git a/apps/mana/apps/web/src/lib/i18n/locales/dashboard/en.json b/apps/mana/apps/web/src/lib/i18n/locales/dashboard/en.json index 52882b565..e87b3eb0d 100644 --- a/apps/mana/apps/web/src/lib/i18n/locales/dashboard/en.json +++ b/apps/mana/apps/web/src/lib/i18n/locales/dashboard/en.json @@ -155,6 +155,10 @@ "title": "News", "description": "Top articles from your curated feed" }, + "articles_unread": { + "title": "Articles", + "description": "Unread articles from your reading list" + }, "body_stats": { "title": "Body", "description": "Latest weight and training status" diff --git a/apps/mana/apps/web/src/lib/modules/articles/ListView.svelte b/apps/mana/apps/web/src/lib/modules/articles/ListView.svelte index bd5cb4cc9..52841d29f 100644 --- a/apps/mana/apps/web/src/lib/modules/articles/ListView.svelte +++ b/apps/mana/apps/web/src/lib/modules/articles/ListView.svelte @@ -80,6 +80,15 @@

Später lesen — gespeicherte Web-Artikel, offline verfügbar.

+ +
+ {#if rows.length > 0} +
+ + +
+ {/if} + + + {#if rows$.loading} +

Lädt…

+ {:else if groups.length === 0} +
+

Noch keine Highlights.

+

+ Markier eine Textstelle in einem gespeicherten Artikel — sie erscheint hier automatisch. +

+ +
+ {:else} +
+ {#each groups as group (group.articleId)} +
+
+ +
+
    + {#each group.highlights as h (h.id)} +
  • + + {#if h.note} +

    {h.note}

    + {/if} +
  • + {/each} +
+
+ {/each} +
+ {/if} + + + diff --git a/apps/mana/apps/web/src/lib/modules/articles/widgets/ArticlesUnreadWidget.svelte b/apps/mana/apps/web/src/lib/modules/articles/widgets/ArticlesUnreadWidget.svelte new file mode 100644 index 000000000..9ca1459c6 --- /dev/null +++ b/apps/mana/apps/web/src/lib/modules/articles/widgets/ArticlesUnreadWidget.svelte @@ -0,0 +1,78 @@ + + +
+
+

+ + Artikel +

+ Alle → +
+ + {#if articles$.loading} +
+ {#each Array(3) as _} +
+ {/each} +
+ {:else if articles.length === 0} +
+

Noch keine Artikel gespeichert.

+ + Erste URL speichern + +
+ {:else if topUnread.length === 0} +
+

Alles gelesen — stark.

+ + Leseliste öffnen + +
+ {:else} + +
+ {stats.unread} ungelesen · {stats.savedThisWeek} diese Woche gespeichert +
+ {/if} +
diff --git a/apps/mana/apps/web/src/lib/types/dashboard.ts b/apps/mana/apps/web/src/lib/types/dashboard.ts index ea96ed334..6c23cb45e 100644 --- a/apps/mana/apps/web/src/lib/types/dashboard.ts +++ b/apps/mana/apps/web/src/lib/types/dashboard.ts @@ -32,6 +32,7 @@ export type WidgetType = | 'activity-feed' // TimeBlocks: recent activity across modules | 'period' // Period: current phase + days until next period | 'news-unread' // News: latest unread curated articles + | 'articles-unread' // Articles: saved read-it-later articles | 'body-stats' // Body: latest weight + active workout summary | 'invoices-open' // Invoices: open/overdue totals + oldest overdue | 'broadcasts'; // Broadcast: YTD counts + last sent + next scheduled @@ -355,6 +356,14 @@ export const WIDGET_REGISTRY: WidgetMeta[] = [ defaultSize: 'small', allowMultiple: false, }, + { + type: 'articles-unread', + nameKey: 'dashboard.widgets.articles_unread.title', + descriptionKey: 'dashboard.widgets.articles_unread.description', + icon: '📚', + defaultSize: 'small', + allowMultiple: false, + }, { type: 'body-stats', nameKey: 'dashboard.widgets.body_stats.title', diff --git a/apps/mana/apps/web/src/routes/(app)/articles/highlights/+page.svelte b/apps/mana/apps/web/src/routes/(app)/articles/highlights/+page.svelte new file mode 100644 index 000000000..cb03cd180 --- /dev/null +++ b/apps/mana/apps/web/src/routes/(app)/articles/highlights/+page.svelte @@ -0,0 +1,5 @@ + + + diff --git a/docs/plans/articles-module.md b/docs/plans/articles-module.md index 20a175636..37fc71b16 100644 --- a/docs/plans/articles-module.md +++ b/docs/plans/articles-module.md @@ -16,11 +16,13 @@ **Hinweis AiProposalInbox:** Der apps/mana/CLAUDE.md-Abschnitt erwähnt `` als Inline-Mount, aber die Komponente existiert im aktuellen Codebase nicht — nach dem `pendingProposals`-Table-Drop in Dexie v29 wurde die Proposal-Darstellung auf `server-iteration-staging` + den Cross-Module-Inbox im Mission-Detail-View umgestellt. Articles-Proposals tauchen dort automatisch auf. Falls die Inline-Komponente wieder reaktiviert wird, muss nur der Mount in `ListView.svelte` ergänzt werden. -**M7 Share-Target + Bookmarklet: DONE** (commit pending) — `@mana/shared-pwa` bekommt neue Types (`PWAShareTarget`, `PWAShareTargetParams`), `createPWAConfig` threadet `shareTarget` in den Manifest, `ManifestConfig.share_target?` ergänzt. Web-App: `vite.config.ts` setzt `shareTarget: { action: '/articles/add', method: 'GET', params: { title, text, url } }`; `AddUrlForm` liest Query-Params in `onMount` (inkl. URL-Regex-Fallback auf `text` weil Chrome Android / WhatsApp den Link dort reinstecken), triggert auto-Vorschau. Neue Route `/articles/settings` rendert Bookmarklet-Karte (Drag-to-Bookmark + Copy-Snippet + expandable Quellcode) und Share-Target-Erklärung. `ListView` bekommt Zahnrad-Button zum Settings-Aufruf. +**M7 Share-Target + Bookmarklet: DONE** (commit `8a991f7c3`) — `@mana/shared-pwa` bekommt neue Types (`PWAShareTarget`, `PWAShareTargetParams`), `createPWAConfig` threadet `shareTarget` in den Manifest, `ManifestConfig.share_target?` ergänzt. Web-App: `vite.config.ts` setzt `shareTarget: { action: '/articles/add', method: 'GET', params: { title, text, url } }`; `AddUrlForm` liest Query-Params in `onMount` (inkl. URL-Regex-Fallback auf `text` weil Chrome Android / WhatsApp den Link dort reinstecken), triggert auto-Vorschau. Neue Route `/articles/settings` rendert Bookmarklet-Karte (Drag-to-Bookmark + Copy-Snippet + expandable Quellcode) und Share-Target-Erklärung. `ListView` bekommt Zahnrad-Button zum Settings-Aufruf. Nicht im Scope (bewusst ausgelassen): die „optional" im Plan markierte `_pendingUrls`-Offline-Queue. Kann als M7b nachgereicht werden wenn das Problem auftaucht. -Nächster Schritt: M8 (HighlightsView + Stats + Dashboard-Widget). +**M8 HighlightsView + Stats + Dashboard-Widget: DONE** (commit pending) — `queries.ts` bekommt `useStats()` (total, pro-Status, savedThisWeek, finishedThisWeek, topSites, totalHighlights) und `useAllHighlights()` (chronologisch, joined mit Artikel-Header-Info). Neue Route `/articles/highlights` mountet `HighlightsView.svelte`: Highlights pro Artikel gruppiert, farbige Akzent-Striche, Click-to-Reader, Copy-Markdown + Download-.md via `lib/markdown-export.ts` (pure Funktion, unit-testbar). Dashboard-Widget `ArticlesUnreadWidget` zeigt Top-3 unread + Stats-Strip; registriert in `widget-registry.ts`, `dashboard.ts` `WidgetType`-Union + `WIDGET_REGISTRY`; i18n-Keys in de.json + en.json (fr/it/es konsistent mit anderen Widgets weggelassen). ListView bekommt ✎-Button zum Highlights-Aufruf neben dem Settings-Zahnrad. + +Damit ist der komplette M1–M8-Scope aus diesem Plan umgesetzt. Phase-3-Kandidaten (Highlight→Note-Export mit Backlink, Full-Text-Search, Mercury/archive.org-Fallback, Jahresrückblick) bleiben offen für spätere Iterationen. ## Ziel