Top Bar Breadcrumb Design

Date: 2026-05-04
Status: Approved for planning

1. Goal

Add a breadcrumb to the dashboard top bar that improves orientation in deep navigation paths.

Scope constraints:

  • Breadcrumb is shown next to the logo in the top bar.
  • Breadcrumb is desktop-only (show on lg and above, hidden on mobile/tablet).
  • Breadcrumb generation uses a hybrid strategy: auto from route path with centralized overrides.

Out of scope:

  • Refactoring the route architecture in App.tsx.
  • Mobile breadcrumb UX.
  • Pulling entity names from APIs for dynamic titles in this phase.

2. Current State

  • Top navigation is rendered in frontend/src/components/layouts/TopNav.tsx.
  • App route definitions are centralized in frontend/src/App.tsx.
  • Main page content renders under DashboardLayout via <Outlet />.

3. Proposed Architecture

3.1 Breadcrumb resolver module

Add a dedicated resolver module:

  • frontend/src/navigation/breadcrumb-resolver.ts

Responsibilities:

  • Accept pathname as input.
  • Build cumulative route segments.
  • Resolve each segment to a breadcrumb item using a centralized registry.
  • Return a render-ready list of breadcrumb items.

3.2 Centralized breadcrumb registry

Add a route metadata registry in navigation layer (same module or adjacent file), mapping path patterns to label definitions.

Examples:

  • /dashboard -> Dashboard
  • /farms/ponds -> Farms / Ponds
  • /farms/ponds/:id -> Chi tiết

Rule priority:

  1. Pattern override in registry.
  2. Fallback auto-label from URL token formatting.

3.3 TopNav integration

Update TopNav to:

  • Use useLocation() to read current pathname.
  • Run resolver and render Ant Design Breadcrumb beside logo.
  • Only render breadcrumb when screens.lg is true.

Non-final breadcrumb items are clickable and navigate to their corresponding paths.
Final breadcrumb item is display-only.

4. Resolver Behavior

  1. Normalize input path:
    • Ignore query string and hash.
    • Normalize trailing slash.
  2. Split into cumulative segments:
    • /farms/ponds/123 -> /farms, /farms/ponds, /farms/ponds/123
  3. For each cumulative segment:
    • Match against registry patterns (support static + :param).
    • Resolve label from override when found.
    • Fallback to formatted token label when not found.
  4. Build list shape:
    • title, path, clickable
  5. Mark last item as non-clickable.

5. UX Rules

  • Desktop-only visibility: hidden for non-desktop breakpoints.
  • Dashboard/root behavior: show one-item breadcrumb (Dashboard) for orientation.
  • Unknown paths: show readable fallback labels, never fail rendering.
  • Long breadcrumb labels: constrain with ellipsis to preserve top bar stability.

6. Error Handling Strategy

  • Resolver must be pure and defensive:
    • Return empty array for invalid or empty path.
    • Never throw during normal rendering.
  • If registry lookup fails, fallback labeling guarantees output continuity.
  • If no valid items are resolved, breadcrumb region remains hidden.

7. Testing Strategy

7.1 Unit tests (resolver)

Add tests covering:

  • Static paths (/dashboard, /devices/list)
  • Parameterized paths (/farms/ponds/:id equivalent concrete path)
  • Unknown path fallback formatting
  • Override priority over auto format
  • Trailing slash normalization
  • Query/hash ignored behavior

7.2 Component tests (TopNav)

Add tests covering:

  • Desktop breakpoint renders breadcrumb.
  • Non-desktop breakpoint hides breadcrumb.
  • Intermediate items are clickable.
  • Last item is non-clickable.

7.3 Manual verification

Validate on desktop for key paths:

  • /dashboard
  • /farms/ponds
  • /farms/ponds/:id (concrete id)
  • /system/device-profiles

Confirm no breadcrumb appears on mobile/tablet breakpoints.

8. Rollout Notes

  • Keep change localized to navigation/layout layer.
  • Avoid route-definition refactor in this phase.
  • Keep registry entries focused on current major routes; extend incrementally as needed.

9. Acceptance Criteria

  1. Breadcrumb appears next to top bar logo on desktop only.
  2. Breadcrumb is hidden on mobile/tablet.
  3. Breadcrumb trail is generated from current route path.
  4. Central registry overrides are applied where configured.
  5. Unknown routes still render readable fallback crumbs.
  6. Existing layout/navigation behavior remains unchanged outside breadcrumb addition.