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>
|
</Box>
|
||||||
|
|
||||||
{/* Floating control strip */}
|
{/* Floating control strip — no container chrome; each control has
|
||||||
<Paper
|
its own fill/border so it reads cleanly over any map tile */}
|
||||||
elevation={0}
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 12,
|
top: 12,
|
||||||
left: 12,
|
left: 12,
|
||||||
right: 12,
|
right: 12,
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
p: 1,
|
|
||||||
borderRadius: 2,
|
|
||||||
boxShadow: 'var(--fa-shadow-md)',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
gap: 1,
|
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 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||||
<FilterPanel
|
<FilterPanel
|
||||||
activeCount={activeCount}
|
activeCount={activeCount}
|
||||||
onClear={handleClear}
|
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}
|
{filterDialogChildren}
|
||||||
</FilterPanel>
|
</FilterPanel>
|
||||||
|
|
||||||
<Button
|
{/* Sort — icon-only on mobile (expansion of the current sort
|
||||||
variant="outlined"
|
surfaced through the menu + aria-label) */}
|
||||||
color="secondary"
|
<IconButton
|
||||||
size="small"
|
|
||||||
startIcon={<SwapVertIcon sx={{ fontSize: 16 }} />}
|
|
||||||
onClick={(e) => setSortAnchor(e.currentTarget)}
|
onClick={(e) => setSortAnchor(e.currentTarget)}
|
||||||
aria-haspopup="listbox"
|
aria-haspopup="listbox"
|
||||||
aria-label={`Sort by ${SORT_OPTIONS.find((o) => o.value === sortBy)?.label ?? 'Recommended'}`}
|
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 }}>
|
<SwapVertIcon sx={{ fontSize: 18 }} />
|
||||||
Sort:
|
</IconButton>
|
||||||
</Box>
|
|
||||||
{SORT_OPTIONS.find((o) => o.value === sortBy)?.label ?? 'Recommended'}
|
|
||||||
</Button>
|
|
||||||
<Menu
|
<Menu
|
||||||
anchorEl={sortAnchor}
|
anchorEl={sortAnchor}
|
||||||
open={Boolean(sortAnchor)}
|
open={Boolean(sortAnchor)}
|
||||||
@@ -681,7 +693,7 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
|||||||
))}
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
{/* View toggle — icon-only on mobile to keep the row tight */}
|
{/* View toggle — icon-only, aligned height with the buttons */}
|
||||||
<ToggleButtonGroup
|
<ToggleButtonGroup
|
||||||
value={viewMode}
|
value={viewMode}
|
||||||
exclusive
|
exclusive
|
||||||
@@ -692,8 +704,11 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
|||||||
ml: 'auto',
|
ml: 'auto',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
'& .MuiToggleButton-root': {
|
'& .MuiToggleButton-root': {
|
||||||
|
height: 32,
|
||||||
px: 1,
|
px: 1,
|
||||||
py: 0.5,
|
py: 0,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
'&:hover': { bgcolor: 'background.paper' },
|
||||||
'&.Mui-selected': {
|
'&.Mui-selected': {
|
||||||
bgcolor: 'var(--fa-color-brand-100)',
|
bgcolor: 'var(--fa-color-brand-100)',
|
||||||
color: 'primary.main',
|
color: 'primary.main',
|
||||||
@@ -710,7 +725,7 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
|||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</ToggleButtonGroup>
|
</ToggleButtonGroup>
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Box>
|
||||||
|
|
||||||
{/* Bottom drawer — slides up when a pin/cluster is active */}
|
{/* Bottom drawer — slides up when a pin/cluster is active */}
|
||||||
<Paper
|
<Paper
|
||||||
@@ -741,28 +756,42 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
|||||||
pointerEvents: drawerOpen ? 'auto' : 'none',
|
pointerEvents: drawerOpen ? 'auto' : 'none',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Close X */}
|
{/* Drawer header — holds the close X (and the cluster count when
|
||||||
|
applicable) so it doesn't sit over the card image */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
minHeight: 40,
|
||||||
|
px: 1.5,
|
||||||
|
py: 0.5,
|
||||||
|
gap: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{drawerCluster && !drawerProvider && (
|
||||||
|
<Typography variant="labelLg" sx={{ color: 'text.secondary', display: 'block' }}>
|
||||||
|
{drawerCluster.providers.length} providers in this area
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
onClick={() => mapRef.current?.clearActive()}
|
onClick={() => mapRef.current?.clearActive()}
|
||||||
|
size="small"
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
ml: 'auto',
|
||||||
top: 8,
|
|
||||||
right: 8,
|
|
||||||
zIndex: 1,
|
|
||||||
width: 32,
|
width: 32,
|
||||||
height: 32,
|
height: 32,
|
||||||
bgcolor: 'background.paper',
|
color: 'text.secondary',
|
||||||
boxShadow: 'var(--fa-shadow-sm)',
|
'&:hover': { bgcolor: 'var(--fa-color-surface-subtle)' },
|
||||||
'&:hover': { bgcolor: 'background.paper' },
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CloseRoundedIcon sx={{ fontSize: 18 }} />
|
<CloseRoundedIcon sx={{ fontSize: 20 }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
|
||||||
{/* Single-provider drawer content — entire card clickable */}
|
{/* Single-provider drawer content — entire card clickable */}
|
||||||
{drawerProvider && (
|
{drawerProvider && (
|
||||||
<Box sx={{ p: 1.5 }}>
|
<Box sx={{ px: 1.5, pb: 1.5 }}>
|
||||||
<ProviderCard
|
<ProviderCard
|
||||||
name={drawerProvider.name}
|
name={drawerProvider.name}
|
||||||
location={drawerProvider.location}
|
location={drawerProvider.location}
|
||||||
@@ -780,13 +809,7 @@ export const ProvidersStep: React.FC<ProvidersStepProps> = ({
|
|||||||
|
|
||||||
{/* Cluster list drawer content — tap row to drill in */}
|
{/* Cluster list drawer content — tap row to drill in */}
|
||||||
{drawerCluster && !drawerProvider && (
|
{drawerCluster && !drawerProvider && (
|
||||||
<Box sx={{ pt: 5, pb: 1 }}>
|
<Box sx={{ pb: 1 }}>
|
||||||
<Typography
|
|
||||||
variant="labelLg"
|
|
||||||
sx={{ px: 2, pb: 1, color: 'text.secondary', display: 'block' }}
|
|
||||||
>
|
|
||||||
{drawerCluster.providers.length} providers in this area
|
|
||||||
</Typography>
|
|
||||||
<Box>
|
<Box>
|
||||||
{[...drawerCluster.providers]
|
{[...drawerCluster.providers]
|
||||||
.sort((a, b) => Number(!!b.verified) - Number(!!a.verified))
|
.sort((a, b) => Number(!!b.verified) - Number(!!a.verified))
|
||||||
|
|||||||
Reference in New Issue
Block a user