redesign: proper globals.css, new Sidebar, DashboardHeader with clock
All checks were successful
Build & Deploy Dashboard / deploy (push) Successful in 1m0s

This commit is contained in:
Cosmo
2026-04-16 09:18:11 +00:00
parent 254ecbfd14
commit 3cca22519e
3 changed files with 48 additions and 102 deletions

View File

@@ -4,90 +4,37 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
@layer base { body {
:root { background-color: #080810;
--background: 240 10% 4%; font-family: 'Inter', system-ui, sans-serif;
--foreground: 210 40% 98%; color: #f1f5f9;
--card: 240 10% 4%;
--card-foreground: 210 40% 98%;
--border: 240 6% 12%;
--input: 240 6% 12%;
--primary: 210 40% 98%;
--primary-foreground: 240 10% 4%;
--secondary: 240 6% 10%;
--secondary-foreground: 210 40% 98%;
--muted: 240 6% 9%;
--muted-foreground: 215 16% 47%;
--accent: 240 6% 12%;
--accent-foreground: 210 40% 98%;
--destructive: 0 63% 31%;
--destructive-foreground: 210 40% 98%;
--ring: 240 6% 12%;
--radius: 0.75rem;
}
} }
@layer base {
* { @apply border-border; }
body {
background-color: #080810;
font-family: 'Inter', system-ui, sans-serif;
color: #f1f5f9;
min-height: 100vh;
}
}
/* Scrollbar */
::-webkit-scrollbar { width: 4px; height: 4px; } ::-webkit-scrollbar { width: 4px; height: 4px; }
::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(99,102,241,0.3); border-radius: 2px; } ::-webkit-scrollbar-thumb { background: rgba(99,102,241,0.3); border-radius: 2px; }
::-webkit-scrollbar-thumb:hover { background: rgba(99,102,241,0.5); } ::-webkit-scrollbar-thumb:hover { background: rgba(99,102,241,0.5); }
/* Card base */
.card { .card {
background: rgba(255,255,255,0.03); background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.07); border: 1px solid rgba(255,255,255,0.07);
border-radius: 20px; border-radius: 20px;
transition: all 0.25s ease; transition: all 0.2s ease;
} }
.card:hover { .card:hover {
background: rgba(255,255,255,0.05); background: rgba(255,255,255,0.05);
border-color: rgba(255,255,255,0.12); border-color: rgba(255,255,255,0.12);
transform: translateY(-1px); transform: translateY(-1px);
box-shadow: 0 20px 60px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.05);
}
/* Legacy compat */
.glass-card {
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.07);
border-radius: 20px;
backdrop-filter: blur(10px);
transition: all 0.25s ease;
}
.glass-card:hover {
background: rgba(255,255,255,0.05);
border-color: rgba(255,255,255,0.12);
box-shadow: 0 20px 60px rgba(0,0,0,0.5); box-shadow: 0 20px 60px rgba(0,0,0,0.5);
} }
/* Accent borders — short names */ .card-blue { border-top: 2px solid #3b82f6 !important; }
.card-blue { border-top: 2px solid #3b82f6; } .card-violet { border-top: 2px solid #8b5cf6 !important; }
.card-violet { border-top: 2px solid #8b5cf6; } .card-emerald { border-top: 2px solid #10b981 !important; }
.card-emerald { border-top: 2px solid #10b981; } .card-amber { border-top: 2px solid #f59e0b !important; }
.card-amber { border-top: 2px solid #f59e0b; } .card-cyan { border-top: 2px solid #06b6d4 !important; }
.card-cyan { border-top: 2px solid #06b6d4; } .card-rose { border-top: 2px solid #f43f5e !important; }
.card-rose { border-top: 2px solid #f43f5e; }
/* Legacy accent names */
.card-accent-blue { border-top: 2px solid #3b82f6; }
.card-accent-violet { border-top: 2px solid #8b5cf6; }
.card-accent-emerald { border-top: 2px solid #10b981; }
.card-accent-amber { border-top: 2px solid #f59e0b; }
.card-accent-cyan { border-top: 2px solid #06b6d4; }
.card-accent-rose { border-top: 2px solid #f43f5e; }
/* Gradient text */
.gradient-text { .gradient-text {
background: linear-gradient(135deg, #818cf8, #c084fc); background: linear-gradient(135deg, #818cf8, #c084fc);
-webkit-background-clip: text; -webkit-background-clip: text;
@@ -95,24 +42,14 @@
background-clip: text; background-clip: text;
} }
/* Status indicators */
.status-online { background: #10b981; box-shadow: 0 0 6px rgba(16,185,129,0.5); }
.status-offline { background: #ef4444; box-shadow: 0 0 6px rgba(239,68,68,0.5); }
.status-checking { background: #6b7280; }
/* Pulsing status */
@keyframes ping-slow { @keyframes ping-slow {
0%, 100% { opacity: 0.8; transform: scale(1); } 0%, 100% { opacity: 0.8; transform: scale(1); }
50% { opacity: 0.3; transform: scale(1.5); } 50% { opacity: 0.2; transform: scale(1.8); }
} }
.ping-slow { animation: ping-slow 2s ease-in-out infinite; } .ping-slow { animation: ping-slow 2s ease-in-out infinite; }
/* Glow effects */ .glass-card {
.glow-violet { box-shadow: 0 0 40px rgba(139,92,246,0.15); } background: rgba(255,255,255,0.03);
.glow-blue { box-shadow: 0 0 40px rgba(59,130,246,0.15); } border: 1px solid rgba(255,255,255,0.07);
border-radius: 20px;
/* Sidebar */
.sidebar {
background: #0a0a14;
border-right: 1px solid rgba(255,255,255,0.05);
} }

View File

@@ -1,7 +1,7 @@
"use client"; "use client";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
import { signOut, useSession } from "next-auth/react"; import { signOut } from "next-auth/react";
import { LayoutDashboard, Monitor, Bookmark, LogOut, Home } from "lucide-react"; import { LayoutDashboard, Monitor, Bookmark, LogOut, Home } from "lucide-react";
const NAV = [ const NAV = [
@@ -12,19 +12,19 @@ const NAV = [
export function Sidebar() { export function Sidebar() {
const pathname = usePathname(); const pathname = usePathname();
const { data: session } = useSession();
return ( return (
<aside className="w-[220px] flex-shrink-0 flex flex-col h-screen bg-[#0a0a14] border-r border-white/5"> <aside className="w-[220px] flex-shrink-0 flex flex-col h-screen" style={{ background: "#0a0a14", borderRight: "1px solid rgba(255,255,255,0.05)" }}>
{/* Logo */} {/* Logo */}
<div className="px-5 py-6 border-b border-white/5"> <div className="px-5 py-6" style={{ borderBottom: "1px solid rgba(255,255,255,0.05)" }}>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="w-9 h-9 rounded-xl bg-gradient-to-br from-indigo-500 to-violet-600 flex items-center justify-center shadow-lg shadow-indigo-500/20"> <div className="w-9 h-9 rounded-xl flex items-center justify-center shadow-lg"
style={{ background: "linear-gradient(135deg,#6366f1,#8b5cf6)", boxShadow: "0 4px 20px rgba(99,102,241,0.3)" }}>
<Home className="w-4 h-4 text-white" /> <Home className="w-4 h-4 text-white" />
</div> </div>
<div> <div>
<div className="text-sm font-bold text-white">Digital Home</div> <div className="text-sm font-bold text-white">Digital Home</div>
<div className="text-[10px] text-slate-500">Dashboard</div> <div className="text-[10px]" style={{ color: "#475569" }}>Dashboard</div>
</div> </div>
</div> </div>
</div> </div>
@@ -37,13 +37,19 @@ export function Sidebar() {
<Link <Link
key={href} key={href}
href={href} href={href}
className={`flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm font-medium transition-all ${ className="flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm font-medium transition-all"
active style={active ? {
? "bg-indigo-500/15 text-indigo-300 border border-indigo-500/20" background: "rgba(99,102,241,0.15)",
: "text-slate-500 hover:text-slate-300 hover:bg-white/5 border border-transparent" color: "#a5b4fc",
}`} border: "1px solid rgba(99,102,241,0.25)",
} : {
color: "#475569",
border: "1px solid transparent",
}}
onMouseEnter={e => { if (!active) { (e.currentTarget as HTMLElement).style.color = "#94a3b8"; (e.currentTarget as HTMLElement).style.background = "rgba(255,255,255,0.04)"; } }}
onMouseLeave={e => { if (!active) { (e.currentTarget as HTMLElement).style.color = "#475569"; (e.currentTarget as HTMLElement).style.background = "transparent"; } }}
> >
<Icon className={`w-4 h-4 ${active ? "text-indigo-400" : ""}`} /> <Icon className="w-4 h-4" style={{ color: active ? "#818cf8" : "inherit" }} />
{label} {label}
</Link> </Link>
); );
@@ -51,19 +57,22 @@ export function Sidebar() {
</nav> </nav>
{/* User */} {/* User */}
<div className="px-3 py-4 border-t border-white/5"> <div className="px-3 py-4" style={{ borderTop: "1px solid rgba(255,255,255,0.05)" }}>
<div className="flex items-center gap-3 px-3 py-2 rounded-xl" style={{ background: "rgba(255,255,255,0.03)" }}> <div className="flex items-center gap-3 px-3 py-2 rounded-xl" style={{ background: "rgba(255,255,255,0.03)" }}>
<div className="w-8 h-8 rounded-full bg-gradient-to-br from-indigo-500 to-violet-600 flex items-center justify-center text-xs font-bold text-white flex-shrink-0"> <div className="w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold text-white flex-shrink-0"
style={{ background: "linear-gradient(135deg,#6366f1,#8b5cf6)" }}>
D D
</div> </div>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="text-xs font-medium text-slate-300 truncate">{session?.user?.name ?? "Daniil"}</div> <div className="text-xs font-medium truncate" style={{ color: "#cbd5e1" }}>Daniil</div>
<div className="text-[10px] text-slate-600 truncate">Admin</div> <div className="text-[10px] truncate" style={{ color: "#334155" }}>Admin</div>
</div> </div>
<button <button
onClick={() => signOut({ callbackUrl: "/auth/signin" })} onClick={() => signOut({ callbackUrl: "/auth/signin" })}
className="text-slate-600 hover:text-red-400 transition-colors"
title="Выйти" title="Выйти"
style={{ color: "#334155" }}
onMouseEnter={e => (e.currentTarget.style.color = "#f87171")}
onMouseLeave={e => (e.currentTarget.style.color = "#334155")}
> >
<LogOut className="w-3.5 h-3.5" /> <LogOut className="w-3.5 h-3.5" />
</button> </button>

View File

@@ -11,16 +11,16 @@ export function DashboardHeader() {
return () => clearInterval(i); return () => clearInterval(i);
}, []); }, []);
const hour = now.getHours(); const h = now.getHours();
const greeting = hour < 6 ? "Доброй ночи" : hour < 12 ? "Доброе утро" : hour < 17 ? "Добрый день" : "Добрый вечер"; const greeting = h < 6 ? "Доброй ночи" : h < 12 ? "Доброе утро" : h < 17 ? "Добрый день" : "Добрый вечер";
return ( return (
<div className="flex items-start justify-between pt-1"> <div className="flex items-start justify-between pt-1 pb-2">
<div> <div>
<h1 className="text-2xl font-bold text-white"> <h1 className="text-2xl font-bold text-white">
{greeting}, <span className="gradient-text">Daniil</span> 👋 {greeting}, <span className="gradient-text">Daniil</span> 👋
</h1> </h1>
<p className="text-slate-500 text-sm mt-0.5"> <p className="text-sm mt-0.5" style={{ color: "#475569" }}>
{DAYS[now.getDay()]}, {now.getDate()} {MONTHS[now.getMonth()]} {now.getFullYear()} {DAYS[now.getDay()]}, {now.getDate()} {MONTHS[now.getMonth()]} {now.getFullYear()}
</p> </p>
</div> </div>
@@ -28,8 +28,8 @@ export function DashboardHeader() {
<div className="text-2xl font-light text-white tabular-nums"> <div className="text-2xl font-light text-white tabular-nums">
{now.toLocaleTimeString("ru-RU", { hour: "2-digit", minute: "2-digit" })} {now.toLocaleTimeString("ru-RU", { hour: "2-digit", minute: "2-digit" })}
</div> </div>
<div className="text-xs text-slate-600"> <div className="text-xs tabular-nums" style={{ color: "#334155" }}>
{now.toLocaleTimeString("ru-RU", { second: "2-digit" })} сек {String(now.getSeconds()).padStart(2,"0")} сек
</div> </div>
</div> </div>
</div> </div>