Add professional historian modal with realtime analytics

This commit is contained in:
litoral05
2026-05-22 17:08:22 +01:00
parent a30d41d031
commit 6277653fed
9 changed files with 1705 additions and 44 deletions
+93 -34
View File
@@ -1,4 +1,6 @@
import {
ChevronLeft,
ChevronRight,
CloudSun,
Droplet,
Home,
@@ -8,70 +10,99 @@ import {
} from "lucide-react";
import logo from "../../assets/logo.png";
import type { AppPage } from "../../app/App";
type SidebarProps = {
theme: "dark" | "light";
activePage: AppPage;
collapsed: boolean;
onNavigate: (page: AppPage) => void;
onToggleCollapsed: () => void;
};
const navigationItems = [
{ label: "Painel Principal", icon: Home, active: true },
{ label: "Meteorologia", icon: CloudSun },
const navigationItems: {
label: string;
page: AppPage;
icon: React.ElementType;
}[] = [
{ label: "Painel Principal", page: "dashboard", icon: Home },
{ label: "Meteorologia", page: "meteo", icon: CloudSun },
];
const disabledItems = [
{ label: "Consola (VNC)", icon: TabletSmartphone },
{ label: "Rega", icon: Droplet },
{ label: "Clima", icon: Wind },
{ label: "Configurações", icon: Settings },
];
export function Sidebar({ theme }: SidebarProps) {
export function Sidebar({
theme,
activePage,
collapsed,
onNavigate,
onToggleCollapsed,
}: SidebarProps) {
const isDark = theme === "dark";
return (
<aside
className={
isDark
? "flex min-h-screen w-64 flex-col bg-[#0B1620] px-4 py-5 shadow-[inset_-1px_0_0_0_rgba(80,100,120,0.25),2px_0_12px_rgba(0,0,0,0.15)]"
: "flex min-h-screen w-64 flex-col bg-[#EEF3F7] px-4 py-5 shadow-[inset_-1px_0_0_0_rgba(180,190,200,0.5)]"
? `${collapsed ? "w-20" : "w-64"} flex h-full flex-col bg-[#0B1620] px-4 py-5 shadow-[inset_-1px_0_0_0_rgba(80,100,120,0.25),2px_0_12px_rgba(0,0,0,0.15)] transition-all duration-200`
: `${collapsed ? "w-20" : "w-64"} flex h-full flex-col bg-[#EEF3F7] px-4 py-5 shadow-[inset_-1px_0_0_0_rgba(180,190,200,0.5)] transition-all duration-200`
}
>
<div className="mb-10 flex items-center gap-3 px-2">
<div
className={
collapsed
? "mb-10 flex items-center justify-center"
: "mb-10 flex items-center gap-3 px-2"
}
>
<img
src={logo}
alt="LitoralRegas"
className="h-12 w-12 shrink-0 object-contain"
/>
<div className="min-w-0">
<div
className={
isDark
? "truncate text-[16px] font-bold tracking-wide text-white"
: "truncate text-[16px] font-bold tracking-wide text-[#162434]"
}
>
LITORAL CENTRAL
</div>
{!collapsed && (
<div className="min-w-0">
<div
className={
isDark
? "truncate text-[16px] font-bold tracking-wide text-white"
: "truncate text-[16px] font-bold tracking-wide text-[#162434]"
}
>
LITORAL CENTRAL
</div>
<div
className={
isDark
? "mt-0.5 text-[10px] uppercase tracking-[0.18em] text-[#8FA3B8]"
: "mt-0.5 text-[10px] uppercase tracking-[0.18em] text-[#607284]"
}
>
OPERAÇÕES AGRÍCOLAS
<div
className={
isDark
? "mt-0.5 text-[10px] uppercase tracking-[0.18em] text-[#8FA3B8]"
: "mt-0.5 text-[10px] uppercase tracking-[0.18em] text-[#607284]"
}
>
OPERAÇÕES AGRÍCOLAS
</div>
</div>
</div>
)}
</div>
<nav className="space-y-2">
{navigationItems.map((item) => {
const Icon = item.icon;
const active = activePage === item.page;
return (
<button
key={item.label}
onClick={() => onNavigate(item.page)}
title={collapsed ? item.label : undefined}
className={
item.active
active
? isDark
? "flex w-full items-center gap-3 rounded-xl bg-[#18304B] px-4 py-3 text-left text-sm font-semibold text-white"
: "flex w-full items-center gap-3 rounded-xl bg-[#DCE8F5] px-4 py-3 text-left text-sm font-semibold text-[#162434]"
@@ -80,22 +111,50 @@ export function Sidebar({ theme }: SidebarProps) {
: "flex w-full items-center gap-3 rounded-xl px-4 py-3 text-left text-sm font-medium text-[#445569] hover:bg-[#E2E8F0] hover:text-[#162434]"
}
>
<Icon className="h-5 w-5" />
{item.label}
<Icon className="h-5 w-5 shrink-0" />
{!collapsed && <span>{item.label}</span>}
</button>
);
})}
{disabledItems.map((item) => {
const Icon = item.icon;
return (
<button
key={item.label}
disabled
title={collapsed ? item.label : undefined}
className={
isDark
? "flex w-full cursor-not-allowed items-center gap-3 rounded-xl px-4 py-3 text-left text-sm font-medium text-[#607284] opacity-60"
: "flex w-full cursor-not-allowed items-center gap-3 rounded-xl px-4 py-3 text-left text-sm font-medium text-[#8A9AAB] opacity-70"
}
>
<Icon className="h-5 w-5 shrink-0" />
{!collapsed && <span>{item.label}</span>}
</button>
);
})}
</nav>
<div
<button
onClick={onToggleCollapsed}
className={
isDark
? "mt-auto px-4 text-sm text-slate-400"
: "mt-auto px-4 text-sm text-[#607284]"
? "mt-auto flex items-center justify-center gap-2 rounded-xl px-4 py-3 text-sm text-slate-400 hover:bg-[#132434] hover:text-white"
: "mt-auto flex items-center justify-center gap-2 rounded-xl px-4 py-3 text-sm text-[#607284] hover:bg-[#E2E8F0] hover:text-[#162434]"
}
>
Recolher menu
</div>
{collapsed ? (
<ChevronRight className="h-5 w-5" />
) : (
<>
<ChevronLeft className="h-5 w-5" />
<span>Recolher menu</span>
</>
)}
</button>
</aside>
);
}