- AdminSidebar: group labels (Management/Organisation/Service Providers/Operations), navy active state (bg-[#e8edf5] + [#0a1d37] left bar + navy icon), width 268px, 13.5px font, 40px item height, lucide-solid icons only (no img fallback), min-w-0 truncation fix, tighter py spacing - AdminShell: header height 64px (was 86px), compact search bar 40px/rounded-lg, navy avatar square (was orange gradient), tab indicator navy (was orange), sidebar width 268px, main bg #f3f4f8 - Dashboard: rounded-xl→rounded-lg cards, rounded-2xl→rounded-xl sections, navy accent bars on KPI cards, tabular-nums on values, navy pipeline progress bars - app.css: table thead now navy (#0a1d37) with white text matching reference screenshot, focus rings navy, admin-segment/admin-link-tabs active state navy, reduced border radii on segmented controls and list items Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
132 lines
6.2 KiB
TypeScript
132 lines
6.2 KiB
TypeScript
import { A, useLocation } from '@solidjs/router';
|
|
import { For, Show } from 'solid-js';
|
|
import {
|
|
Bell,
|
|
Briefcase,
|
|
ClipboardList,
|
|
FileText,
|
|
FolderCog,
|
|
HandHelping,
|
|
LayoutGrid,
|
|
Percent,
|
|
Receipt,
|
|
Sparkles,
|
|
UserCircle2,
|
|
Users,
|
|
WalletCards,
|
|
} from 'lucide-solid';
|
|
|
|
type Item = {
|
|
href: string;
|
|
label: string;
|
|
iconPath?: string;
|
|
icon?: any;
|
|
aliasPrefix?: string;
|
|
separatorBefore?: boolean;
|
|
group?: string;
|
|
};
|
|
|
|
const items: Item[] = [
|
|
{ href: '/admin', label: 'Dashboard', icon: LayoutGrid },
|
|
{ href: '/admin/roles', label: 'Internal Role Management', icon: FolderCog, group: 'Management' },
|
|
{ href: '/admin/runtime-roles', label: 'External Role Management', icon: Users },
|
|
{ href: '/admin/onboarding-management', label: 'External Onboarding', icon: Users, aliasPrefix: '/admin/onboarding-schemas' },
|
|
{ href: '/admin/internal-dashboard-management', label: 'Internal Dashboards', icon: LayoutGrid },
|
|
{ href: '/admin/external-dashboard-management', label: 'External Dashboards', icon: LayoutGrid, aliasPrefix: '/admin/role-ui-configs' },
|
|
{ href: '/admin/approval', label: 'Approval Management', icon: ClipboardList },
|
|
{ href: '/admin/department', label: 'Department Management', icon: Briefcase, group: 'Organisation' },
|
|
{ href: '/admin/designation', label: 'Designation Management', icon: Briefcase },
|
|
{ href: '/admin/employees', label: 'Employee Management', icon: UserCircle2 },
|
|
{ href: '/admin/users', label: 'Users Management', icon: Users },
|
|
{ href: '/admin/company', label: 'Company Management', icon: Briefcase },
|
|
{ href: '/admin/candidate', label: 'Candidate Management', icon: UserCircle2 },
|
|
{ href: '/admin/customer', label: 'Customer Management', icon: UserCircle2 },
|
|
{ href: '/admin/photographer', label: 'Photographer Management', icon: Sparkles, group: 'Service Providers' },
|
|
{ href: '/admin/makeup-artist', label: 'Makeup Artist Management', icon: Sparkles },
|
|
{ href: '/admin/tutors', label: 'Tutors Management', icon: Sparkles },
|
|
{ href: '/admin/developers', label: 'Developers Management', icon: Sparkles },
|
|
{ href: '/admin/jobs', label: 'Jobs Management', icon: Briefcase, group: 'Operations' },
|
|
{ href: '/admin/leads', label: 'Leads Management', icon: HandHelping },
|
|
{ href: '/admin/pricing', label: 'Pricing Management', icon: WalletCards, group: 'Finance' },
|
|
{ href: '/admin/credit', label: 'Credit Management', icon: WalletCards },
|
|
{ href: '/admin/coupon', label: 'Coupon Management', icon: Percent },
|
|
{ href: '/admin/discount', label: 'Discount Management', icon: Percent },
|
|
{ href: '/admin/tax', label: 'Tax Management', icon: Receipt },
|
|
{ href: '/admin/order', label: 'Order Management', icon: FileText },
|
|
{ href: '/admin/invoice', label: 'Invoice Management', icon: FileText },
|
|
{ href: '/admin/review', label: 'Review Management', icon: FileText, group: 'Support' },
|
|
{ href: '/admin/support', label: 'Support Management', icon: UserCircle2 },
|
|
{ href: '/admin/report', label: 'Report Management', icon: Bell },
|
|
{ href: '/admin/ledger', label: 'Ledger Management', icon: Receipt },
|
|
{ href: '/admin/kb', label: 'Knowledge Base', icon: FileText },
|
|
{ href: '/admin/notifications', label: 'Notifications', icon: Bell },
|
|
];
|
|
|
|
export default function AdminSidebar(props: { onNavigate?: () => void; onLogout?: () => void }) {
|
|
const location = useLocation();
|
|
|
|
const active = (item: Item) => {
|
|
if (item.href === '/admin') return location.pathname === '/admin';
|
|
if (item.aliasPrefix && location.pathname.startsWith(item.aliasPrefix)) return true;
|
|
return location.pathname === item.href || location.pathname.startsWith(`${item.href}/`);
|
|
};
|
|
|
|
return (
|
|
<aside class="flex h-full w-[268px] flex-col border-r border-[#d7d8df] bg-white">
|
|
<nav class="scrollbar min-h-0 flex-1 overflow-y-auto px-3 py-4">
|
|
<For each={items}>
|
|
{(item, index) => {
|
|
const isActive = () => active(item);
|
|
const showGroup = () => item.group && (index() === 0 || items[index() - 1]?.group !== item.group);
|
|
const Icon = item.icon || FileText;
|
|
|
|
return (
|
|
<>
|
|
<Show when={showGroup()}>
|
|
<div class={`${index() > 0 ? 'mt-4' : ''} mb-1 px-3 pb-1`}>
|
|
<p class="text-[10px] font-bold uppercase tracking-widest text-slate-400">{item.group}</p>
|
|
</div>
|
|
</Show>
|
|
<A
|
|
href={item.href}
|
|
onClick={() => props.onNavigate?.()}
|
|
title={item.label}
|
|
class={`group relative mb-0.5 flex min-h-[40px] w-full items-center gap-2.5 overflow-hidden rounded-lg px-3 text-[13.5px] font-semibold leading-tight transition-all duration-150 ${
|
|
isActive()
|
|
? 'bg-[#e8edf5] text-[#0a1d37]'
|
|
: 'text-[#44495a] hover:bg-slate-50 hover:text-[#0a1d37]'
|
|
}`}
|
|
>
|
|
{/* Left active indicator */}
|
|
<span
|
|
class={`absolute bottom-1.5 left-0 top-1.5 w-[3px] rounded-r-full bg-[#0a1d37] transition-opacity duration-150 ${
|
|
isActive() ? 'opacity-100' : 'opacity-0'
|
|
}`}
|
|
/>
|
|
<Icon
|
|
size={16}
|
|
class={`shrink-0 transition-colors ${isActive() ? 'text-[#0a1d37]' : 'text-slate-400 group-hover:text-slate-600'}`}
|
|
/>
|
|
<span class="min-w-0 flex-1 truncate">{item.label}</span>
|
|
</A>
|
|
</>
|
|
);
|
|
}}
|
|
</For>
|
|
</nav>
|
|
|
|
<div class="border-t border-[#e5e7ef] px-3 py-3">
|
|
<button
|
|
type="button"
|
|
onClick={() => props.onLogout?.()}
|
|
class="flex h-[40px] w-full items-center gap-2.5 rounded-lg px-3 text-left text-[13.5px] font-semibold text-[#c51d1d] transition hover:bg-red-50"
|
|
>
|
|
<svg class="h-4 w-4 shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M17 16l4-4m0 0l-4-4m4 4H9m8 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h8a3 3 0 013 3v1" />
|
|
</svg>
|
|
<span>Sign Out</span>
|
|
</button>
|
|
</div>
|
|
</aside>
|
|
);
|
|
}
|