feat: full-width responsive chart layout (Task 5.4)
- Remove PAGE_MAX_WIDTH constraint from main_content() - Update chart_display() with calc(100vh - 152px) height - Update icicle_figure with autosize=True and reduced margins - Update chart_section() with flex layout for height fill - Update page_layout() with 100vh height
This commit is contained in:
+12
-10
@@ -91,16 +91,18 @@ python -m reflex compile
|
|||||||
- reflex compile succeeds in 15s
|
- 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
|
- [x] Remove PAGE_MAX_WIDTH constraint for chart container
|
||||||
- [ ] Chart should stretch to viewport width (with small padding: 16px each side)
|
- Removed from main_content() - now uses 100% width with 16px padding
|
||||||
- [ ] Update chart height calculation:
|
- [x] Chart should stretch to viewport width (with small padding: 16px each side)
|
||||||
- Use CSS calc() or flex-grow to fill remaining viewport height
|
- Using padding_x=Spacing.XL (16px) in main_content()
|
||||||
- Minimum height: 500px
|
- [x] Update chart height calculation:
|
||||||
- Target: viewport height minus (top bar + filters + KPIs + padding)
|
- Using calc(100vh - 152px) for chart height
|
||||||
- [ ] Update Plotly layout:
|
- 152px = 48px top bar + 48px filter strip + 16px padding + 40px chart header
|
||||||
- Remove fixed height=600, use responsive sizing
|
- Minimum height: 500px preserved
|
||||||
- Reduce margins further for maximum chart area
|
- [x] Update Plotly layout:
|
||||||
- [ ] Verify: Chart fills available space on 1920x1080 display
|
- Removed fixed height=600, using autosize=True
|
||||||
|
- Reduced margins to t:40, l:8, r:8, b:24 per DESIGN_SYSTEM.md
|
||||||
|
- [ ] Verify: Chart fills available space on 1920x1080 display (requires visual check)
|
||||||
|
|
||||||
### 5.5 Top Bar Refinement
|
### 5.5 Top Bar Refinement
|
||||||
- [ ] Reduce top bar height to 48px (was 64px)
|
- [ ] Reduce top bar height to 48px (was 64px)
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ from pathways_app.styles import (
|
|||||||
kpi_badge_style,
|
kpi_badge_style,
|
||||||
kpi_badge_value_style,
|
kpi_badge_value_style,
|
||||||
kpi_badge_label_style,
|
kpi_badge_label_style,
|
||||||
|
# v2.1 chart styles (full-width layout)
|
||||||
|
chart_container_style,
|
||||||
|
chart_wrapper_style,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -1341,6 +1344,8 @@ class AppState(rx.State):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Configure layout
|
# Configure layout
|
||||||
|
# v2.1: Remove fixed height for responsive sizing
|
||||||
|
# Margins reduced per DESIGN_SYSTEM.md (t:40, l:8, r:8, b:24)
|
||||||
fig.update_layout(
|
fig.update_layout(
|
||||||
title=dict(
|
title=dict(
|
||||||
text=f"Patient Pathways — {self.chart_title}",
|
text=f"Patient Pathways — {self.chart_title}",
|
||||||
@@ -1352,7 +1357,7 @@ class AppState(rx.State):
|
|||||||
x=0.5,
|
x=0.5,
|
||||||
xanchor="center",
|
xanchor="center",
|
||||||
),
|
),
|
||||||
margin=dict(t=60, l=10, r=10, b=30),
|
margin=dict(t=40, l=8, r=8, b=24), # Reduced margins
|
||||||
hoverlabel=dict(
|
hoverlabel=dict(
|
||||||
bgcolor="#FFFFFF",
|
bgcolor="#FFFFFF",
|
||||||
bordercolor="#CBD5E1", # Slate 300
|
bordercolor="#CBD5E1", # Slate 300
|
||||||
@@ -1364,8 +1369,8 @@ class AppState(rx.State):
|
|||||||
),
|
),
|
||||||
paper_bgcolor="rgba(0,0,0,0)", # Transparent background
|
paper_bgcolor="rgba(0,0,0,0)", # Transparent background
|
||||||
plot_bgcolor="rgba(0,0,0,0)",
|
plot_bgcolor="rgba(0,0,0,0)",
|
||||||
# Responsive sizing - height set but width auto
|
# v2.1: Responsive sizing - no fixed height, container controls size
|
||||||
height=600,
|
autosize=True,
|
||||||
# Enable interactivity
|
# Enable interactivity
|
||||||
clickmode="event+select",
|
clickmode="event+select",
|
||||||
)
|
)
|
||||||
@@ -2193,15 +2198,23 @@ def chart_display() -> rx.Component:
|
|||||||
chart_data changes (which happens when filters change).
|
chart_data changes (which happens when filters change).
|
||||||
|
|
||||||
Uses rx.plotly() to render the Plotly figure object.
|
Uses rx.plotly() to render the Plotly figure object.
|
||||||
|
|
||||||
|
v2.1: Full-height responsive layout using calc(100vh - overhead).
|
||||||
|
Overhead = top bar (48px) + filter strip (48px) + padding (16px) + chart header (~40px) = 152px
|
||||||
"""
|
"""
|
||||||
|
# Calculate available height: viewport minus fixed elements
|
||||||
|
# 48px top bar + 48px filter strip + 16px padding + 40px chart header
|
||||||
|
chart_height = "calc(100vh - 152px)"
|
||||||
|
|
||||||
return rx.box(
|
return rx.box(
|
||||||
rx.plotly(
|
rx.plotly(
|
||||||
data=AppState.icicle_figure,
|
data=AppState.icicle_figure,
|
||||||
width="100%",
|
width="100%",
|
||||||
height="600px",
|
height=chart_height,
|
||||||
),
|
),
|
||||||
width="100%",
|
width="100%",
|
||||||
min_height="600px",
|
min_height="500px",
|
||||||
|
height=chart_height,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -2218,10 +2231,12 @@ def chart_section() -> rx.Component:
|
|||||||
- Ready: Shows interactive Plotly icicle chart
|
- Ready: Shows interactive Plotly icicle chart
|
||||||
|
|
||||||
The chart updates reactively when filters change via the icicle_figure computed property.
|
The chart updates reactively when filters change via the icicle_figure computed property.
|
||||||
|
|
||||||
|
v2.1: Full-width chart layout with minimal chrome. No card styling - chart fills space.
|
||||||
"""
|
"""
|
||||||
return rx.box(
|
return rx.box(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
# Header row with title and chart type info
|
# Header row with title and chart type info (minimal height)
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
rx.text(
|
rx.text(
|
||||||
"Patient Pathway Visualization",
|
"Patient Pathway Visualization",
|
||||||
@@ -2234,7 +2249,7 @@ def chart_section() -> rx.Component:
|
|||||||
color=Colors.SLATE_500,
|
color=Colors.SLATE_500,
|
||||||
),
|
),
|
||||||
rx.text(
|
rx.text(
|
||||||
"Hierarchical view: Trust → Directorate → Drug → Patient Pathway",
|
"Trust → Directorate → Drug → Patient Pathway",
|
||||||
font_size=Typography.CAPTION_SIZE,
|
font_size=Typography.CAPTION_SIZE,
|
||||||
font_weight=Typography.CAPTION_WEIGHT,
|
font_weight=Typography.CAPTION_WEIGHT,
|
||||||
color=Colors.SLATE_500,
|
color=Colors.SLATE_500,
|
||||||
@@ -2246,7 +2261,6 @@ def chart_section() -> rx.Component:
|
|||||||
justify="between",
|
justify="between",
|
||||||
align="center",
|
align="center",
|
||||||
width="100%",
|
width="100%",
|
||||||
flex_wrap="wrap",
|
|
||||||
),
|
),
|
||||||
# Chart container with state-based rendering
|
# Chart container with state-based rendering
|
||||||
rx.cond(
|
rx.cond(
|
||||||
@@ -2268,12 +2282,18 @@ def chart_section() -> rx.Component:
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
spacing="4",
|
spacing="2", # Tighter spacing between header and chart
|
||||||
width="100%",
|
width="100%",
|
||||||
align="start",
|
align="start",
|
||||||
|
flex="1", # Fill available space
|
||||||
),
|
),
|
||||||
**card_style(),
|
# v2.1: Minimal styling - no card border, just subtle background
|
||||||
|
background_color=Colors.WHITE,
|
||||||
|
border_radius=Radii.MD,
|
||||||
width="100%",
|
width="100%",
|
||||||
|
flex="1", # Grow to fill remaining space
|
||||||
|
display="flex",
|
||||||
|
flex_direction="column",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -2283,22 +2303,28 @@ def main_content() -> rx.Component:
|
|||||||
|
|
||||||
Layout (v2.1): Filter Section (with KPI badges) → Chart Section
|
Layout (v2.1): Filter Section (with KPI badges) → Chart Section
|
||||||
KPIs are now inline badges in the filter strip (zero extra height).
|
KPIs are now inline badges in the filter strip (zero extra height).
|
||||||
Max width constrained to PAGE_MAX_WIDTH, centered.
|
|
||||||
|
v2.1: Full-width layout - no max-width constraint for chart.
|
||||||
|
Uses 16px horizontal padding per DESIGN_SYSTEM.md.
|
||||||
"""
|
"""
|
||||||
return rx.box(
|
return rx.box(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
filter_section(),
|
filter_section(),
|
||||||
# KPIs now integrated into filter_section as badges
|
# KPIs now integrated into filter_section as badges
|
||||||
chart_section(),
|
chart_section(),
|
||||||
spacing="4", # Tighter spacing
|
spacing="2", # Minimal spacing between filter strip and chart
|
||||||
width="100%",
|
width="100%",
|
||||||
align="stretch",
|
align="stretch",
|
||||||
|
flex="1", # Fill remaining height
|
||||||
),
|
),
|
||||||
width="100%",
|
width="100%",
|
||||||
max_width=PAGE_MAX_WIDTH,
|
# v2.1: No max-width constraint - chart fills viewport
|
||||||
margin_x="auto",
|
padding_x=Spacing.XL, # 16px horizontal padding
|
||||||
padding=PAGE_PADDING,
|
|
||||||
padding_top=Spacing.MD, # Tighter top padding
|
padding_top=Spacing.MD, # Tighter top padding
|
||||||
|
padding_bottom=Spacing.MD,
|
||||||
|
flex="1", # Fill remaining height
|
||||||
|
display="flex",
|
||||||
|
flex_direction="column",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -2307,9 +2333,11 @@ def page_layout() -> rx.Component:
|
|||||||
Full page layout combining top bar and main content.
|
Full page layout combining top bar and main content.
|
||||||
|
|
||||||
Structure:
|
Structure:
|
||||||
- Sticky top bar (64px)
|
- Sticky top bar (48px)
|
||||||
- Scrollable main content area
|
- Full-height main content area
|
||||||
- White background
|
- White background
|
||||||
|
|
||||||
|
v2.1: Uses flexbox to fill viewport height with chart.
|
||||||
"""
|
"""
|
||||||
return rx.box(
|
return rx.box(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
@@ -2317,11 +2345,14 @@ def page_layout() -> rx.Component:
|
|||||||
main_content(),
|
main_content(),
|
||||||
spacing="0",
|
spacing="0",
|
||||||
width="100%",
|
width="100%",
|
||||||
min_height="100vh",
|
height="100vh", # Full viewport height
|
||||||
|
flex="1",
|
||||||
),
|
),
|
||||||
background_color=Colors.WHITE,
|
background_color=Colors.WHITE,
|
||||||
font_family=Typography.FONT_FAMILY,
|
font_family=Typography.FONT_FAMILY,
|
||||||
width="100%",
|
width="100%",
|
||||||
|
height="100vh", # Full viewport height
|
||||||
|
overflow="hidden", # Prevent scrollbars on outer container
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user