Skip to content

feat(ui): add AreaBreadcrumb shared component and SearchPicker secondary-line slot #1237

@steilerDev

Description

@steilerDev

Background

To display the full area tree as secondary info beneath work item and household item titles across many views, we need a reusable shared component. The component must support a default (full path) variant and a compact (left-truncated with middle ellipsis on root) variant for narrow contexts, with the full path always available via tooltip. Additionally, the existing SearchPicker must gain an optional secondary-line slot so pickers can render the breadcrumb under the primary label without duplicating layout logic.

Per the shared-component policy, UX designer produces a visual spec before implementation. Translator adds non-English strings for the new areas.noArea key.

Scope

  • client/src/components/AreaBreadcrumb/* (new directory) — component, CSS module, index export
  • client/src/components/SearchPicker/SearchPicker.tsx — add optional renderSecondary?: (item) => ReactNode prop
  • client/src/i18n/en/areas.json — add (or reuse namespace for) areas.noArea\"No area\"
  • client/src/i18n/glossary.json — add domain term if applicable (translator-owned)

Acceptance Criteria

Scenario 1: Happy path — full path rendering (default variant)

  • Given an AreaSummary with ancestors: [House, Basement] and name Bathroom
  • When <AreaBreadcrumb area={summary} /> is rendered (default variant)
  • Then the rendered text reads House › Basement › Bathroom using the separator (U+203A, single spaces)
  • And text uses --color-text-muted and .textSmall style tokens (no hardcoded colors)

Scenario 2: Null-area fallback

  • Given area is null
  • When <AreaBreadcrumb area={null} /> is rendered
  • Then the component renders the translated areas.noArea placeholder (\"No area\" in English)
  • And the component does not crash or render an empty separator

Scenario 3: Compact variant — truncation and tooltip

  • Given an AreaSummary with ancestors [Property, House, Floor 1, Kitchen Area] and name Pantry
  • When <AreaBreadcrumb area={summary} variant=\"compact\" /> is rendered in a narrow container
  • Then the visible text left-truncates with a middle ellipsis on the root segment, e.g., … › Kitchen Area › Pantry
  • And hovering/tapping the breadcrumb surfaces a tooltip containing the full path Property › House › Floor 1 › Kitchen Area › Pantry

Scenario 4: SearchPicker renderSecondary slot

  • Given a SearchPicker instance with renderSecondary={(item) => <AreaBreadcrumb area={item.area} variant=\"compact\" />}
  • When the picker renders an item list
  • Then each item shows the primary label on line 1 and the breadcrumb on line 2, muted and single-line with overflow ellipsis
  • And when renderSecondary is omitted, the picker renders as before (single-line label) with no regression

Dependencies

None. This item unblocks issues 3, 4, and 5.

Out of scope

  • Wiring the component into any page, list, or picker (covered by issues 3, 4, 5)
  • Backend changes to AreaSummary (covered by issue 1)
  • German translations (handled by translator agent in parallel, per i18n convention)
  • Changes to SearchPicker behaviors other than the new optional renderSecondary slot

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions