deploy
This commit is contained in:
@@ -40,21 +40,30 @@ export function ProductCard({ product, mediaHeight = 200, actions }: Props) {
|
|||||||
swiperRef.current.slideTo(idx, 0)
|
swiperRef.current.slideTo(idx, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stockLabel =
|
||||||
|
product.inStock && product.quantity === 0
|
||||||
|
? { label: 'Нет в наличии', color: 'default' as const }
|
||||||
|
: !product.inStock
|
||||||
|
? { label: `Под заказ · ${product.leadTimeDays ?? '—'} дн.`, color: 'warning' as const }
|
||||||
|
: null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
variant="outlined"
|
|
||||||
sx={{
|
sx={{
|
||||||
height: '100%',
|
height: '100%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
transition: 'transform 160ms ease, box-shadow 160ms ease, border-color 160ms ease',
|
borderRadius: 3,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'divider',
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
transition: 'transform 200ms ease, box-shadow 250ms ease',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
transform: 'translateY(-3px)',
|
transform: 'translateY(-4px)',
|
||||||
boxShadow: 6,
|
boxShadow: '0 8px 30px rgba(0,0,0,0.10)',
|
||||||
borderColor: 'divider',
|
|
||||||
},
|
},
|
||||||
'&:hover .product-card__media': { transform: 'scale(1.03)' },
|
'&:hover .product-card__media': { transform: 'scale(1.06)' },
|
||||||
'@media (prefers-reduced-motion: reduce)': {
|
'@media (prefers-reduced-motion: reduce)': {
|
||||||
transition: 'none',
|
transition: 'none',
|
||||||
'&:hover': { transform: 'none' },
|
'&:hover': { transform: 'none' },
|
||||||
@@ -67,10 +76,10 @@ export function ProductCard({ product, mediaHeight = 200, actions }: Props) {
|
|||||||
to={`/products/${product.id}`}
|
to={`/products/${product.id}`}
|
||||||
underline="none"
|
underline="none"
|
||||||
color="inherit"
|
color="inherit"
|
||||||
sx={{ display: 'block' }}
|
sx={{ display: 'block', position: 'relative' }}
|
||||||
>
|
>
|
||||||
{imageUrls.length ? (
|
{imageUrls.length ? (
|
||||||
<Box onMouseMove={onMouseMove} sx={{ height: mediaHeight }}>
|
<Box onMouseMove={onMouseMove} sx={{ height: mediaHeight, overflow: 'hidden' }}>
|
||||||
<Swiper
|
<Swiper
|
||||||
onSwiper={(s) => {
|
onSwiper={(s) => {
|
||||||
swiperRef.current = s
|
swiperRef.current = s
|
||||||
@@ -90,9 +99,10 @@ export function ProductCard({ product, mediaHeight = 200, actions }: Props) {
|
|||||||
height: mediaHeight,
|
height: mediaHeight,
|
||||||
objectFit: 'cover',
|
objectFit: 'cover',
|
||||||
display: 'block',
|
display: 'block',
|
||||||
transition: 'transform 240ms ease',
|
transition: 'transform 320ms ease',
|
||||||
'@media (prefers-reduced-motion: reduce)': { transition: 'none' },
|
'@media (prefers-reduced-motion: reduce)': { transition: 'none' },
|
||||||
userSelect: 'none',
|
userSelect: 'none',
|
||||||
|
bgcolor: 'grey.50',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
@@ -103,62 +113,104 @@ export function ProductCard({ product, mediaHeight = 200, actions }: Props) {
|
|||||||
<CardMedia
|
<CardMedia
|
||||||
component="div"
|
component="div"
|
||||||
sx={{
|
sx={{
|
||||||
height: 200,
|
height: mediaHeight,
|
||||||
bgcolor: 'grey.100',
|
bgcolor: 'grey.50',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography color="text.secondary">Нет фото</Typography>
|
<Typography color="text.disabled" variant="body2">
|
||||||
|
Нет фото
|
||||||
|
</Typography>
|
||||||
</CardMedia>
|
</CardMedia>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{stockLabel && (
|
||||||
|
<Chip
|
||||||
|
label={stockLabel.label}
|
||||||
|
size="small"
|
||||||
|
color={stockLabel.color}
|
||||||
|
variant={stockLabel.color === 'warning' ? 'outlined' : 'filled'}
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 8,
|
||||||
|
left: 8,
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: '0.7rem',
|
||||||
|
backdropFilter: 'blur(4px)',
|
||||||
|
bgcolor: stockLabel.color === 'default' ? 'rgba(0,0,0,0.55)' : undefined,
|
||||||
|
color: stockLabel.color === 'default' ? 'common.white' : undefined,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
<CardContent sx={{ flexGrow: 1 }}>
|
|
||||||
<Stack spacing={1}>
|
<CardContent sx={{ flexGrow: 1, p: 2, '&:last-child': { pb: 2 } }}>
|
||||||
{product.category && <Chip label={product.category.name} size="small" />}
|
<Stack spacing={1.25}>
|
||||||
{product.inStock && product.quantity === 0 && <Chip label="Нет в наличии" size="small" color="default" />}
|
{product.category && (
|
||||||
{!product.inStock && (
|
|
||||||
<Chip
|
<Chip
|
||||||
label={`Под заказ · ${product.leadTimeDays ?? '—'} дн.`}
|
label={product.category.name}
|
||||||
size="small"
|
size="small"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="warning"
|
sx={{ alignSelf: 'flex-start', fontWeight: 500, fontSize: '0.7rem' }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
variant="h6"
|
variant="subtitle1"
|
||||||
component={RouterLink}
|
component={RouterLink}
|
||||||
to={`/products/${product.id}`}
|
to={`/products/${product.id}`}
|
||||||
style={{ textDecoration: 'none', color: 'inherit' }}
|
sx={{
|
||||||
|
textDecoration: 'none',
|
||||||
|
color: 'text.primary',
|
||||||
|
fontWeight: 600,
|
||||||
|
lineHeight: 1.3,
|
||||||
|
transition: 'color 150ms ease',
|
||||||
|
'&:hover': { color: 'primary.main' },
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{product.title}
|
{product.title}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{(product.materials?.length ?? 0) > 0 && (
|
{(product.materials?.length ?? 0) > 0 && (
|
||||||
<Stack direction="row" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>
|
<Stack direction="row" spacing={0.5} useFlexGap sx={{ flexWrap: 'wrap' }}>
|
||||||
{materials.map((m) => (
|
{materials.map((m) => (
|
||||||
<Chip key={m} label={m} size="small" variant="outlined" />
|
<Chip key={m} label={m} size="small" variant="outlined" sx={{ fontSize: '0.7rem', height: 22 }} />
|
||||||
))}
|
))}
|
||||||
{moreMaterials > 0 && <Chip label={`+${moreMaterials}`} size="small" variant="outlined" />}
|
{moreMaterials > 0 && (
|
||||||
|
<Chip
|
||||||
|
label={`+${moreMaterials}`}
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
sx={{ fontSize: '0.7rem', height: 22 }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Typography
|
<Typography
|
||||||
variant="body2"
|
variant="body2"
|
||||||
color="text.secondary"
|
color="text.secondary"
|
||||||
sx={{
|
sx={{
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
WebkitLineClamp: 3,
|
WebkitLineClamp: 2,
|
||||||
display: '-webkit-box',
|
display: '-webkit-box',
|
||||||
WebkitBoxOrient: 'vertical',
|
WebkitBoxOrient: 'vertical',
|
||||||
|
fontSize: '0.8125rem',
|
||||||
|
lineHeight: 1.45,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{product.shortDescription ?? 'Описание появится позже.'}
|
{product.shortDescription ?? 'Описание появится позже.'}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6" color="primary">
|
|
||||||
{formatPriceRub(product.priceCents)}
|
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mt: 'auto', pt: 0.5 }}>
|
||||||
</Typography>
|
<Typography variant="h6" color="primary" sx={{ fontWeight: 700, fontSize: '1.1rem' }}>
|
||||||
{actions}
|
{formatPriceRub(product.priceCents)}
|
||||||
|
</Typography>
|
||||||
|
{actions}
|
||||||
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
Reference in New Issue
Block a user