feat(person): show document statistics bar #19

Closed
opened 2026-03-19 21:13:29 +01:00 by marcel · 0 comments
Owner

User Journey

Thomas opens the person page for his grandfather Karl. He wants a quick sense of how well-documented Karl's life is before scrolling through documents. Currently there is no summary — he has to mentally count the list and find the earliest/latest dates himself.

With this feature, Thomas sees a compact strip above the document list: "23 Dokumente · 1921–1967". In three seconds he knows the scope of Karl's archive.


High-Level Plan

Derive statistics from the documents already loaded in the page — no backend changes needed. Compute total count and date range (min/max documentDate) reactively and render a small strip between the page header and the document list.

Depends on issue #1 (sent + received documents) being implemented first, since the stats should cover both directions.


Detailed Plan

Frontend only

  1. Derived values in persons/[id]/+page.svelte:

    const allDocs = $derived([...data.sentDocuments, ...data.receivedDocuments]);
    
    const docStats = $derived(() => {
        const dated = allDocs.filter(d => d.documentDate);
        const years = dated.map(d => parseInt(d.documentDate!.substring(0, 4)));
        return {
            total: allDocs.length,
            minYear: years.length ? Math.min(...years) : null,
            maxYear: years.length ? Math.max(...years) : null,
        };
    });
    
  2. Statistics strip — render between the header card and the document sections, only when docStats.total > 0:

    ┌──────────────────────────────────────────────┐
    │  23 Dokumente   ·   1921 – 1967              │
    └──────────────────────────────────────────────┘
    

    Styled as a subtle bg-brand-sand/30 banner with font-sans text-sm text-brand-navy/70.

  3. If only one year exists (all documents have the same year, or only one document), show just 1921 instead of a range.

  4. If no document has a date, omit the year range entirely — show only "5 Dokumente".

Acceptance Criteria

  • Strip shows correct total document count (sent + received)
  • Year range reflects actual min/max documentDate
  • Strip is hidden when there are no documents
  • Single-year case shows one year, not a range
  • No backend changes, no additional API calls
## User Journey Thomas opens the person page for his grandfather Karl. He wants a quick sense of how well-documented Karl's life is before scrolling through documents. Currently there is no summary — he has to mentally count the list and find the earliest/latest dates himself. With this feature, Thomas sees a compact strip above the document list: **"23 Dokumente · 1921–1967"**. In three seconds he knows the scope of Karl's archive. --- ## High-Level Plan Derive statistics from the documents already loaded in the page — no backend changes needed. Compute total count and date range (min/max `documentDate`) reactively and render a small strip between the page header and the document list. Depends on issue #1 (sent + received documents) being implemented first, since the stats should cover both directions. --- ## Detailed Plan ### Frontend only 1. **Derived values** in `persons/[id]/+page.svelte`: ```typescript const allDocs = $derived([...data.sentDocuments, ...data.receivedDocuments]); const docStats = $derived(() => { const dated = allDocs.filter(d => d.documentDate); const years = dated.map(d => parseInt(d.documentDate!.substring(0, 4))); return { total: allDocs.length, minYear: years.length ? Math.min(...years) : null, maxYear: years.length ? Math.max(...years) : null, }; }); ``` 2. **Statistics strip** — render between the header card and the document sections, only when `docStats.total > 0`: ``` ┌──────────────────────────────────────────────┐ │ 23 Dokumente · 1921 – 1967 │ └──────────────────────────────────────────────┘ ``` Styled as a subtle `bg-brand-sand/30` banner with `font-sans text-sm text-brand-navy/70`. 3. If only one year exists (all documents have the same year, or only one document), show just `1921` instead of a range. 4. If no document has a date, omit the year range entirely — show only `"5 Dokumente"`. ### Acceptance Criteria - [ ] Strip shows correct total document count (sent + received) - [ ] Year range reflects actual min/max `documentDate` - [ ] Strip is hidden when there are no documents - [ ] Single-year case shows one year, not a range - [ ] No backend changes, no additional API calls
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#19