Gas Fee Mode Selector
Base: 30 | Next update in 3s
Speed Bike
Base: 30 | Next update in 3s
Speed Bike
"use client";
import { useEffect, useState } from "react";
type GasMode = {
id: string;
image: string;
imageClassName: string;
label: string;
priceLabel: string;
speed: string;
textColor: string;
tone: string;
};
const gasModes: GasMode[] = [
{
id: "walking",
image: "/proteus/overview/walker.png",
imageClassName: "h-[40px] w-[23px] object-contain",
label: "Walking",
priceLabel: "$1.05 | ~ 30 secs",
speed: "Low Speed",
textColor: "#E56910",
tone: "#FFF3EB",
},
{
id: "speed-bike",
image: "/proteus/overview/bike.png",
imageClassName: "h-[38px] w-[87px] object-contain",
label: "Speed Bike",
priceLabel: "$1.05 | ~ 30 secs",
speed: "Average Speed",
textColor: "#22A06B",
tone: "#DCFFF1",
},
{
id: "future-car",
image: "/proteus/overview/car.png",
imageClassName: "h-[50px] w-[101px] object-contain -mt-2",
label: "Future Car",
priceLabel: "$1.05 | ~ 30 secs",
speed: "High Speed",
textColor: "#1D7AFC",
tone: "#E9F2FF",
},
];
const gasProfile = {
base: 30,
values: {
"future-car": 34,
"speed-bike": 32,
walking: 31,
} as Record<string, number>,
};
function GasFeeModeCard({ active, gwei, mode, onSelect }) {
const speedParts = mode.speed.split(" ");
return (
<button
className={`flex items-center gap-4 rounded-[16px] px-3 py-2 text-left transition-colors ${
active ? "bg-white shadow-[0_8px_18px_rgba(0,0,0,0.08)]" : "hover:bg-white/70"
}`}
onClick={() => onSelect(mode.id)}
type="button"
>
<div className="flex flex-col items-center gap-1 text-center">
<img alt="" className={mode.imageClassName} src={mode.image} />
<div className="flex flex-col items-center gap-[2px]">
<p className="text-[16px] font-medium leading-6 text-[#374151]">{mode.label}</p>
<div className="flex items-center gap-1 text-[12px] font-medium tracking-[0.24px]">
<span style={{ color: mode.textColor }}>{speedParts[0]}</span>
<span className="text-[#374151]">{speedParts.slice(1).join(" ")}</span>
</div>
<p className="text-[10px] font-semibold leading-4 text-[#6b7280]">{mode.priceLabel}</p>
</div>
</div>
<div
className="flex h-20 w-20 flex-col items-center justify-center rounded-full pb-1"
style={{ backgroundColor: mode.tone, color: mode.textColor }}
>
<span className="text-[36px] font-medium leading-[44px]">{gwei}</span>
<span className="text-[12px] font-medium leading-4 tracking-[0.24px]">gwei</span>
</div>
</button>
);
}
export default function GasCardPage() {
const [selectedGasMode, setSelectedGasMode] = useState("speed-bike");
const [countdown, setCountdown] = useState(3);
const [gasRefreshIndex, setGasRefreshIndex] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCountdown((prev) => {
if (prev <= 1) {
setGasRefreshIndex((i) => i + 1);
return 3;
}
return prev - 1;
});
}, 1000);
return () => clearInterval(interval);
}, []);
function getGwei(modeId) {
const base = gasProfile.values[modeId] ?? gasProfile.base;
const variance = ((gasRefreshIndex + modeId.length) % 3) - 1;
return base + variance;
}
const selectedMode = gasModes.find((m) => m.id === selectedGasMode) ?? gasModes[1];
return (
<div className="proteus-panel rounded-[8px] p-4">
<div className="mb-2 flex items-center justify-between">
<div className="flex items-center gap-2">
<img alt="fuel" className="h-5 w-5" src="/proteus/overview/fuel.svg" />
<span className="text-[16px] font-semibold text-[#1f2937]">ETH Gas Fees</span>
</div>
<img alt="info" className="h-4 w-4" src="/proteus/overview/info.svg" />
</div>
<p className="mb-3 text-[12px] text-[#6b7280]">
Base: {gasProfile.base} | Next update in {countdown}s
</p>
<p className="mb-2 text-[14px] font-medium text-[#374151]">{selectedMode.label}</p>
<div className="flex items-center gap-2">
{gasModes.map((mode) => (
<GasFeeModeCard
active={selectedGasMode === mode.id}
gwei={getGwei(mode.id)}
key={mode.id}
mode={mode}
onSelect={setSelectedGasMode}
/>
))}
</div>
</div>
);
}Build a Gas Fee Mode Selector card component in Next.js with the following requirements: - Display three gas fee modes: Walking (Low Speed), Speed Bike (Average Speed), and Future Car (High Speed) - Each mode shows an icon, label, speed tier, price label, and a circular gwei badge - The selected mode is highlighted with a white background and subtle shadow - Include a countdown timer that refreshes gwei values every 3 seconds with slight variance - Show base gas price and next update countdown in a subtitle row - Use a warm, pastel color scheme: orange for Walking, green for Speed Bike, blue for Future Car - The gwei badge for each mode uses the mode's tone color as background - Panel has a fuel icon header with "ETH Gas Fees" title and an info icon - Use Tailwind CSS for all styling with rounded corners and clean typography