refactor(admin): compact UI styling for data-dense admin interface
- Reduce table cell padding (px-5 py-4 → px-3 py-2) across OrderTableBody, ProductTableBody, StopTableBody, AdminTable - Narrow sidebar (w-60 → w-56) with smaller nav items - Reduce page/card padding in admin-design-system.css - Smaller default buttons (md → sm) in AdminButton - Smaller page headers (text-2xl → text-xl, w-12 → w-10 icon) - Tighter cards and filter tabs Makes admin UI feel like professional B2B tool at 100% zoom
This commit is contained in:
@@ -316,7 +316,7 @@ export default function AdminSidebar({ userRole }: SidebarProps) {
|
||||
ref={sidebarRef}
|
||||
id="admin-sidebar"
|
||||
className={[
|
||||
"fixed top-0 left-0 h-full w-60 z-50",
|
||||
"fixed top-0 left-0 h-full w-56 z-50",
|
||||
"border-r flex flex-col",
|
||||
"transition-transform duration-300 ease-out lg:translate-x-0",
|
||||
mobileOpen ? "translate-x-0" : "-translate-x-full",
|
||||
@@ -408,7 +408,7 @@ export default function AdminSidebar({ userRole }: SidebarProps) {
|
||||
onClick={() => closeMobileMenu()}
|
||||
onKeyDown={(e) => handleNavKeyDown(e, item.href!, navIndex)}
|
||||
className={[
|
||||
"group flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm font-medium transition-all duration-200",
|
||||
"group flex items-center gap-2.5 px-3 py-2 rounded-lg text-xs font-medium transition-all duration-200",
|
||||
"focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--admin-sidebar-bg)]",
|
||||
active
|
||||
? "border-l-[3px]"
|
||||
|
||||
@@ -47,13 +47,13 @@ export default function OrderTableBody({ orders }: { orders: Order[] }) {
|
||||
<tbody className="divide-y divide-slate-200">
|
||||
{orders.map((order) => (
|
||||
<tr key={order.id} className="hover:bg-zinc-800">
|
||||
<td className="px-5 py-4">
|
||||
<td className="px-3 py-2">
|
||||
<span className="font-mono text-sm text-zinc-500">
|
||||
{order.id.slice(0, 8)}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4">
|
||||
<td className="px-3 py-2">
|
||||
<div className="font-medium text-zinc-100">
|
||||
{order.customer_name}
|
||||
</div>
|
||||
@@ -62,9 +62,9 @@ export default function OrderTableBody({ orders }: { orders: Order[] }) {
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4">
|
||||
<td className="px-3 py-2">
|
||||
<span
|
||||
className={`rounded-full px-3 py-1 text-xs font-medium ${
|
||||
className={`rounded-full px-2 py-0.5 text-xs font-medium ${
|
||||
statusColors[order.status] ?? "bg-zinc-950 text-zinc-400"
|
||||
}`}
|
||||
>
|
||||
@@ -72,14 +72,14 @@ export default function OrderTableBody({ orders }: { orders: Order[] }) {
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4 font-semibold text-zinc-100">
|
||||
<td className="px-3 py-2 font-semibold text-zinc-100">
|
||||
${Number(order.subtotal).toFixed(2)}
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4">
|
||||
<td className="px-3 py-2">
|
||||
<button
|
||||
onClick={() => togglePickup(order.id, pickupToggles[order.id])}
|
||||
className={`rounded-full px-3 py-1 text-xs font-medium ${
|
||||
className={`rounded-full px-2 py-0.5 text-xs font-medium ${
|
||||
pickupToggles[order.id]
|
||||
? "bg-green-900/40 text-green-400"
|
||||
: "bg-zinc-950 text-zinc-500"
|
||||
@@ -89,7 +89,7 @@ export default function OrderTableBody({ orders }: { orders: Order[] }) {
|
||||
</button>
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4 text-sm text-zinc-500">
|
||||
<td className="px-3 py-2 text-sm text-zinc-500">
|
||||
{formatDate(new Date(order.created_at))}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -122,7 +122,7 @@ export default function ProductTableBody({
|
||||
key={product.id}
|
||||
className="hover:bg-zinc-800 transition-colors relative"
|
||||
>
|
||||
<td className="px-5 py-4">
|
||||
<td className="px-3 py-2">
|
||||
<Link
|
||||
href={`/admin/products/${product.id}`}
|
||||
className="block font-medium text-zinc-100 hover:text-zinc-400"
|
||||
@@ -134,25 +134,25 @@ export default function ProductTableBody({
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4 text-zinc-300">
|
||||
<td className="px-3 py-2 text-zinc-300">
|
||||
{Array.isArray(product.brands)
|
||||
? product.brands[0]?.name
|
||||
: product.brands?.name}
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4 text-zinc-300">{product.type}</td>
|
||||
<td className="px-3 py-2 text-zinc-300">{product.type}</td>
|
||||
|
||||
<td className="px-5 py-4 font-semibold text-zinc-100">
|
||||
<td className="px-3 py-2 font-semibold text-zinc-100">
|
||||
${Number(product.price).toFixed(2)}
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4">
|
||||
<td className="px-3 py-2">
|
||||
<AdminBadge variant={product.active ? "success" : "default"} dot>
|
||||
{product.active ? "Active" : "Inactive"}
|
||||
</AdminBadge>
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4">
|
||||
<td className="px-3 py-2">
|
||||
{product.is_taxable === false ? (
|
||||
<AdminBadge variant="warning">Non-taxable</AdminBadge>
|
||||
) : (
|
||||
@@ -161,7 +161,7 @@ export default function ProductTableBody({
|
||||
</td>
|
||||
|
||||
{/* Actions */}
|
||||
<td className="px-5 py-4 text-right">
|
||||
<td className="px-3 py-2 text-right">
|
||||
<div className="relative inline-flex items-center justify-end gap-2">
|
||||
<Link
|
||||
href={`/admin/products/${product.id}`}
|
||||
|
||||
@@ -22,31 +22,31 @@ export default function StopTableBody({ stops }: { stops: Stop[] }) {
|
||||
}
|
||||
className="cursor-pointer hover:bg-zinc-800"
|
||||
>
|
||||
<td className="px-5 py-4">
|
||||
<td className="px-3 py-2">
|
||||
<span className="font-medium text-zinc-100">
|
||||
{stop.city}, {stop.state}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4 text-zinc-300">
|
||||
<td className="px-3 py-2 text-zinc-300">
|
||||
{stop.location}
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4 text-zinc-300">
|
||||
<td className="px-3 py-2 text-zinc-300">
|
||||
{stop.date}
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4 text-zinc-300">
|
||||
<td className="px-3 py-2 text-zinc-300">
|
||||
{stop.time}
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4 text-zinc-300">
|
||||
<td className="px-3 py-2 text-zinc-300">
|
||||
{Array.isArray(stop.brands)
|
||||
? stop.brands[0]?.name
|
||||
: stop.brands?.name}
|
||||
</td>
|
||||
|
||||
<td className="px-5 py-4">
|
||||
<td className="px-3 py-2">
|
||||
<span className="rounded-full bg-zinc-950 px-3 py-1 text-xs font-medium text-zinc-300">
|
||||
{stop.active ? "Active" : "Inactive"}
|
||||
</span>
|
||||
|
||||
@@ -38,7 +38,7 @@ const variantClasses: Record<ButtonVariant, string> = {
|
||||
};
|
||||
|
||||
const sizeClasses: Record<ButtonSize, string> = {
|
||||
sm: "px-3 py-1.5 text-xs rounded-lg gap-1.5",
|
||||
sm: "px-2.5 py-1 text-xs rounded-lg gap-1",
|
||||
md: "px-4 py-2 text-sm rounded-xl gap-2",
|
||||
lg: "px-5 py-3 text-base rounded-xl gap-2",
|
||||
};
|
||||
@@ -46,7 +46,7 @@ const sizeClasses: Record<ButtonSize, string> = {
|
||||
export default function AdminButton({
|
||||
children,
|
||||
variant = "primary",
|
||||
size = "md",
|
||||
size = "sm",
|
||||
icon,
|
||||
iconPosition = "left",
|
||||
isLoading = false,
|
||||
|
||||
@@ -12,7 +12,7 @@ type AdminCardProps = {
|
||||
export default function AdminCard({ children, className = "", noPadding = false, style }: AdminCardProps) {
|
||||
return (
|
||||
<div
|
||||
className={`rounded-2xl border bg-white shadow-[var(--admin-shadow-sm)] transition-all duration-200 hover:shadow-[var(--admin-shadow-md)] ${noPadding ? "" : "p-5"} ${className}`}
|
||||
className={`rounded-xl border bg-white shadow-[var(--admin-shadow-sm)] transition-all duration-200 hover:shadow-[var(--admin-shadow-md)] ${noPadding ? "" : "p-4"} ${className}`}
|
||||
style={{
|
||||
borderColor: 'var(--admin-border)',
|
||||
...style
|
||||
|
||||
@@ -31,11 +31,11 @@ type AdminFilterTabsProps = {
|
||||
const sizeClasses = {
|
||||
sm: {
|
||||
container: "p-0.5 gap-0.5",
|
||||
tab: "px-2.5 sm:px-3 py-2 sm:py-1.5 text-xs sm:text-[10px]",
|
||||
tab: "px-2 py-1.5 text-[10px]",
|
||||
},
|
||||
md: {
|
||||
container: "p-1 gap-0.5",
|
||||
tab: "px-3 sm:px-4 py-2.5 sm:py-1.5 text-sm sm:text-xs",
|
||||
container: "p-0.5 gap-0.5",
|
||||
tab: "px-2.5 py-1.5 text-xs",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export default function AdminTable<T extends Record<string, unknown>>({
|
||||
<thead>
|
||||
<tr className="border-b border-[var(--admin-border)] bg-[var(--admin-bg-subtle)]">
|
||||
{columns.map((col) => (
|
||||
<th key={col.key} className={`px-3 sm:px-5 py-3 text-xs sm:text-[10px] font-bold uppercase tracking-widest text-[var(--admin-text-muted)] whitespace-nowrap ${col.className ?? ""}`}>
|
||||
<th key={col.key} className={`px-2 sm:px-3 py-2 text-xs sm:text-[10px] font-bold uppercase tracking-widest text-[var(--admin-text-muted)] whitespace-nowrap ${col.className ?? ""}`}>
|
||||
{col.header}
|
||||
</th>
|
||||
))}
|
||||
@@ -59,7 +59,7 @@ export default function AdminTable<T extends Record<string, unknown>>({
|
||||
style={{ animationDelay: `${index * 30}ms` }}
|
||||
>
|
||||
{columns.map((col) => (
|
||||
<td key={col.key} className={`px-5 py-3.5 ${col.className ?? ""}`}>
|
||||
<td key={col.key} className={`px-3 py-2 ${col.className ?? ""}`}>
|
||||
{col.render ? col.render(item) : String(item[col.key] ?? "")}
|
||||
</td>
|
||||
))}
|
||||
|
||||
@@ -56,18 +56,18 @@ export default function PageHeader({
|
||||
{/* Title Row with Icon and Actions */}
|
||||
<div className="flex items-center justify-between">
|
||||
{/* Left: Icon + Title + Subtitle */}
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-3">
|
||||
{icon && (
|
||||
<div className="flex items-center justify-center w-12 h-12 rounded-2xl bg-[var(--admin-accent-light)] text-[var(--admin-accent)] shadow-[var(--admin-shadow-sm)] transition-transform duration-200 hover:scale-105">
|
||||
<div className="flex items-center justify-center w-10 h-10 rounded-xl bg-[var(--admin-accent-light)] text-[var(--admin-accent)] shadow-[var(--admin-shadow-sm)] transition-transform duration-200 hover:scale-105">
|
||||
{icon}
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-[var(--admin-text-primary)] tracking-tight">
|
||||
<h1 className="text-xl font-bold text-[var(--admin-text-primary)] tracking-tight">
|
||||
{title}
|
||||
</h1>
|
||||
{subtitle && (
|
||||
<p className="mt-1 text-sm text-[var(--admin-text-muted)]">
|
||||
<p className="mt-0.5 text-xs text-[var(--admin-text-muted)]">
|
||||
{subtitle}
|
||||
</p>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user