PrintCal / src /components /Navbar.tsx
phucsd's picture
style: refine and simplify UI, adopt spacious 2-column layout and chip-based finishing selector
160531a
Raw History Blame Contribute Delete
5.12 kB
'use client';
import React from 'react';
import {
Printer,
Calculator,
ClipboardList,
FileSpreadsheet,
Cpu,
Scissors,
Users,
Settings,
Sparkles,
} from 'lucide-react';
export type ActiveTab =
| 'calculator'
| 'orders'
| 'papers'
| 'machines'
| 'finishing'
| 'customers'
| 'settings';
interface NavbarProps {
activeTab: ActiveTab;
setActiveTab: (tab: ActiveTab) => void;
orderCount?: number;
}
export const Navbar: React.FC<NavbarProps> = ({
activeTab,
setActiveTab,
orderCount = 0,
}) => {
const navItems = [
{ id: 'calculator', label: 'Tính Giá In', icon: Calculator, badge: null },
{ id: 'orders', label: 'Đơn Hàng & Báo Giá', icon: ClipboardList, badge: orderCount > 0 ? orderCount : null },
{ id: 'papers', label: 'Kho Giá Giấy', icon: FileSpreadsheet, badge: null },
{ id: 'machines', label: 'Bảng Giá In Máy', icon: Cpu, badge: null },
{ id: 'finishing', label: 'Gia Công Sau In', icon: Scissors, badge: null },
{ id: 'customers', label: 'Khách Hàng', icon: Users, badge: null },
{ id: 'settings', label: 'Cài Đặt', icon: Settings, badge: null },
] as const;
return (
<header className="bg-slate-900 border-b border-slate-800 text-white sticky top-0 z-40 shadow-md">
<div className="max-w-7xl mx-auto px-4 sm:px-6">
<div className="flex items-center justify-between h-16">
{/* Logo & Brand */}
<div className="flex items-center gap-3 cursor-pointer" onClick={() => setActiveTab('calculator')}>
<div className="w-10 h-10 rounded-xl bg-gradient-to-tr from-blue-600 via-indigo-600 to-cyan-400 flex items-center justify-center shadow-lg shadow-blue-500/30">
<Printer className="w-5 h-5 text-white" />
</div>
<div>
<div className="flex items-center gap-1.5">
<span className="font-black text-lg tracking-wider text-white">PrintCal</span>
<span className="text-[10px] uppercase font-bold tracking-widest px-1.5 py-0.5 rounded bg-blue-500/20 text-blue-400 border border-blue-500/30 flex items-center gap-1">
<Sparkles className="w-2.5 h-2.5" /> ERP Pro
</span>
</div>
<p className="text-[11px] text-slate-400 hidden sm:block">Tính Giá In Offset & In Nhanh Thông Minh</p>
</div>
</div>
{/* Navigation Links */}
<nav className="hidden lg:flex items-center gap-1">
{navItems.map((item) => {
const Icon = item.icon;
const isActive = activeTab === item.id;
return (
<button
key={item.id}
onClick={() => setActiveTab(item.id as ActiveTab)}
className={`flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium transition-all ${
isActive
? 'bg-blue-600 text-white shadow-sm font-semibold'
: 'text-slate-300 hover:text-white hover:bg-slate-800/80'
}`}
>
<Icon className="w-4 h-4" />
<span>{item.label}</span>
{item.badge !== null && (
<span className="px-1.5 py-0.2 bg-rose-500 text-white text-[10px] font-bold rounded-full">
{item.badge}
</span>
)}
</button>
);
})}
</nav>
<div className="flex items-center gap-2 text-xs">
<div className="hidden sm:flex items-center gap-1.5 px-2.5 py-1 bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 rounded-full font-medium text-[11px]">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse" />
<span>Sẵn sàng</span>
</div>
</div>
</div>
{/* Mobile menu tab bar */}
<div className="lg:hidden flex items-center gap-1 overflow-x-auto py-2 border-t border-slate-800/80 text-xs no-scrollbar">
{navItems.map((item) => {
const Icon = item.icon;
const isActive = activeTab === item.id;
return (
<button
key={item.id}
onClick={() => setActiveTab(item.id as ActiveTab)}
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-lg whitespace-nowrap text-xs transition-colors shrink-0 ${
isActive
? 'bg-blue-600 text-white font-medium'
: 'text-slate-300 hover:text-white hover:bg-slate-800'
}`}
>
<Icon className="w-3.5 h-3.5" />
<span>{item.label}</span>
{item.badge !== null && (
<span className="px-1 bg-rose-500 text-white text-[9px] font-bold rounded-full">
{item.badge}
</span>
)}
</button>
);
})}
</div>
</div>
</header>
);
};