189 lines
5.7 KiB
TypeScript
189 lines
5.7 KiB
TypeScript
import React from 'react';
|
||
import { Box, Slider, Typography } from '@mui/material';
|
||
|
||
interface MemorySliderProps {
|
||
memory: number;
|
||
onChange: (e: Event, value: number | number[]) => void;
|
||
min?: number;
|
||
max?: number;
|
||
step?: number;
|
||
}
|
||
|
||
const gradientPrimary =
|
||
'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)';
|
||
|
||
const formatMb = (v: number) => `${v} MB`;
|
||
const formatGb = (v: number) => `${(v / 1024).toFixed(v % 1024 === 0 ? 0 : 1)} GB`;
|
||
|
||
const MemorySlider = ({
|
||
memory,
|
||
onChange,
|
||
min = 1024,
|
||
max = 32768,
|
||
step = 1024,
|
||
}: MemorySliderProps) => {
|
||
// marks только на “красивых” значениях, чтобы не было каши
|
||
const marks = [
|
||
{ value: 1024, label: '1 GB' },
|
||
{ value: 4096, label: '4 GB' },
|
||
{ value: 8192, label: '8 GB' },
|
||
{ value: 16384, label: '16 GB' },
|
||
{ value: 32768, label: '32 GB' },
|
||
].filter((m) => m.value >= min && m.value <= max);
|
||
|
||
return (
|
||
<Box sx={{ width: '100%' }}>
|
||
{/* Header */}
|
||
<Box
|
||
sx={{
|
||
display: 'flex',
|
||
alignItems: 'baseline',
|
||
justifyContent: 'space-between',
|
||
mb: '1.2vh',
|
||
}}
|
||
>
|
||
<Typography
|
||
sx={{
|
||
fontFamily: 'Benzin-Bold, system-ui, -apple-system, Segoe UI, Roboto, Arial',
|
||
fontWeight: 800,
|
||
fontSize: '1.1vw',
|
||
color: '#fff',
|
||
textTransform: 'uppercase',
|
||
letterSpacing: 0.5,
|
||
}}
|
||
>
|
||
Память
|
||
</Typography>
|
||
|
||
<Typography
|
||
sx={{
|
||
fontFamily: 'Benzin-Bold, system-ui, -apple-system, Segoe UI, Roboto, Arial',
|
||
fontWeight: 800,
|
||
fontSize: '1.1vw',
|
||
backgroundImage: gradientPrimary,
|
||
WebkitBackgroundClip: 'text',
|
||
WebkitTextFillColor: 'transparent',
|
||
}}
|
||
>
|
||
{memory >= 1024 ? formatGb(memory) : formatMb(memory)}
|
||
</Typography>
|
||
</Box>
|
||
|
||
<Slider
|
||
name="memory"
|
||
aria-label="Memory"
|
||
valueLabelDisplay="auto"
|
||
valueLabelFormat={(v) => (v >= 1024 ? formatGb(v as number) : formatMb(v as number))}
|
||
shiftStep={step}
|
||
step={step}
|
||
marks={marks}
|
||
min={min}
|
||
max={max}
|
||
value={memory}
|
||
onChange={onChange}
|
||
sx={{
|
||
px: '0.2vw',
|
||
|
||
// rail (фон полосы)
|
||
'& .MuiSlider-rail': {
|
||
opacity: 1,
|
||
height: '0.9vh',
|
||
borderRadius: '999vw',
|
||
backgroundColor: 'rgba(255,255,255,0.10)',
|
||
boxShadow: 'inset 0 0.25vh 0.6vh rgba(0,0,0,0.45)',
|
||
},
|
||
|
||
// track (заполненная часть)
|
||
'& .MuiSlider-track': {
|
||
height: '0.9vh',
|
||
borderRadius: '999vw',
|
||
border: 'none',
|
||
background: gradientPrimary,
|
||
boxShadow: '0 0.6vh 1.6vh rgba(233,64,205,0.18)',
|
||
},
|
||
|
||
// thumb (ползунок)
|
||
'& .MuiSlider-thumb': {
|
||
width: '1.6vw',
|
||
height: '1.6vw',
|
||
minWidth: 14,
|
||
minHeight: 14,
|
||
borderRadius: '999vw',
|
||
background: 'rgba(10,10,20,0.92)',
|
||
border: '0.22vw solid rgba(255,255,255,0.18)',
|
||
boxShadow:
|
||
'0 0.9vh 2.4vh rgba(0,0,0,0.55), 0 0 1.2vw rgba(242,113,33,0.20)',
|
||
transition: 'transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease',
|
||
'&:hover': {
|
||
// transform: 'scale(1.06)',
|
||
borderColor: 'rgba(242,113,33,0.55)',
|
||
boxShadow:
|
||
'0 1.1vh 2.8vh rgba(0,0,0,0.62), 0 0 1.6vw rgba(233,64,205,0.28)',
|
||
},
|
||
|
||
// внутренний “свет”
|
||
'&:before': {
|
||
content: '""',
|
||
position: 'absolute',
|
||
inset: '18%',
|
||
borderRadius: '999vw',
|
||
background: gradientPrimary,
|
||
opacity: 0.85,
|
||
filter: 'blur(0.3vw)',
|
||
},
|
||
},
|
||
|
||
// value label (плашка значения)
|
||
'& .MuiSlider-valueLabel': {
|
||
fontFamily: 'Benzin-Bold, system-ui, -apple-system, Segoe UI, Roboto, Arial',
|
||
fontSize: '0.85vw',
|
||
borderRadius: '1.2vw',
|
||
padding: '0.4vh 0.8vw',
|
||
color: '#fff',
|
||
background: 'rgba(0,0,0,0.55)',
|
||
border: '1px solid rgba(255,255,255,0.10)',
|
||
backdropFilter: 'blur(10px)',
|
||
boxShadow: '0 1.2vh 3vh rgba(0,0,0,0.55)',
|
||
'&:before': { display: 'none' },
|
||
},
|
||
|
||
// marks (точки)
|
||
'& .MuiSlider-mark': {
|
||
width: '0.35vw',
|
||
height: '0.35vw',
|
||
minWidth: 4,
|
||
minHeight: 4,
|
||
borderRadius: '999vw',
|
||
backgroundColor: 'rgba(255,255,255,0.18)',
|
||
},
|
||
'& .MuiSlider-markActive': {
|
||
backgroundColor: 'rgba(255,255,255,0.55)',
|
||
},
|
||
|
||
// mark labels (подписи)
|
||
'& .MuiSlider-markLabel': {
|
||
color: 'rgba(255,255,255,0.55)',
|
||
fontSize: '0.75vw',
|
||
marginTop: '1vh',
|
||
userSelect: 'none',
|
||
},
|
||
|
||
// focus outline
|
||
'& .MuiSlider-thumb.Mui-focusVisible': {
|
||
outline: 'none',
|
||
boxShadow:
|
||
'0 0 0 0.25vw rgba(242,113,33,0.20), 0 1.1vh 2.8vh rgba(0,0,0,0.62)',
|
||
},
|
||
}}
|
||
/>
|
||
|
||
{/* Subtext */}
|
||
<Typography sx={{ mt: '1.2vh', color: 'rgba(255,255,255,0.55)', fontSize: '0.85vw' }}>
|
||
Шаг: {formatGb(step)} • Рекомендуем: 4–8 GB для большинства сборок
|
||
</Typography>
|
||
</Box>
|
||
);
|
||
};
|
||
|
||
export default MemorySlider;
|