ProvidersStep mobile: transparent control strip, icon-only sort, drawer header
- Drop the Paper container around the mobile-map floating controls —
each control (Filters, Sort, view toggle) now carries its own white
fill and reads over any map tile without a shared box
- Sort button becomes icon-only on mobile-map (the current sort is
still communicated via the aria-label and the menu) — saves the
row's horizontal budget
- Align all three controls to 32px height so Filters, Sort, and the
List/Map toggle sit on a common baseline
- Move the drawer close X out of the image overlay area into a
dedicated 40px drawer header bar; cluster header text ("N providers
in this area") now lives in the same strip. No more overlap with the
Verified badge on the card image.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -538,18 +538,15 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Floating control strip */}
|
||||
<Paper
|
||||
elevation={0}
|
||||
{/* Floating control strip — no container chrome; each control has
|
||||
its own fill/border so it reads cleanly over any map tile */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
left: 12,
|
||||
right: 12,
|
||||
zIndex: 2,
|
||||
p: 1,
|
||||
borderRadius: 2,
|
||||
boxShadow: 'var(--fa-shadow-md)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 1,
|
||||
@@ -634,31 +631,46 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Control row: Filters, Sort, view toggle */}
|
||||
{/* Control row: Filters, Sort (icon-only on mobile), view toggle.
|
||||
Each control carries its own white fill so it reads cleanly
|
||||
over any map tile — no shared container. Heights aligned at
|
||||
32px to match Button small + ToggleButton small. */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<FilterPanel
|
||||
activeCount={activeCount}
|
||||
onClear={handleClear}
|
||||
sx={{ '& .MuiButton-root:focus-visible': { outline: 'none' } }}
|
||||
sx={{
|
||||
'& .MuiButton-root': {
|
||||
height: 32,
|
||||
bgcolor: 'background.paper',
|
||||
'&:hover': { bgcolor: 'background.paper' },
|
||||
'&:focus-visible': { outline: 'none' },
|
||||
},
|
||||
}}
|
||||
>
|
||||
{filterDialogChildren}
|
||||
</FilterPanel>
|
||||
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
size="small"
|
||||
startIcon={<SwapVertIcon sx={{ fontSize: 16 }} />}
|
||||
{/* Sort — icon-only on mobile (expansion of the current sort
|
||||
surfaced through the menu + aria-label) */}
|
||||
<IconButton
|
||||
onClick={(e) => setSortAnchor(e.currentTarget)}
|
||||
aria-haspopup="listbox"
|
||||
aria-label={`Sort by ${SORT_OPTIONS.find((o) => o.value === sortBy)?.label ?? 'Recommended'}`}
|
||||
sx={{ textTransform: 'none', '&:focus-visible': { outline: 'none' } }}
|
||||
sx={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 1,
|
||||
border: '1px solid',
|
||||
borderColor: 'divider',
|
||||
bgcolor: 'background.paper',
|
||||
color: 'text.secondary',
|
||||
'&:hover': { bgcolor: 'background.paper' },
|
||||
'&:focus-visible': { outline: 'none' },
|
||||
}}
|
||||
>
|
||||
<Box component="span" sx={{ color: 'text.secondary', fontWeight: 400, mr: 0.5 }}>
|
||||
Sort:
|
||||
</Box>
|
||||
{SORT_OPTIONS.find((o) => o.value === sortBy)?.label ?? 'Recommended'}
|
||||
</Button>
|
||||
<SwapVertIcon sx={{ fontSize: 18 }} />
|
||||
</IconButton>
|
||||
<Menu
|
||||
anchorEl={sortAnchor}
|
||||
open={Boolean(sortAnchor)}
|
||||
@@ -681,7 +693,7 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
||||
))}
|
||||
</Menu>
|
||||
|
||||
{/* View toggle — icon-only on mobile to keep the row tight */}
|
||||
{/* View toggle — icon-only, aligned height with the buttons */}
|
||||
<ToggleButtonGroup
|
||||
value={viewMode}
|
||||
exclusive
|
||||
@@ -692,8 +704,11 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
||||
ml: 'auto',
|
||||
flexShrink: 0,
|
||||
'& .MuiToggleButton-root': {
|
||||
height: 32,
|
||||
px: 1,
|
||||
py: 0.5,
|
||||
py: 0,
|
||||
bgcolor: 'background.paper',
|
||||
'&:hover': { bgcolor: 'background.paper' },
|
||||
'&.Mui-selected': {
|
||||
bgcolor: 'var(--fa-color-brand-100)',
|
||||
color: 'primary.main',
|
||||
@@ -710,7 +725,7 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
{/* Bottom drawer — slides up when a pin/cluster is active */}
|
||||
<Paper
|
||||
@@ -741,28 +756,42 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
||||
pointerEvents: drawerOpen ? 'auto' : 'none',
|
||||
}}
|
||||
>
|
||||
{/* Close X */}
|
||||
<IconButton
|
||||
aria-label="Close"
|
||||
onClick={() => mapRef.current?.clearActive()}
|
||||
{/* Drawer header — holds the close X (and the cluster count when
|
||||
applicable) so it doesn't sit over the card image */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 8,
|
||||
right: 8,
|
||||
zIndex: 1,
|
||||
width: 32,
|
||||
height: 32,
|
||||
bgcolor: 'background.paper',
|
||||
boxShadow: 'var(--fa-shadow-sm)',
|
||||
'&:hover': { bgcolor: 'background.paper' },
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
minHeight: 40,
|
||||
px: 1.5,
|
||||
py: 0.5,
|
||||
gap: 1,
|
||||
}}
|
||||
>
|
||||
<CloseRoundedIcon sx={{ fontSize: 18 }} />
|
||||
</IconButton>
|
||||
{drawerCluster && !drawerProvider && (
|
||||
<Typography variant="labelLg" sx={{ color: 'text.secondary', display: 'block' }}>
|
||||
{drawerCluster.providers.length} providers in this area
|
||||
</Typography>
|
||||
)}
|
||||
<IconButton
|
||||
aria-label="Close"
|
||||
onClick={() => mapRef.current?.clearActive()}
|
||||
size="small"
|
||||
sx={{
|
||||
ml: 'auto',
|
||||
width: 32,
|
||||
height: 32,
|
||||
color: 'text.secondary',
|
||||
'&:hover': { bgcolor: 'var(--fa-color-surface-subtle)' },
|
||||
}}
|
||||
>
|
||||
<CloseRoundedIcon sx={{ fontSize: 20 }} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
||||
{/* Single-provider drawer content — entire card clickable */}
|
||||
{drawerProvider && (
|
||||
<Box sx={{ p: 1.5 }}>
|
||||
<Box sx={{ px: 1.5, pb: 1.5 }}>
|
||||
<ProviderCard
|
||||
name={drawerProvider.name}
|
||||
location={drawerProvider.location}
|
||||
@@ -780,13 +809,7 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
||||
|
||||
{/* Cluster list drawer content — tap row to drill in */}
|
||||
{drawerCluster && !drawerProvider && (
|
||||
<Box sx={{ pt: 5, pb: 1 }}>
|
||||
<Typography
|
||||
variant="labelLg"
|
||||
sx={{ px: 2, pb: 1, color: 'text.secondary', display: 'block' }}
|
||||
>
|
||||
{drawerCluster.providers.length} providers in this area
|
||||
</Typography>
|
||||
<Box sx={{ pb: 1 }}>
|
||||
<Box>
|
||||
{[...drawerCluster.providers]
|
||||
.sort((a, b) => Number(!!b.verified) - Number(!!a.verified))
|
||||
|
||||
Reference in New Issue
Block a user