style: Switch from slate (blue) to zinc (neutral) for dark mode
Some checks are pending
Test / backend-test (push) Waiting to run
Test / frontend-test (push) Waiting to run

This commit is contained in:
fullsizemalt 2026-01-06 13:26:02 -08:00
parent ad875443ed
commit 469286deac
3 changed files with 87 additions and 87 deletions

View file

@ -78,8 +78,8 @@ export function PulseSensorCard({ reading, history, thresholds, onClick }: Pulse
onClick={handleClick}
className={cn(
"group relative overflow-hidden rounded-2xl cursor-pointer transition-all",
"bg-white dark:bg-gradient-to-br dark:from-slate-800/80 dark:to-slate-900/80",
"border border-slate-200 dark:border-slate-700/50 hover:border-emerald-500/50",
"bg-white dark:bg-zinc-900/80",
"border border-gray-200 dark:border-zinc-700/50 hover:border-emerald-500/50",
"shadow-sm dark:shadow-xl hover:shadow-md dark:hover:shadow-2xl hover:shadow-emerald-500/10"
)}
>
@ -90,7 +90,7 @@ export function PulseSensorCard({ reading, history, thresholds, onClick }: Pulse
<div className={cn(
"p-3 rounded-xl",
isOffline
? "bg-slate-100 dark:bg-slate-700 text-slate-500 dark:text-slate-400"
? "bg-gray-100 dark:bg-zinc-800 text-gray-500 dark:text-zinc-500"
: isTempWarning || isVpdWarning
? "bg-amber-100 dark:bg-amber-500/20 text-amber-600 dark:text-amber-400"
: "bg-emerald-100 dark:bg-emerald-500/20 text-emerald-600 dark:text-emerald-400"
@ -149,7 +149,7 @@ export function PulseSensorCard({ reading, history, thresholds, onClick }: Pulse
isTempWarning ? "bg-amber-50 dark:bg-amber-500/10" : "bg-slate-50 dark:bg-slate-800/50"
)}>
<div className="flex items-center justify-between mb-1">
<div className="flex items-center gap-1.5 text-slate-500 dark:text-slate-400">
<div className="flex items-center gap-1.5 text-gray-500 dark:text-zinc-400">
<Thermometer size={14} />
<span className="text-[10px] font-bold uppercase tracking-wider">Temp</span>
</div>
@ -157,21 +157,21 @@ export function PulseSensorCard({ reading, history, thresholds, onClick }: Pulse
</div>
<p className={cn(
"text-2xl font-bold",
isOffline ? "text-slate-400 dark:text-slate-500" : isTempWarning ? "text-amber-600 dark:text-amber-400" : "text-slate-900 dark:text-white"
isOffline ? "text-gray-400 dark:text-zinc-600" : isTempWarning ? "text-amber-600 dark:text-amber-400" : "text-gray-900 dark:text-white"
)}>
{reading.temperature.toFixed(1)}°
</p>
</div>
{/* Humidity */}
<div className="p-3 rounded-xl bg-slate-50 dark:bg-slate-800/50">
<div className="flex items-center gap-1.5 mb-1 text-slate-500 dark:text-slate-400">
<div className="p-3 rounded-xl bg-gray-50 dark:bg-zinc-800/50">
<div className="flex items-center gap-1.5 mb-1 text-gray-500 dark:text-zinc-400">
<Droplets size={14} />
<span className="text-[10px] font-bold uppercase tracking-wider">RH</span>
</div>
<p className={cn(
"text-2xl font-bold",
isOffline ? "text-slate-400 dark:text-slate-500" : "text-blue-600 dark:text-blue-400"
isOffline ? "text-gray-400 dark:text-zinc-600" : "text-blue-600 dark:text-blue-400"
)}>
{reading.humidity.toFixed(0)}%
</p>
@ -180,15 +180,15 @@ export function PulseSensorCard({ reading, history, thresholds, onClick }: Pulse
{/* VPD */}
<div className={cn(
"p-3 rounded-xl transition-colors",
isVpdWarning ? "bg-purple-50 dark:bg-purple-500/10" : "bg-slate-50 dark:bg-slate-800/50"
isVpdWarning ? "bg-purple-50 dark:bg-purple-500/10" : "bg-gray-50 dark:bg-zinc-800/50"
)}>
<div className="flex items-center gap-1.5 mb-1 text-slate-500 dark:text-slate-400">
<div className="flex items-center gap-1.5 mb-1 text-gray-500 dark:text-zinc-400">
<CloudFog size={14} />
<span className="text-[10px] font-bold uppercase tracking-wider">VPD</span>
</div>
<p className={cn(
"text-2xl font-bold",
isOffline ? "text-slate-400 dark:text-slate-500" : isVpdWarning ? "text-purple-600 dark:text-purple-400" : "text-emerald-600 dark:text-emerald-400"
isOffline ? "text-gray-400 dark:text-zinc-600" : isVpdWarning ? "text-purple-600 dark:text-purple-400" : "text-emerald-600 dark:text-emerald-400"
)}>
{reading.vpd.toFixed(2)}
</p>
@ -197,11 +197,11 @@ export function PulseSensorCard({ reading, history, thresholds, onClick }: Pulse
{/* Dewpoint Row */}
<div className="mt-3 flex items-center justify-between px-1">
<div className="flex items-center gap-2 text-slate-500 dark:text-slate-500">
<div className="flex items-center gap-2 text-gray-500 dark:text-zinc-500">
<Wind size={12} />
<span className="text-xs">Dewpoint: <span className="text-slate-700 dark:text-slate-300">{reading.dewpoint.toFixed(1)}°F</span></span>
<span className="text-xs">Dewpoint: <span className="text-gray-700 dark:text-zinc-300">{reading.dewpoint.toFixed(1)}°F</span></span>
</div>
<div className="flex items-center gap-1 text-slate-400 dark:text-slate-500 group-hover:text-emerald-500 group-hover:dark:text-emerald-400 transition-colors">
<div className="flex items-center gap-1 text-gray-400 dark:text-zinc-500 group-hover:text-emerald-500 group-hover:dark:text-emerald-400 transition-colors">
<span className="text-xs font-medium">View Details</span>
<ChevronRight size={14} className="group-hover:translate-x-0.5 transition-transform" />
</div>
@ -210,7 +210,7 @@ export function PulseSensorCard({ reading, history, thresholds, onClick }: Pulse
{/* Timestamp Footer */}
<div className="px-5 pb-4">
<div className="flex items-center justify-between text-xs text-slate-400 dark:text-slate-500 pt-3 border-t border-slate-100 dark:border-slate-700/50">
<div className="flex items-center justify-between text-xs text-gray-400 dark:text-zinc-500 pt-3 border-t border-gray-100 dark:border-zinc-700/50">
<span>Last reading</span>
<span className={isOffline ? "text-red-500 dark:text-red-400" : ""}>
{readingTime.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}

View file

@ -308,7 +308,7 @@ export default function EnvironmentReportPage() {
}
`}</style>
<div className="min-h-screen bg-slate-50 dark:bg-slate-950 p-8 transition-colors duration-300">
<div className="min-h-screen bg-gray-50 dark:bg-zinc-950 p-8 transition-colors duration-300">
<div className="max-w-5xl mx-auto">
{/* --- WEB DASHBOARD VIEW --- */}
<div className="no-print mb-8 flex items-center justify-between">
@ -383,16 +383,16 @@ export default function EnvironmentReportPage() {
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="p-5 rounded-2xl bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700/50 shadow-sm dark:shadow-none"
className="p-5 rounded-2xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 shadow-sm dark:shadow-none"
>
<div className="flex items-center gap-2 mb-2 text-slate-500 dark:text-slate-400">
<div className="flex items-center gap-2 mb-2 text-gray-500 dark:text-zinc-400">
<Thermometer className="w-5 h-5 text-red-500 dark:text-red-400" />
<span className="text-sm font-medium">Avg Temperature</span>
</div>
<p className="text-2xl md:text-3xl font-bold text-slate-900 dark:text-white">
<p className="text-2xl md:text-3xl font-bold text-gray-900 dark:text-white">
{reportData?.devices[0]?.stats.temperature.avg.toFixed(1) || '--'}°F
</p>
<p className="text-xs text-slate-500 dark:text-slate-400 mt-1">
<p className="text-xs text-slate-500 dark:text-zinc-400 mt-1">
Range: {reportData?.devices[0]?.stats.temperature.min.toFixed(1)}° {reportData?.devices[0]?.stats.temperature.max.toFixed(1)}°
</p>
</motion.div>
@ -401,16 +401,16 @@ export default function EnvironmentReportPage() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 }}
className="p-5 rounded-2xl bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700/50 shadow-sm dark:shadow-none"
className="p-5 rounded-2xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 shadow-sm dark:shadow-none"
>
<div className="flex items-center gap-2 mb-2 text-slate-500 dark:text-slate-400">
<div className="flex items-center gap-2 mb-2 text-gray-500 dark:text-zinc-400">
<Droplets className="w-5 h-5 text-blue-500 dark:text-blue-400" />
<span className="text-sm font-medium">Avg Humidity</span>
</div>
<p className="text-2xl md:text-3xl font-bold text-slate-900 dark:text-white">
{reportData?.devices[0]?.stats.humidity.avg.toFixed(0) || '--'}%
</p>
<p className="text-xs text-slate-500 dark:text-slate-400 mt-1">
<p className="text-xs text-gray-500 dark:text-zinc-400 mt-1">
Range: {reportData?.devices[0]?.stats.humidity.min.toFixed(0)}% {reportData?.devices[0]?.stats.humidity.max.toFixed(0)}%
</p>
</motion.div>
@ -419,16 +419,16 @@ export default function EnvironmentReportPage() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
className="p-5 rounded-2xl bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700/50 shadow-sm dark:shadow-none"
className="p-5 rounded-2xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 shadow-sm dark:shadow-none"
>
<div className="flex items-center gap-2 mb-2 text-slate-500 dark:text-slate-400">
<div className="flex items-center gap-2 mb-2 text-gray-500 dark:text-zinc-400">
<Wind className="w-5 h-5 text-purple-500 dark:text-purple-400" />
<span className="text-sm font-medium">Avg VPD</span>
</div>
<p className="text-2xl md:text-3xl font-bold text-slate-900 dark:text-white">
{reportData?.devices[0]?.stats.vpd.avg.toFixed(2) || '--'} kPa
</p>
<p className="text-xs text-slate-500 dark:text-slate-400 mt-1">
<p className="text-xs text-gray-500 dark:text-zinc-400 mt-1">
Range: {reportData?.devices[0]?.stats.vpd.min.toFixed(2)} {reportData?.devices[0]?.stats.vpd.max.toFixed(2)}
</p>
</motion.div>
@ -437,9 +437,9 @@ export default function EnvironmentReportPage() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3 }}
className="p-5 rounded-2xl bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700/50 shadow-sm dark:shadow-none"
className="p-5 rounded-2xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 shadow-sm dark:shadow-none"
>
<div className="flex items-center gap-2 mb-2 text-slate-500 dark:text-slate-400">
<div className="flex items-center gap-2 mb-2 text-gray-500 dark:text-zinc-400">
<AlertTriangle className="w-5 h-5 text-amber-500 dark:text-amber-400" />
<span className="text-sm font-medium">Alerts</span>
</div>
@ -506,8 +506,8 @@ export default function EnvironmentReportPage() {
</div>
</div>
<div className="p-6 rounded-2xl bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700/50 shadow-sm dark:shadow-none">
<h3 className="text-sm font-semibold text-slate-900 dark:text-white mb-4 flex items-center gap-2">
<div className="p-6 rounded-2xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 shadow-sm dark:shadow-none">
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Wind className="w-4 h-4 text-purple-500 dark:text-purple-400" />
VPD Trend
</h3>
@ -520,10 +520,10 @@ export default function EnvironmentReportPage() {
<stop offset="95%" stopColor="#a855f7" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#334155" opacity={0.3} />
<XAxis dataKey="timestamp" stroke="#64748b" fontSize={9} tickLine={false} />
<YAxis stroke="#64748b" fontSize={9} tickLine={false} domain={[0, 2]} />
<Tooltip contentStyle={{ backgroundColor: '#1e293b', border: '1px solid #334155', borderRadius: '8px' }} />
<CartesianGrid strokeDasharray="3 3" stroke="#3f3f46" opacity={0.3} />
<XAxis dataKey="timestamp" stroke="#71717a" fontSize={9} tickLine={false} />
<YAxis stroke="#71717a" fontSize={9} tickLine={false} domain={[0, 2]} />
<Tooltip contentStyle={{ backgroundColor: '#18181b', border: '1px solid #3f3f46', borderRadius: '8px' }} />
<ReferenceLine y={1.2} stroke="#f59e0b" strokeDasharray="3 3" />
<ReferenceLine y={0.8} stroke="#3b82f6" strokeDasharray="3 3" />
<Area type="monotone" dataKey="vpd" stroke="#a855f7" fill="url(#reportVpdGradient)" strokeWidth={2} />
@ -535,18 +535,18 @@ export default function EnvironmentReportPage() {
{/* Hourly Breakdown */}
{reportData?.hourlyBreakdown && reportData.hourlyBreakdown.length > 0 && (
<div className="p-6 rounded-2xl bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700/50 shadow-sm dark:shadow-none print-break">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white mb-4 flex items-center gap-2">
<div className="p-6 rounded-2xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 shadow-sm dark:shadow-none print-break">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Clock className="w-5 h-5 text-cyan-500 dark:text-cyan-400" />
Hourly Average Temperature
</h3>
<div className="h-64">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={reportData.hourlyBreakdown}>
<CartesianGrid strokeDasharray="3 3" stroke="#334155" opacity={0.3} />
<XAxis dataKey="hour" stroke="#64748b" fontSize={10} tickLine={false} />
<YAxis stroke="#64748b" fontSize={10} tickLine={false} />
<Tooltip contentStyle={{ backgroundColor: '#1e293b', border: '1px solid #334155', borderRadius: '8px' }} />
<CartesianGrid strokeDasharray="3 3" stroke="#3f3f46" opacity={0.3} />
<XAxis dataKey="hour" stroke="#71717a" fontSize={10} tickLine={false} />
<YAxis stroke="#71717a" fontSize={10} tickLine={false} />
<Tooltip contentStyle={{ backgroundColor: '#18181b', border: '1px solid #3f3f46', borderRadius: '8px' }} />
<Bar dataKey="avgTemp" fill="#10b981" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
@ -555,12 +555,12 @@ export default function EnvironmentReportPage() {
)}
{/* Device Summary Table */}
<div className="p-6 rounded-2xl bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700/50 shadow-sm dark:shadow-none">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white mb-4">Device Summary</h3>
<div className="p-6 rounded-2xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 shadow-sm dark:shadow-none">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">Device Summary</h3>
<div className="overflow-x-auto">
<table className="w-full">
<thead>
<tr className="text-left text-xs text-slate-500 dark:text-slate-400 uppercase tracking-wider">
<tr className="text-left text-xs text-gray-500 dark:text-zinc-400 uppercase tracking-wider">
<th className="pb-3">Device</th>
<th className="pb-3 text-center">Readings</th>
<th className="pb-3 text-center">Temp (Avg)</th>
@ -568,11 +568,11 @@ export default function EnvironmentReportPage() {
<th className="pb-3 text-center">VPD (Avg)</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-200 dark:divide-slate-700/50">
<tbody className="divide-y divide-gray-200 dark:divide-zinc-800">
{reportData?.devices.map(device => (
<tr key={device.id} className="text-sm">
<td className="py-3 text-slate-900 dark:text-white font-medium">{device.name}</td>
<td className="py-3 text-slate-600 dark:text-slate-300 text-center">{device.readings}</td>
<td className="py-3 text-gray-900 dark:text-white font-medium">{device.name}</td>
<td className="py-3 text-gray-600 dark:text-zinc-300 text-center">{device.readings}</td>
<td className="py-3 text-center">
<span className="text-red-500 dark:text-red-400 font-medium">{device.stats.temperature.avg.toFixed(1)}°F</span>
</td>
@ -591,8 +591,8 @@ export default function EnvironmentReportPage() {
{/* Alert Summary */}
{reportData?.alerts.byType && reportData.alerts.byType.length > 0 && (
<div className="p-6 rounded-2xl bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700/50 shadow-sm dark:shadow-none">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white mb-4 flex items-center gap-2">
<div className="p-6 rounded-2xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 shadow-sm dark:shadow-none">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<AlertTriangle className="w-5 h-5 text-amber-500 dark:text-amber-400" />
Alert Summary
</h3>
@ -898,8 +898,8 @@ export default function EnvironmentReportPage() {
{/* Recent Alerts List */}
{reportData?.alertAnalytics?.recentAlerts && reportData.alertAnalytics.recentAlerts.length > 0 ? (
<table className="w-full text-xs text-left border border-slate-200 dark:border-slate-700">
<thead className="bg-slate-800 text-white font-semibold uppercase dark:bg-slate-900">
<table className="w-full text-xs text-left border border-gray-200 dark:border-zinc-700">
<thead className="bg-gray-800 text-white font-semibold uppercase dark:bg-zinc-900">
<tr>
<th className="px-4 py-2">Time</th>
<th className="px-4 py-2">Severity</th>
@ -908,10 +908,10 @@ export default function EnvironmentReportPage() {
<th className="px-4 py-2 text-right">Duration</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-200 dark:divide-slate-700/50">
<tbody className="divide-y divide-gray-200 dark:divide-zinc-700/50">
{reportData.alertAnalytics.recentAlerts.slice(0, 15).map((alert, idx) => (
<tr key={alert.id} className={idx % 2 === 0 ? 'bg-white dark:bg-slate-800/50' : 'bg-slate-50 dark:bg-slate-800/30'}>
<td className="px-4 py-2 whitespace-nowrap text-slate-600 dark:text-slate-400">
<tr key={alert.id} className={idx % 2 === 0 ? 'bg-white dark:bg-zinc-800/30' : 'bg-gray-50 dark:bg-zinc-800/10'}>
<td className="px-4 py-2 whitespace-nowrap text-gray-600 dark:text-zinc-400">
{new Date(alert.createdAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', month: 'short', day: 'numeric' })}
</td>
<td className="px-4 py-2">
@ -922,9 +922,9 @@ export default function EnvironmentReportPage() {
{alert.severity}
</span>
</td>
<td className="px-4 py-2 font-medium text-slate-900 dark:text-white">{alert.type.replace('_', ' ')}</td>
<td className="px-4 py-2 text-slate-600 dark:text-slate-400 truncate max-w-xs">{alert.message}</td>
<td className="px-4 py-2 text-right font-mono text-slate-700 dark:text-slate-300">
<td className="px-4 py-2 font-medium text-gray-900 dark:text-white">{alert.type.replace('_', ' ')}</td>
<td className="px-4 py-2 text-gray-600 dark:text-zinc-400 truncate max-w-xs">{alert.message}</td>
<td className="px-4 py-2 text-right font-mono text-gray-700 dark:text-zinc-300">
{alert.resolutionTimeMin ? `${alert.resolutionTimeMin.toFixed(1)}m` : '-'}
</td>
</tr>
@ -932,12 +932,12 @@ export default function EnvironmentReportPage() {
</tbody>
</table>
) : (
<p className="text-slate-500 dark:text-slate-400 italic text-sm p-4 border border-slate-200 dark:border-slate-700 rounded">No recent alerts found for this period.</p>
<p className="text-gray-500 dark:text-zinc-400 italic text-sm p-4 border border-gray-200 dark:border-zinc-700 rounded">No recent alerts found for this period.</p>
)}
</div>
{/* Footer */}
<div className="mt-12 pt-6 border-t border-slate-200 text-center text-xs text-slate-400">
<div className="mt-12 pt-6 border-t border-gray-200 text-center text-xs text-gray-400">
<p>© {new Date().getFullYear()} Veridian Systems Generated via Environment Operations Manager</p>
</div>
</div>

View file

@ -129,30 +129,30 @@ export default function PulseTestPage() {
const currentReading = readings.find(r => r.deviceId === selectedDevice) || readings[0];
return (
<div className="min-h-screen bg-slate-50 dark:bg-slate-950 p-6 transition-colors duration-300">
<div className="min-h-screen bg-gray-50 dark:bg-zinc-950 p-6 transition-colors duration-300">
<div className="max-w-7xl mx-auto space-y-6">
{/* Header */}
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
<div>
<h1 className="text-3xl font-bold text-slate-900 dark:text-white flex items-center gap-3">
<h1 className="text-3xl font-bold text-gray-900 dark:text-white flex items-center gap-3">
<div className="p-2.5 rounded-xl bg-gradient-to-br from-emerald-500 to-teal-600 shadow-lg shadow-emerald-500/25 text-white">
<Activity className="w-6 h-6" />
</div>
Pulse Sensor Analytics (v2)
Pulse Sensor Analytics (v3)
</h1>
<p className="text-slate-500 dark:text-slate-400 ml-14 mt-1">
<p className="text-gray-500 dark:text-zinc-400 ml-14 mt-1">
Real-time environmental monitoring with historical trends
</p>
</div>
<div className="flex items-center gap-4">
{/* WebSocket Status */}
<div className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700 shadow-sm">
<div className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 shadow-sm">
{wsConnected ? (
<Wifi className="w-4 h-4 text-emerald-500" />
) : (
<WifiOff className="w-4 h-4 text-red-500" />
)}
<span className="text-xs font-medium text-slate-600 dark:text-slate-300">
<span className="text-xs font-medium text-gray-600 dark:text-zinc-300">
{wsConnected ? 'Live' : 'Offline'}
</span>
{unreadCount > 0 && (
@ -167,7 +167,7 @@ export default function PulseTestPage() {
<button
onClick={fetchData}
disabled={loading}
className="p-2.5 rounded-xl bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700 hover:bg-slate-50 dark:hover:bg-slate-700 transition-colors disabled:opacity-50 shadow-sm text-slate-500 dark:text-slate-400"
className="p-2.5 rounded-xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 hover:bg-gray-50 dark:hover:bg-zinc-800 transition-colors disabled:opacity-50 shadow-sm text-gray-500 dark:text-zinc-400"
>
<RefreshCw className={`w-5 h-5 ${loading ? 'animate-spin' : ''}`} />
</button>
@ -185,7 +185,7 @@ export default function PulseTestPage() {
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
{/* Live Readings Panel */}
<div className="lg:col-span-1 space-y-4">
<h2 className="text-sm font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wider">Live Sensors</h2>
<h2 className="text-sm font-semibold text-gray-500 dark:text-zinc-400 uppercase tracking-wider">Live Sensors</h2>
{readings.map((reading) => (
<motion.div
@ -194,11 +194,11 @@ export default function PulseTestPage() {
onClick={() => setSelectedDevice(reading.deviceId)}
className={`p-4 rounded-xl cursor-pointer transition-all shadow-sm ${selectedDevice === reading.deviceId
? 'bg-emerald-50 dark:bg-emerald-500/20 border-2 border-emerald-500/50'
: 'bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700/50 hover:border-slate-300 dark:hover:border-slate-600'
: 'bg-white dark:bg-zinc-900/50 border border-gray-200 dark:border-zinc-800 hover:border-gray-300 dark:hover:border-zinc-700'
}`}
>
<div className="flex items-center justify-between mb-3">
<h3 className="font-semibold text-slate-900 dark:text-white text-sm">{reading.deviceName}</h3>
<h3 className="font-semibold text-gray-900 dark:text-white text-sm">{reading.deviceName}</h3>
<div className="flex items-center gap-1.5">
<div className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
<span className="text-xs text-emerald-600 dark:text-emerald-400 font-medium">LIVE</span>
@ -207,19 +207,19 @@ export default function PulseTestPage() {
<div className="grid grid-cols-3 gap-2">
<div>
<p className="text-xs text-slate-500 dark:text-slate-400 mb-0.5">Temp</p>
<p className="text-xs text-gray-500 dark:text-zinc-400 mb-0.5">Temp</p>
<p className={`text-lg font-bold ${getTempColor(reading.temperature)}`}>
{reading.temperature.toFixed(1)}°
</p>
</div>
<div>
<p className="text-xs text-slate-500 dark:text-slate-400 mb-0.5">RH</p>
<p className="text-xs text-gray-500 dark:text-zinc-400 mb-0.5">RH</p>
<p className="text-lg font-bold text-blue-500 dark:text-blue-400">
{reading.humidity.toFixed(0)}%
</p>
</div>
<div>
<p className="text-xs text-slate-500 dark:text-slate-400 mb-0.5">VPD</p>
<p className="text-xs text-gray-500 dark:text-zinc-400 mb-0.5">VPD</p>
<p className={`text-lg font-bold ${getVpdColor(reading.vpd)}`}>
{reading.vpd.toFixed(2)}
</p>
@ -229,9 +229,9 @@ export default function PulseTestPage() {
))}
{readings.length === 0 && !loading && (
<div className="p-6 text-center rounded-xl bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700/50 shadow-sm">
<Activity className="w-8 h-8 mx-auto mb-2 text-slate-400 dark:text-slate-500" />
<p className="text-slate-500 dark:text-slate-400 text-sm">No sensors connected</p>
<div className="p-6 text-center rounded-xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 shadow-sm">
<Activity className="w-8 h-8 mx-auto mb-2 text-gray-400 dark:text-zinc-500" />
<p className="text-gray-500 dark:text-zinc-400 text-sm">No sensors connected</p>
</div>
)}
</div>
@ -244,11 +244,11 @@ export default function PulseTestPage() {
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="p-5 rounded-2xl bg-white dark:bg-slate-800/30 border border-red-100 dark:border-red-500/10 shadow-sm dark:shadow-none"
className="p-5 rounded-2xl bg-white dark:bg-zinc-900 border border-red-100 dark:border-red-500/10 shadow-sm dark:shadow-none"
>
<div className="flex items-center gap-2 mb-2">
<Thermometer className="w-5 h-5 text-red-500 dark:text-red-400" />
<span className="text-sm text-slate-500 dark:text-slate-400">Temperature</span>
<span className="text-sm text-gray-500 dark:text-zinc-400">Temperature</span>
</div>
<p className={`text-3xl lg:text-4xl font-bold ${getTempColor(currentReading.temperature)}`}>
{currentReading.temperature.toFixed(1)}°F
@ -259,11 +259,11 @@ export default function PulseTestPage() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 }}
className="p-5 rounded-2xl bg-white dark:bg-slate-800/30 border border-blue-100 dark:border-blue-500/10 shadow-sm dark:shadow-none"
className="p-5 rounded-2xl bg-white dark:bg-zinc-900 border border-blue-100 dark:border-blue-500/10 shadow-sm dark:shadow-none"
>
<div className="flex items-center gap-2 mb-2">
<Droplets className="w-5 h-5 text-blue-500 dark:text-blue-400" />
<span className="text-sm text-slate-500 dark:text-slate-400">Humidity</span>
<span className="text-sm text-gray-500 dark:text-zinc-400">Humidity</span>
</div>
<p className="text-3xl lg:text-4xl font-bold text-blue-500 dark:text-blue-400">
{currentReading.humidity.toFixed(0)}%
@ -274,27 +274,27 @@ export default function PulseTestPage() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
className="p-5 rounded-2xl bg-white dark:bg-slate-800/30 border border-purple-100 dark:border-purple-500/10 shadow-sm dark:shadow-none"
className="p-5 rounded-2xl bg-white dark:bg-zinc-900 border border-purple-100 dark:border-purple-500/10 shadow-sm dark:shadow-none"
>
<div className="flex items-center gap-2 mb-2">
<Wind className="w-5 h-5 text-purple-500 dark:text-purple-400" />
<span className="text-sm text-slate-500 dark:text-slate-400">VPD</span>
<span className="text-sm text-gray-500 dark:text-zinc-400">VPD</span>
</div>
<p className={`text-3xl lg:text-4xl font-bold ${getVpdColor(currentReading.vpd)}`}>
{currentReading.vpd.toFixed(2)}
</p>
<p className="text-xs text-slate-500 dark:text-slate-500 mt-1">kPa</p>
<p className="text-xs text-gray-500 dark:text-zinc-500 mt-1">kPa</p>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3 }}
className="p-5 rounded-2xl bg-white dark:bg-slate-800/30 border border-cyan-100 dark:border-cyan-500/10 shadow-sm dark:shadow-none"
className="p-5 rounded-2xl bg-white dark:bg-zinc-900 border border-cyan-100 dark:border-cyan-500/10 shadow-sm dark:shadow-none"
>
<div className="flex items-center gap-2 mb-2">
<Droplets className="w-5 h-5 text-cyan-500 dark:text-cyan-400" />
<span className="text-sm text-slate-500 dark:text-slate-400">Dewpoint</span>
<span className="text-sm text-gray-500 dark:text-zinc-400">Dewpoint</span>
</div>
<p className="text-3xl lg:text-4xl font-bold text-cyan-500 dark:text-cyan-400">
{currentReading.dewpoint.toFixed(1)}°F
@ -305,16 +305,16 @@ export default function PulseTestPage() {
{/* Time Range Selector */}
<div className="flex items-center justify-between pt-4">
<h2 className="text-lg font-semibold text-slate-900 dark:text-white flex items-center gap-2">
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
<TrendingUp className="w-5 h-5 text-emerald-500 dark:text-emerald-400" />
Historical Trends
</h2>
<div className="flex items-center gap-2">
<Clock className="w-4 h-4 text-slate-400" />
<Clock className="w-4 h-4 text-gray-400" />
<select
value={historyHours}
onChange={(e) => setHistoryHours(Number(e.target.value))}
className="bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg px-3 py-1.5 text-sm text-slate-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-emerald-500 shadow-sm"
className="bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 rounded-lg px-3 py-1.5 text-sm text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-emerald-500 shadow-sm"
>
<option value={1}>Last hour</option>
<option value={6}>Last 6 hours</option>
@ -326,7 +326,7 @@ export default function PulseTestPage() {
</div>
{/* Temperature Chart */}
<div className="p-6 rounded-2xl bg-white dark:bg-slate-800/50 border border-slate-200 dark:border-slate-700/50 shadow-sm">
<div className="p-6 rounded-2xl bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 shadow-sm">
<h3 className="text-sm font-medium text-slate-500 dark:text-slate-400 mb-4 flex items-center gap-2">
<Thermometer className="w-4 h-4 text-red-500 dark:text-red-400" />
Temperature History