'use client'; import React, { useEffect, useRef, useState } from 'react'; import { useMdUp } from '../../hooks'; type ProgressBarProps = { progress: number; // 0–100 warningThreshold?: number; // default 70 criticalThreshold?: number; // default 90 segmentWidth?: number; // desktop segment width (px) mobileSegmentWidth?: number; // mobile segment width (px) segmentGap?: number; // px, default 2 height?: number; // desktop height (px) mobileHeight?: number; // mobile height (px) inverted?: boolean; // if true, high values are good (green), low values are bad (red) }; export const ProgressBar: React.FC = ({ progress, warningThreshold = 75, criticalThreshold = 90, segmentWidth = 3.43, mobileSegmentWidth = 5, segmentGap = 2, height = 24, mobileHeight = 8, inverted = false, }) => { const isMdUp = useMdUp() ?? true; const effectiveSegmentWidth = isMdUp ? segmentWidth : mobileSegmentWidth; const effectiveHeight = isMdUp ? height : mobileHeight; const containerRef = useRef(null); const [segmentCount, setSegmentCount] = useState(0); useEffect(() => { if (!containerRef.current) return; const resizeObserver = new ResizeObserver(() => { if (containerRef.current) { const width = containerRef.current.offsetWidth; // N segments have only (N-1) gaps, so add one gap back before dividing — // otherwise the last segment is dropped due to a phantom trailing gap. const count = Math.floor((width + segmentGap) / (effectiveSegmentWidth + segmentGap)); setSegmentCount(count); } }); resizeObserver.observe(containerRef.current); return () => resizeObserver.disconnect(); }, [effectiveSegmentWidth, segmentGap]); // Pick color based on thresholds using ODS design tokens const getColor = () => { if (inverted) { // Inverted: high values = good (green), low values = bad (red) // For battery health: 100% = green, <30% = red if (progress >= criticalThreshold) return "var(--color-success)"; // high = green if (progress >= warningThreshold) return "var(--color-warning)"; // medium = warning return "var(--color-error)"; // low = red } else { // Normal: high values = bad (red), low values = good (green) // For disk usage: 100% = red, <70% = green if (progress >= criticalThreshold) return "var(--color-error)"; // critical red if (progress >= warningThreshold) return "var(--color-warning)"; // warning yellow return "var(--color-success)"; // base green } }; return (
{Array.from({ length: segmentCount }).map((_, i) => (
))}
); };