updated the ui for the mobile view
This commit is contained in:
140
src/components/nearle_components/MobileCard.js
Normal file
140
src/components/nearle_components/MobileCard.js
Normal file
@@ -0,0 +1,140 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { Box, Paper, Stack, Typography } from '@mui/material';
|
||||
|
||||
// ============================================================================
|
||||
// MobileCard — shared primitives that turn a desktop data-table row into an
|
||||
// app-style card on phones. Used by every operator list page (deliveries,
|
||||
// orders, customers, riders, tenants, …) so the mobile experience is
|
||||
// consistent. Purely presentational: pages keep their own data + handlers and
|
||||
// just slot content into these shells. Desktop layouts are untouched — these
|
||||
// only render inside an `isMobile` branch.
|
||||
//
|
||||
// Tokens mirror the `DT` block in deliveries.js so cards match page surfaces.
|
||||
// ============================================================================
|
||||
const BORDER = '#e2e8f0';
|
||||
const MUTED = '#94a3b8';
|
||||
const PRIMARY_TEXT = '#0f172a';
|
||||
|
||||
// Vertical list wrapper — drop-in replacement for <TableContainer>/<TableBody>
|
||||
// on mobile. `scroll` makes it an internal scroll region (matches the table's
|
||||
// maxHeight behaviour); omit it to let the page scroll naturally.
|
||||
export const MobileCardList = ({ children, scroll = false, onScroll, sx, ...rest }) => (
|
||||
<Stack
|
||||
spacing={1.25}
|
||||
onScroll={onScroll}
|
||||
sx={{
|
||||
p: 1.5,
|
||||
...(scroll && { maxHeight: 'calc(100vh - 220px)', overflowY: 'auto', overflowX: 'hidden' }),
|
||||
...sx
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Stack>
|
||||
);
|
||||
|
||||
MobileCardList.propTypes = {
|
||||
children: PropTypes.node,
|
||||
scroll: PropTypes.bool,
|
||||
onScroll: PropTypes.func,
|
||||
sx: PropTypes.object
|
||||
};
|
||||
|
||||
// Card shell — coloured accent rail on the left, a header slot (status badge /
|
||||
// title / action buttons), then any field grid / collapse content as children.
|
||||
export const MobileCard = ({ accent = '#662582', header, footer, selected = false, onClick, children, sx }) => (
|
||||
<Paper
|
||||
elevation={0}
|
||||
onClick={onClick}
|
||||
sx={{
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
// Cards live inside a flex-column list; without this, a scroll-capped
|
||||
// list (maxHeight) would SHRINK each card to a sliver (flex-shrink:1)
|
||||
// and clip its content instead of scrolling. Keep natural height.
|
||||
flexShrink: 0,
|
||||
borderRadius: 2.5,
|
||||
border: '1px solid',
|
||||
borderColor: selected ? accent : BORDER,
|
||||
background: selected ? `${accent}0a` : '#fff',
|
||||
boxShadow: '0 4px 14px rgba(15,23,42,0.05)',
|
||||
transition: 'border-color 0.15s, box-shadow 0.15s',
|
||||
...sx
|
||||
}}
|
||||
>
|
||||
<Box sx={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 3, bgcolor: accent }} />
|
||||
<Box sx={{ p: 1.5, pl: 2 }}>
|
||||
{header}
|
||||
{children}
|
||||
{footer}
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
|
||||
MobileCard.propTypes = {
|
||||
accent: PropTypes.string,
|
||||
header: PropTypes.node,
|
||||
footer: PropTypes.node,
|
||||
selected: PropTypes.bool,
|
||||
onClick: PropTypes.func,
|
||||
children: PropTypes.node,
|
||||
sx: PropTypes.object
|
||||
};
|
||||
|
||||
// Grid wrapper for MobileField cells. Two columns by default; pass `columns`
|
||||
// to change. Keeps every card's body alignment identical.
|
||||
export const MobileFieldGrid = ({ children, columns = 2, sx }) => (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
|
||||
gap: 1,
|
||||
mt: 1.25,
|
||||
...sx
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
|
||||
MobileFieldGrid.propTypes = {
|
||||
children: PropTypes.node,
|
||||
columns: PropTypes.number,
|
||||
sx: PropTypes.object
|
||||
};
|
||||
|
||||
// A single label/value cell. `full` makes it span the whole row; `value` can be
|
||||
// a string/number or any node (chip, stack, etc.).
|
||||
export const MobileField = ({ label, value, children, full = false, align = 'left' }) => (
|
||||
<Box sx={{ gridColumn: full ? '1 / -1' : 'auto', minWidth: 0, textAlign: align }}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: 9.5,
|
||||
fontWeight: 800,
|
||||
letterSpacing: 0.5,
|
||||
textTransform: 'uppercase',
|
||||
color: MUTED,
|
||||
lineHeight: 1.4
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Typography>
|
||||
<Box sx={{ mt: 0.25, minWidth: 0 }}>
|
||||
{children !== undefined ? (
|
||||
children
|
||||
) : (
|
||||
<Typography sx={{ fontSize: 13, fontWeight: 600, color: PRIMARY_TEXT }} noWrap>
|
||||
{value ?? '—'}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
MobileField.propTypes = {
|
||||
label: PropTypes.node,
|
||||
value: PropTypes.node,
|
||||
children: PropTypes.node,
|
||||
full: PropTypes.bool,
|
||||
align: PropTypes.string
|
||||
};
|
||||
Reference in New Issue
Block a user