SPB Git forge
2commits 1branches 0releases
492.0 KBsize
maindefault branch
2 h agolast push
TypeScript 96.1% CSS 3.1% JavaScript 0.8%
3.8 KB · 88 lines tsx
Raw Blame History
1"use client";23import type { NASMetrics } from "@/lib/nas";45function fmt(bytes: number): string {6  const gb = bytes / (1024 * 1024 * 1024);7  if (gb >= 1024) return `${(gb / 1024).toFixed(2)} TB`;8  if (gb >= 1) return `${gb.toFixed(0)} GB`;9  return `${(bytes / (1024 * 1024)).toFixed(0)} MB`;10}1112export default function NASCard({ nas }: { nas: NASMetrics }) {13  const pct = Math.min(Math.max(nas.usedPercent ?? 0, 0), 100);14  const online = nas.online ?? false;15  const color = pct >= 90 ? "#ef4444" : pct >= 75 ? "#f59e0b" : "#22c55e";1617  const r = 42, c = 2 * Math.PI * r;18  const dash = (pct / 100) * c;1920  return (21    <div className="glass glass-hover rounded-2xl p-5 fade-in">22      <div className="flex items-center justify-between mb-4">23        <div className="flex items-center gap-3">24          <div className="text-orange-500"><DriveIcon /></div>25          <div>26            <div className="flex items-center gap-2">27              <h3 className="text-sm font-bold text-zinc-900">{nas.name}</h3>28              <span className={`h-2 w-2 rounded-full ${online ? "bg-green-500" : "bg-red-500"}`}29                    style={online ? { boxShadow: "0 0 8px #22c55e88" } : {}} />30            </div>31            <div className="text-xs text-zinc-500">{nas.model} · {nas.host}</div>32          </div>33        </div>34        <a href={nas.webUrl} target="_blank" rel="noreferrer"35           className="text-xs font-medium bg-white/70 border border-zinc-200 text-zinc-700 px-3 py-1.5 rounded-lg hover:bg-white hover:border-violet-300 transition">36          Open UGOS37        </a>38      </div>3940      <div className="flex items-center gap-6">41        <div className="relative shrink-0" style={{ width: 110, height: 110 }}>42          <svg width="110" height="110" viewBox="0 0 110 110">43            <circle cx="55" cy="55" r={r} fill="none" stroke={color} strokeOpacity="0.15" strokeWidth="10" />44            <circle cx="55" cy="55" r={r} fill="none" stroke={color} strokeWidth="10" strokeLinecap="round"45                    strokeDasharray={`${dash} ${c}`} transform="rotate(-90 55 55)"46                    style={{ transition: "stroke-dasharray .5s ease" }} />47          </svg>48          <div className="absolute inset-0 flex flex-col items-center justify-center">49            <span className="text-2xl font-bold tabular-nums text-zinc-900">{Math.round(pct)}%</span>50            <span className="text-[10px] text-zinc-500">used</span>51          </div>52        </div>5354        <div className="grid grid-cols-2 gap-x-6 gap-y-3 flex-1">55          <Stat label="Used" value={fmt(nas.usedBytes)} accent={color} />56          <Stat label="Free" value={fmt(nas.availBytes)} accent="#16a34a" />57          <Stat label="Capacity" value={fmt(nas.totalBytes)} accent="#2563eb" />58          <Stat label="Mounted on" value={`${nas.mountedNodes}/${nas.totalNodes}`}59                accent={nas.mountedNodes === nas.totalNodes && online ? "#16a34a" : "#d97706"} />60        </div>61      </div>6263      <div className="mt-4 pt-3 border-t border-zinc-200/70 flex flex-wrap gap-x-6 gap-y-1 text-xs text-zinc-500">64        <span>Share: <span className="text-zinc-700 font-medium">{nas.share}</span></span>65        <span>OS: <span className="text-zinc-700 font-medium">UGOS Pro</span></span>66      </div>67    </div>68  );69}7071function Stat({ label, value, accent }: { label: string; value: string; accent: string }) {72  return (73    <div>74      <div className="text-xs text-zinc-500">{label}</div>75      <div className="text-lg font-bold tabular-nums text-zinc-900" style={{ color: accent }}>{value}</div>76    </div>77  );78}7980const DriveIcon = () => (81  <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor"82       strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">83    <rect x="3" y="4" width="18" height="16" rx="2" />84    <path d="M7 8h10M7 12h10" />85    <circle cx="8" cy="16" r="1" />86  </svg>87);88