2025-09-21 09:55:46 +00:00
|
|
|
import { CircularProgress, Box, Typography, useTheme, styled } from "@mui/material";
|
|
|
|
|
|
2025-09-21 10:06:41 +00:00
|
|
|
// Типизация для пропсов таймера
|
|
|
|
|
export interface CircularTimerProps {
|
|
|
|
|
duration: number; // Общая длительность в секундах
|
|
|
|
|
remaining: number; // Оставшееся время в секундах
|
|
|
|
|
showTime?: boolean; // Показывать ли время в формате mm:ss
|
|
|
|
|
size?: number; // Размер таймера
|
|
|
|
|
thickness?: number; // Толщина линии прогресса
|
|
|
|
|
color?: string; // Цвет прогресса
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-21 09:55:46 +00:00
|
|
|
const StyledCircularProgress = styled(CircularProgress)(({ theme }) => ({
|
|
|
|
|
"& .MuiCircularProgress-circle": {
|
|
|
|
|
strokeLinecap: "round",
|
|
|
|
|
transition: "stroke-dashoffset 0.3s ease",
|
|
|
|
|
},
|
|
|
|
|
}));
|
|
|
|
|
|
2025-09-21 10:06:41 +00:00
|
|
|
// Функция для форматирования времени в mm:ss
|
|
|
|
|
const formatTime = (seconds: number): string => {
|
|
|
|
|
const minutes = Math.floor(seconds / 60);
|
|
|
|
|
const remainingSeconds = Math.floor(seconds % 60);
|
|
|
|
|
return `${minutes.toString().padStart(2, "0")}:${remainingSeconds.toString().padStart(2, "0")}`;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const CustomCircularTimer: React.FC<CircularTimerProps> = ({
|
|
|
|
|
duration,
|
|
|
|
|
remaining,
|
|
|
|
|
showTime = true,
|
|
|
|
|
size = 76,
|
|
|
|
|
thickness = 4,
|
|
|
|
|
color,
|
|
|
|
|
}) => {
|
2025-09-21 09:55:46 +00:00
|
|
|
const theme = useTheme();
|
|
|
|
|
const progress = (remaining / duration) * 100;
|
|
|
|
|
|
|
|
|
|
return (
|
2025-09-21 10:06:41 +00:00
|
|
|
<Box sx={{ position: "relative", display: "inline-flex", width: size, height: size }}>
|
2025-09-21 09:55:46 +00:00
|
|
|
{/* Серый фон */}
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
border: "#9A9AAF solid 1px",
|
|
|
|
|
position: "absolute",
|
2025-09-21 10:06:41 +00:00
|
|
|
height: `${size - 4}px`,
|
|
|
|
|
width: `${size - 4}px`,
|
2025-09-21 09:55:46 +00:00
|
|
|
borderRadius: "100%",
|
|
|
|
|
top: "2px",
|
|
|
|
|
left: "2px",
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
{/* Основной прогресс */}
|
|
|
|
|
<StyledCircularProgress
|
|
|
|
|
variant="determinate"
|
|
|
|
|
value={progress}
|
2025-09-21 10:06:41 +00:00
|
|
|
size={size}
|
|
|
|
|
thickness={thickness}
|
2025-09-21 09:55:46 +00:00
|
|
|
sx={{
|
2025-09-21 10:06:41 +00:00
|
|
|
color: color || "linear-gradient(135deg, #FC712F 0%, #7E2AEA 100%)",
|
2025-09-21 09:55:46 +00:00
|
|
|
position: "absolute",
|
|
|
|
|
|
|
|
|
|
"& .MuiCircularProgress-circle": {
|
|
|
|
|
strokeLinecap: "round",
|
2025-09-21 10:06:41 +00:00
|
|
|
stroke: color ? undefined : "url(#timer-gradient)",
|
|
|
|
|
strokeDasharray: color ? undefined : undefined,
|
2025-09-21 09:55:46 +00:00
|
|
|
},
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<svg
|
|
|
|
|
width={0}
|
|
|
|
|
height={0}
|
|
|
|
|
>
|
|
|
|
|
<defs>
|
|
|
|
|
<linearGradient
|
|
|
|
|
id="timer-gradient"
|
|
|
|
|
x1="0%"
|
|
|
|
|
y1="0%"
|
|
|
|
|
x2="100%"
|
|
|
|
|
y2="100%"
|
|
|
|
|
>
|
|
|
|
|
<stop
|
|
|
|
|
offset="9.9%"
|
|
|
|
|
stopColor="#FC712F"
|
|
|
|
|
/>
|
|
|
|
|
<stop
|
|
|
|
|
offset="73.88%"
|
|
|
|
|
stopColor="#7E2AEA"
|
|
|
|
|
/>
|
|
|
|
|
</linearGradient>
|
|
|
|
|
</defs>
|
|
|
|
|
</svg>
|
|
|
|
|
|
|
|
|
|
{/* Центральный контент */}
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
position: "absolute",
|
|
|
|
|
top: "50%",
|
|
|
|
|
left: "50%",
|
|
|
|
|
transform: "translate(-50%, -50%)",
|
2025-09-21 10:06:41 +00:00
|
|
|
width: `${size - 20}px`,
|
|
|
|
|
height: `${size - 20}px`,
|
2025-09-21 09:55:46 +00:00
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
justifyContent: "center",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Typography
|
|
|
|
|
variant="body1"
|
|
|
|
|
fontWeight="bold"
|
|
|
|
|
sx={{
|
2025-09-21 10:06:41 +00:00
|
|
|
fontSize: size > 60 ? "16px" : "12px",
|
|
|
|
|
fontWeight: 600,
|
2025-09-21 09:55:46 +00:00
|
|
|
color: theme.palette.text.primary,
|
2025-09-21 10:06:41 +00:00
|
|
|
textAlign: "center",
|
|
|
|
|
lineHeight: 1,
|
2025-09-21 09:55:46 +00:00
|
|
|
}}
|
|
|
|
|
>
|
2025-09-21 10:06:41 +00:00
|
|
|
{showTime ? formatTime(remaining) : remaining}
|
2025-09-21 09:55:46 +00:00
|
|
|
</Typography>
|
|
|
|
|
</Box>
|
|
|
|
|
</Box>
|
|
|
|
|
);
|
|
|
|
|
};
|