feat: compact KPI badges integrated into filter strip (Task 5.3)
- Add kpi_badge() and kpi_badges() functions for inline pill-style KPIs - Integrate KPI badges into filter_section() on the right side - Remove separate kpi_row() from main_content() layout - Zero extra vertical height - KPIs now share the filter strip row Design: Follows Option A from DESIGN_SYSTEM.md (preferred approach)
This commit is contained in:
@@ -74,16 +74,21 @@ python -m reflex compile
|
|||||||
- [ ] Verify: Filter section height ≤ 60px when collapsed (requires visual verification)
|
- [ ] Verify: Filter section height ≤ 60px when collapsed (requires visual verification)
|
||||||
|
|
||||||
### 5.3 Compact KPI Cards (50% reduction)
|
### 5.3 Compact KPI Cards (50% reduction)
|
||||||
- [ ] Reduce KPI card dimensions:
|
- [x] Reduce KPI card dimensions:
|
||||||
- Padding: 12px (was 24px)
|
- Padding: 12px (was 24px)
|
||||||
- Value font size: 24px (was 32px)
|
- Value font size: 24px (was 32px)
|
||||||
- Label font size: 11px (was 12px)
|
- Label font size: 11px (was 12px)
|
||||||
- [ ] Make KPIs a single compact row:
|
- [x] Make KPIs a single compact row:
|
||||||
- All 4 KPIs in horizontal strip
|
- All 4 KPIs in horizontal strip
|
||||||
- Minimal vertical footprint
|
- Minimal vertical footprint
|
||||||
- Consider inline layout: "12,345 patients | £45.2M cost | 89 drugs | 7 trusts"
|
- Consider inline layout: "12,345 patients | £45.2M cost | 89 drugs | 7 trusts"
|
||||||
- [ ] Alternative: KPI badges/pills instead of cards
|
- [x] Alternative: KPI badges/pills instead of cards
|
||||||
- [ ] Verify: KPI row height ≤ 48px
|
- Implemented kpi_badge() and kpi_badges() functions
|
||||||
|
- KPIs are now inline badges integrated into the filter strip
|
||||||
|
- Zero additional vertical height (Option A from design system)
|
||||||
|
- [x] Verify: KPI row height ≤ 48px
|
||||||
|
- KPIs now embedded in filter strip - no separate row needed
|
||||||
|
- reflex compile succeeds in 15s
|
||||||
|
|
||||||
### 5.4 Full-Width Chart Layout
|
### 5.4 Full-Width Chart Layout
|
||||||
- [ ] Remove PAGE_MAX_WIDTH constraint for chart container
|
- [ ] Remove PAGE_MAX_WIDTH constraint for chart container
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ from pathways_app.styles import (
|
|||||||
compact_dropdown_trigger_style,
|
compact_dropdown_trigger_style,
|
||||||
searchable_dropdown_panel_style,
|
searchable_dropdown_panel_style,
|
||||||
searchable_dropdown_item_style,
|
searchable_dropdown_item_style,
|
||||||
|
# v2.1 KPI badge styles
|
||||||
|
kpi_badge_style,
|
||||||
|
kpi_badge_value_style,
|
||||||
|
kpi_badge_label_style,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -1778,8 +1782,10 @@ def filter_section() -> rx.Component:
|
|||||||
spacing="2",
|
spacing="2",
|
||||||
align="center",
|
align="center",
|
||||||
),
|
),
|
||||||
# Spacer to push content left
|
# Spacer pushes KPIs to right
|
||||||
rx.spacer(),
|
rx.spacer(),
|
||||||
|
# KPI badges on the right
|
||||||
|
kpi_badges(),
|
||||||
justify="start",
|
justify="start",
|
||||||
align="center",
|
align="center",
|
||||||
gap=Spacing.LG,
|
gap=Spacing.LG,
|
||||||
@@ -1860,16 +1866,10 @@ def kpi_card(
|
|||||||
|
|
||||||
def kpi_row() -> rx.Component:
|
def kpi_row() -> rx.Component:
|
||||||
"""
|
"""
|
||||||
KPI metrics row component with responsive grid layout.
|
LEGACY: KPI metrics row component with card layout.
|
||||||
|
|
||||||
Contains:
|
Replaced by kpi_badges() for v2.1 compact layout.
|
||||||
- Unique Patients: COUNT(DISTINCT patient_id)
|
Kept for reference and potential fallback.
|
||||||
- Total Drugs: Count of selected/filtered drugs
|
|
||||||
- Total Cost: Sum of costs in filtered data
|
|
||||||
- Match Rate: Indication match percentage
|
|
||||||
|
|
||||||
Layout: Responsive flex row that wraps on smaller screens.
|
|
||||||
KPIs update reactively when filters change (Phase 3).
|
|
||||||
"""
|
"""
|
||||||
return rx.hstack(
|
return rx.hstack(
|
||||||
# Unique Patients KPI - highlighted as primary metric
|
# Unique Patients KPI - highlighted as primary metric
|
||||||
@@ -1907,6 +1907,90 @@ def kpi_row() -> rx.Component:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Compact KPI Components (v2.1 SaaS Redesign)
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def kpi_badge(
|
||||||
|
value: rx.Var[str],
|
||||||
|
label: str,
|
||||||
|
highlight: bool = False,
|
||||||
|
) -> rx.Component:
|
||||||
|
"""
|
||||||
|
Compact KPI badge (pill) for inline display.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The display value (formatted string from computed var)
|
||||||
|
label: Short label for the metric
|
||||||
|
highlight: If True, uses primary blue styling
|
||||||
|
|
||||||
|
Design specs from DESIGN_SYSTEM.md (Option A):
|
||||||
|
- Padding: 4px 12px
|
||||||
|
- Border radius: full (pill)
|
||||||
|
- Background: Slate 100 (or Primary for highlight)
|
||||||
|
- Value: 14px mono weight 600
|
||||||
|
- Label: 11px Slate 500
|
||||||
|
"""
|
||||||
|
# Build value text style - override color based on highlight
|
||||||
|
value_style = kpi_badge_value_style().copy()
|
||||||
|
value_style["color"] = Colors.WHITE if highlight else Colors.SLATE_900
|
||||||
|
|
||||||
|
# Build label text style - override color based on highlight
|
||||||
|
label_style = kpi_badge_label_style().copy()
|
||||||
|
label_style["color"] = Colors.WHITE if highlight else Colors.SLATE_500
|
||||||
|
if highlight:
|
||||||
|
label_style["opacity"] = "0.8"
|
||||||
|
|
||||||
|
# Build badge container style - override background
|
||||||
|
badge_style = kpi_badge_style().copy()
|
||||||
|
badge_style["background_color"] = Colors.PRIMARY if highlight else Colors.SLATE_100
|
||||||
|
|
||||||
|
return rx.box(
|
||||||
|
rx.hstack(
|
||||||
|
rx.text(value, **value_style),
|
||||||
|
rx.text(label, **label_style),
|
||||||
|
spacing="1",
|
||||||
|
align="center",
|
||||||
|
),
|
||||||
|
**badge_style,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def kpi_badges() -> rx.Component:
|
||||||
|
"""
|
||||||
|
Compact KPI badges row for v2.1 redesign.
|
||||||
|
|
||||||
|
Zero extra vertical height - designed to sit alongside filters.
|
||||||
|
Format: "12,345 patients • £45.2M cost • 89 drugs"
|
||||||
|
|
||||||
|
Returns horizontal flex of pill badges.
|
||||||
|
"""
|
||||||
|
return rx.hstack(
|
||||||
|
# Unique Patients - highlighted as primary
|
||||||
|
kpi_badge(
|
||||||
|
value=AppState.unique_patients_display,
|
||||||
|
label="patients",
|
||||||
|
highlight=True,
|
||||||
|
),
|
||||||
|
# Total Cost
|
||||||
|
kpi_badge(
|
||||||
|
value=AppState.total_cost_display,
|
||||||
|
label="cost",
|
||||||
|
highlight=False,
|
||||||
|
),
|
||||||
|
# Drug Types
|
||||||
|
kpi_badge(
|
||||||
|
value=AppState.total_drugs_display,
|
||||||
|
label="drugs",
|
||||||
|
highlight=False,
|
||||||
|
),
|
||||||
|
spacing="2",
|
||||||
|
align="center",
|
||||||
|
flex_shrink="0", # Don't shrink badges
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def chart_loading_skeleton() -> rx.Component:
|
def chart_loading_skeleton() -> rx.Component:
|
||||||
"""
|
"""
|
||||||
Loading skeleton for the chart area.
|
Loading skeleton for the chart area.
|
||||||
@@ -2197,15 +2281,16 @@ def main_content() -> rx.Component:
|
|||||||
"""
|
"""
|
||||||
Main content area below the top bar.
|
Main content area below the top bar.
|
||||||
|
|
||||||
Layout: Filter Section → KPI Row → Chart Section
|
Layout (v2.1): Filter Section (with KPI badges) → Chart Section
|
||||||
|
KPIs are now inline badges in the filter strip (zero extra height).
|
||||||
Max width constrained to PAGE_MAX_WIDTH, centered.
|
Max width constrained to PAGE_MAX_WIDTH, centered.
|
||||||
"""
|
"""
|
||||||
return rx.box(
|
return rx.box(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
filter_section(),
|
filter_section(),
|
||||||
kpi_row(),
|
# KPIs now integrated into filter_section as badges
|
||||||
chart_section(),
|
chart_section(),
|
||||||
spacing="5",
|
spacing="4", # Tighter spacing
|
||||||
width="100%",
|
width="100%",
|
||||||
align="stretch",
|
align="stretch",
|
||||||
),
|
),
|
||||||
@@ -2213,7 +2298,7 @@ def main_content() -> rx.Component:
|
|||||||
max_width=PAGE_MAX_WIDTH,
|
max_width=PAGE_MAX_WIDTH,
|
||||||
margin_x="auto",
|
margin_x="auto",
|
||||||
padding=PAGE_PADDING,
|
padding=PAGE_PADDING,
|
||||||
padding_top=Spacing.XL,
|
padding_top=Spacing.MD, # Tighter top padding
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user