Energy Meter
thegridcn/energy-meterFreeComponent
thegridcn publishes no description for this item.
Install it
npx shadcn@latest add https://thegridcn.com/r/energy-meter.jsonSource
1"use client";23import * as React from "react";4import { cn } from "@/lib/utils";56interface EnergyMeterProps extends React.HTMLAttributes<HTMLDivElement> {7 label?: string;8 orientation?: "horizontal" | "vertical";9 segments?: number;10 showValue?: boolean;11 value: number;12}1314function getVariant(value: number) {15 if (value < 30) {16 return "critical";17 }18 if (value <= 60) {19 return "warning";20 }21 return "primary";22}2324const variantColors = {25 critical: {26 filled: "bg-red-500 shadow-[0_0_8px_rgba(239,68,68,0.6)]",27 text: "text-red-500",28 },29 primary: {30 filled: "bg-primary shadow-[0_0_8px_var(--primary)]",31 text: "text-primary",32 },33 warning: {34 filled: "bg-amber-500 shadow-[0_0_8px_rgba(245,158,11,0.6)]",35 text: "text-amber-500",36 },37};3839export function EnergyMeter({40 value,41 segments = 10,42 label,43 orientation = "horizontal",44 showValue = false,45 className,46 ...props47}: EnergyMeterProps) {48 const clamped = Math.max(0, Math.min(100, value));49 const filledCount = Math.round((clamped / 100) * segments);50 const variant = getVariant(clamped);51 const colors = variantColors[variant];52 const isVertical = orientation === "vertical";5354 // Staggered segment fill animation55 const [visibleCount, setVisibleCount] = React.useState(0);5657 React.useEffect(() => {58 if (filledCount === 0) {59 setVisibleCount(0);60 return;61 }62 let current = 0;63 const interval = setInterval(() => {64 current++;65 setVisibleCount(current);66 if (current >= filledCount) {67 clearInterval(interval);68 }69 }, 60);70 return () => clearInterval(interval);71 }, [filledCount]);7273 // Animate counter74 const [displayPercent, setDisplayPercent] = React.useState(0);75 React.useEffect(() => {76 const duration = filledCount * 60 + 100;77 const start = performance.now();78 function tick(now: number) {79 const progress = Math.min((now - start) / duration, 1);80 const eased = 1 - (1 - progress) ** 3;81 setDisplayPercent(Math.round(clamped * eased));82 if (progress < 1) {83 requestAnimationFrame(tick);84 }85 }86 requestAnimationFrame(tick);87 }, [clamped, filledCount]);8889 return (90 <div91 data-slot="tron-energy-meter"92 className={cn(93 "relative overflow-hidden rounded border border-primary/30 bg-card/80 p-3 backdrop-blur-sm",94 className95 )}96 {...props}97 >98 {/* Scanline overlay */}99// … truncated
Files it writes
More from thegridcn
All 139 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | thegridcn | Components | Free | 2 deps | |
| Agent Avataragent-avatar | thegridcn | Components | Free | no deps | |
| Alertalert | thegridcn | Components | Free | 1 dep | |
| Alert Dialogalert-dialog | thegridcn | Components | Free | 1 dep | |
| Announcement Barannouncement-bar | thegridcn | Components | Free | no deps | |
| Anomaly Banneranomaly-banner | thegridcn | Components | Free | no deps | |
| Arrival Panelarrival-panel | thegridcn | Components | Free | no deps | |
| Aspect Ratioaspect-ratio | thegridcn | Components | Free | 1 dep |
