@rqdhw3n/react-admin-layout 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,162 @@
1
+ # @rqdhw3n/react-admin-layout
2
+
3
+ Production-ready admin dashboard layout for React — sidebar, navbar, dark mode, breadcrumbs, RBAC, mobile drawer.
4
+
5
+ ![React](https://img.shields.io/badge/React-18%2B-blue) ![TypeScript](https://img.shields.io/badge/TypeScript-5-blue)
6
+
7
+ ## Features
8
+
9
+ - Responsive collapsible sidebar
10
+ - Mobile drawer menu
11
+ - Top navbar with search, notifications, user menu
12
+ - Breadcrumbs + auto-generation from route path
13
+ - Dark mode with `localStorage` persistence
14
+ - RBAC permission filtering on sidebar items
15
+ - React Router support (optional peer)
16
+ - Tailwind CSS — modern SaaS aesthetic
17
+ - Full TypeScript
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ npm install @rqdhw3n/react-admin-layout lucide-react
23
+ # optional for routing
24
+ npm install react-router-dom
25
+ ```
26
+
27
+ ## Styles (required)
28
+
29
+ ```ts
30
+ import '@rqdhw3n/react-admin-layout/style.css'
31
+ ```
32
+
33
+ Works with **Vite**, **Next.js** (`app/layout.tsx` or `_app.tsx`), and **CRA**.
34
+
35
+ ### Next.js
36
+
37
+ ```tsx
38
+ // app/layout.tsx
39
+ import '@rqdhw3n/react-admin-layout/style.css'
40
+ ```
41
+
42
+ ### Tailwind in your app
43
+
44
+ If you use Tailwind v3+, add the package to `content`:
45
+
46
+ ```js
47
+ content: [
48
+ './src/**/*.{js,ts,jsx,tsx}',
49
+ './node_modules/@rqdhw3n/react-admin-layout/dist/**/*.js',
50
+ ],
51
+ ```
52
+
53
+ ## Basic usage
54
+
55
+ ```tsx
56
+ import { AdminLayout, type SidebarItemType } from '@rqdhw3n/react-admin-layout'
57
+ import '@rqdhw3n/react-admin-layout/style.css'
58
+ import { Home, Users } from 'lucide-react'
59
+
60
+ const sidebarItems: SidebarItemType[] = [
61
+ { label: 'Dashboard', icon: Home, path: '/dashboard' },
62
+ {
63
+ label: 'Users',
64
+ icon: Users,
65
+ children: [
66
+ { label: 'List', path: '/users' },
67
+ { label: 'Create', path: '/users/create', permission: 'users.create' },
68
+ ],
69
+ },
70
+ ]
71
+
72
+ export default function App() {
73
+ return (
74
+ <AdminLayout
75
+ sidebarItems={sidebarItems}
76
+ appName='My Admin'
77
+ user={{ name: 'Amine', email: 'amine@gmail.com' }}
78
+ permissions={{ users: ['view', 'create'] }}
79
+ activePath='/dashboard'
80
+ >
81
+ <YourPage />
82
+ </AdminLayout>
83
+ )
84
+ }
85
+ ```
86
+
87
+ ## React Router
88
+
89
+ ```tsx
90
+ import { BrowserRouter, Routes, Route } from 'react-router-dom'
91
+ import { AdminLayout, RouterLink } from '@rqdhw3n/react-admin-layout'
92
+
93
+ function App() {
94
+ return (
95
+ <BrowserRouter>
96
+ <AdminLayout
97
+ enableRouter
98
+ LinkComponent={RouterLink}
99
+ sidebarItems={items}
100
+ appName='My Admin'
101
+ >
102
+ <Routes>
103
+ <Route path='/dashboard' element={<Dashboard />} />
104
+ </Routes>
105
+ </AdminLayout>
106
+ </BrowserRouter>
107
+ )
108
+ }
109
+ ```
110
+
111
+ ## Hooks
112
+
113
+ | Hook | Description |
114
+ |------|-------------|
115
+ | `useSidebar()` | Collapsed state, mobile drawer |
116
+ | `useDarkMode()` | Theme toggle |
117
+ | `useLayoutState()` | Full layout context |
118
+ | `useBreadcrumbs()` | Breadcrumb items |
119
+
120
+ ## Components
121
+
122
+ `AdminLayout` · `Sidebar` · `SidebarItem` · `SidebarGroup` · `Navbar` · `NavbarSearch` · `UserMenu` · `NotificationMenu` · `Breadcrumbs` · `Footer` · `MobileSidebar` · `ThemeToggle` · `RouterLink`
123
+
124
+ ## RBAC
125
+
126
+ ```ts
127
+ permissions={{ users: ['view', 'create'], roles: ['view'] }}
128
+
129
+ // sidebar item
130
+ { label: 'Create', path: '/users/create', permission: 'users.create' }
131
+ ```
132
+
133
+ ## Examples
134
+
135
+ - [`examples/basic/App.example.tsx`](./examples/basic/App.example.tsx)
136
+ - [`examples/dark-mode/App.example.tsx`](./examples/dark-mode/App.example.tsx)
137
+ - [`examples/sidebar-collapse/App.example.tsx`](./examples/sidebar-collapse/App.example.tsx)
138
+
139
+ ## Build (library)
140
+
141
+ ```bash
142
+ npm install
143
+ npm run build
144
+ ```
145
+
146
+ Outputs:
147
+
148
+ - `dist/index.js` (ESM)
149
+ - `dist/index.cjs` (CJS)
150
+ - `dist/index.d.ts`
151
+ - `dist/style.css`
152
+
153
+ ## Peer dependencies
154
+
155
+ - `react` >= 18
156
+ - `react-dom` >= 18
157
+ - `lucide-react` >= 0.400
158
+ - `react-router-dom` >= 6 (optional)
159
+
160
+ ## License
161
+
162
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),u=require("react"),T=require("react-router-dom"),x=require("lucide-react");function re(t){if(typeof window>"u")return{};try{const a=localStorage.getItem(t);return a?JSON.parse(a):{}}catch{return{}}}function ne(t,a){if(!(typeof window>"u"))try{localStorage.setItem(t,JSON.stringify(a))}catch{}}const U=u.createContext(null);function $({children:t,storageKey:a="rqdhw3n-admin-layout",defaultCollapsed:s=!1,permissions:r={},initialBreadcrumbs:l=[],initialActivePath:i="/",initialDarkMode:n}){const d=re(a),[o,b]=u.useState(d.sidebarCollapsed??s),[f,v]=u.useState(!1),[h,c]=u.useState(d.darkMode??n??!1),[p,N]=u.useState(l),[S,g]=u.useState(i);u.useEffect(()=>{ne(a,{sidebarCollapsed:o,darkMode:h})},[a,o,h]),u.useEffect(()=>{const y=document.documentElement;h?y.classList.add("dark"):y.classList.remove("dark")},[h]);const k=u.useCallback(()=>b(y=>!y),[]),j=u.useCallback(()=>v(y=>!y),[]),C=u.useCallback(()=>c(y=>!y),[]),A=u.useMemo(()=>({sidebarCollapsed:o,mobileOpen:f,darkMode:h,toggleSidebar:k,setSidebarCollapsed:b,toggleMobile:j,setMobileOpen:v,toggleDarkMode:C,setDarkMode:c,permissions:r,breadcrumbs:p,setBreadcrumbs:N,activePath:S,setActivePath:g}),[o,f,h,k,j,C,r,p,S]);return e.jsx(U.Provider,{value:A,children:t})}function w(){const t=u.useContext(U);if(!t)throw new Error("useLayoutContext must be used within LayoutProvider / AdminLayout");return t}function M(){const{sidebarCollapsed:t,mobileOpen:a,toggleSidebar:s,setSidebarCollapsed:r,toggleMobile:l,setMobileOpen:i}=w();return{collapsed:t,mobileOpen:a,toggle:s,setCollapsed:r,toggleMobile:l,setMobileOpen:i,closeMobile:()=>i(!1)}}function P(t){const a=t.split("/").filter(Boolean);return a.length?a.map((s,r)=>{const l="/"+a.slice(0,r+1).join("/");return{label:s.replace(/-/g," ").replace(/\b\w/g,n=>n.toUpperCase()),path:r<a.length-1?l:void 0}}):[{label:"Home",path:"/"}]}function z(t){var a,s,r="";if(typeof t=="string"||typeof t=="number")r+=t;else if(typeof t=="object")if(Array.isArray(t)){var l=t.length;for(a=0;a<l;a++)t[a]&&(s=z(t[a]))&&(r&&(r+=" "),r+=s)}else for(s in t)t[s]&&(r&&(r+=" "),r+=s);return r}function ie(){for(var t,a,s=0,r="",l=arguments.length;s<l;s++)(t=arguments[s])&&(a=z(t))&&(r&&(r+=" "),r+=a);return r}function m(...t){return ie(t)}function G({children:t}){const{pathname:a}=T.useLocation(),{setActivePath:s,setBreadcrumbs:r,breadcrumbs:l}=w();return u.useEffect(()=>{s(a),l.length||r(P(a))},[a,s,r,l.length]),e.jsx(e.Fragment,{children:t})}function H({children:t,className:a}){return e.jsx("footer",{className:m("mt-auto border-t border-admin-border bg-admin-surface px-6 py-4 text-sm text-admin-muted",a),children:t??e.jsxs("p",{className:"text-center",children:["© ",new Date().getFullYear()," Admin Layout · Built with @rqdhw3n/react-admin-layout"]})})}function le(t){const a=t.indexOf(".");return a===-1?{resource:t,action:"view"}:{resource:t.slice(0,a),action:t.slice(a+1)}}function J(t,a){if(!a)return!0;const{resource:s,action:r}=le(a),l=t[s];return l!=null&&l.length?l.includes(r)||l.includes("*"):!1}function L(t,a){return t.filter(s=>J(a,s.permission)).map(s=>({...s,children:s.children?L(s.children,a):void 0})).filter(s=>{var r;return!((r=s.children)!=null&&r.length)||s.children.length>0||s.path})}function O({label:t,children:a,collapsed:s,className:r}){return e.jsxs("div",{className:m("mb-4",r),children:[t&&!s&&e.jsx("p",{className:"mb-2 px-3 text-[11px] font-semibold uppercase tracking-wider text-admin-muted",children:t}),e.jsx("ul",{className:"space-y-0.5",children:a})]})}function q(t,a){return t?a===t||a.startsWith(`${t}/`):!1}function B({item:t,collapsed:a=!1,depth:s=0,activePath:r="/",onNavigate:l,LinkComponent:i,onItemClick:n}){var g,k;const d=!!((g=t.children)!=null&&g.length),o=t.path?q(t.path,r):!1,b=(k=t.children)==null?void 0:k.some(j=>j.path&&q(j.path,r)),[f,v]=u.useState(o||b),h=t.icon,c=m("group flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-all duration-200","focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-admin-primary",o||b?"bg-admin-primary text-white shadow-sm":"text-admin-muted hover:bg-admin-bg hover:text-admin-text",t.disabled&&"pointer-events-none opacity-50",s>0&&"text-[13px] py-2"),p=e.jsxs(e.Fragment,{children:[h&&e.jsx(h,{className:m("h-[18px] w-[18px] shrink-0",o||b?"text-white":""),"aria-hidden":!0}),!a&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"flex-1 truncate text-left",children:t.label}),t.badge!=null&&e.jsx("span",{className:m("rounded-full px-2 py-0.5 text-[11px] font-semibold",o?"bg-white/20 text-white":"bg-admin-primary/10 text-admin-primary"),children:t.badge}),d&&e.jsx(x.ChevronDown,{className:m("h-4 w-4 shrink-0 transition-transform",f&&"rotate-180"),"aria-hidden":!0})]})]}),N=()=>{if(d){v(j=>!j);return}t.path&&(l==null||l(t.path),n==null||n())},S=t.path&&!d&&i?e.jsx(i,{to:t.path,className:c,onClick:()=>{n==null||n()},children:p}):e.jsx("button",{type:"button",className:c,onClick:N,disabled:t.disabled,children:p});return e.jsxs("li",{children:[S,d&&f&&!a&&e.jsx("ul",{className:"mt-1 space-y-0.5 border-l border-admin-border ml-5 pl-2",children:t.children.map(j=>e.jsx(B,{item:j,collapsed:a,depth:s+1,activePath:r,onNavigate:l,LinkComponent:i,onItemClick:n},j.label+(j.path??"")))})]})}function Q({items:t,appName:a="Admin",appLogo:s,onNavigate:r,activePath:l,LinkComponent:i}){const{mobileOpen:n,closeMobile:d}=M(),{permissions:o,activePath:b}=w(),f=l??b,v=L(t,o);if(u.useEffect(()=>{if(!n)return;const c=p=>{p.key==="Escape"&&d()};return document.addEventListener("keydown",c),document.body.style.overflow="hidden",()=>{document.removeEventListener("keydown",c),document.body.style.overflow=""}},[n,d]),!n)return null;const h=c=>{r==null||r(c),d()};return e.jsxs("div",{className:"fixed inset-0 z-50 lg:hidden",role:"dialog","aria-modal":"true",children:[e.jsx("button",{type:"button",className:"absolute inset-0 bg-slate-900/50 backdrop-blur-sm animate-fade-in","aria-label":"Close menu",onClick:d}),e.jsxs("aside",{className:m("absolute left-0 top-0 flex h-full w-[min(280px,85vw)] flex-col","border-r border-admin-border bg-admin-surface shadow-admin-lg animate-slide-in"),children:[e.jsxs("div",{className:"flex h-16 items-center justify-between border-b border-admin-border px-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[s??e.jsx("div",{className:"flex h-9 w-9 items-center justify-center rounded-xl bg-admin-primary text-sm font-bold text-white",children:a.charAt(0)}),e.jsx("span",{className:"font-semibold text-admin-text",children:a})]}),e.jsx("button",{type:"button",onClick:d,className:"rounded-lg p-2 text-admin-muted hover:bg-admin-bg","aria-label":"Close sidebar",children:e.jsx(x.X,{className:"h-5 w-5"})})]}),e.jsx("nav",{className:"flex-1 overflow-y-auto p-3",children:e.jsx(O,{children:v.map(c=>e.jsx(B,{item:c,activePath:f,onNavigate:h,LinkComponent:i,onItemClick:d},c.label+(c.path??"")))})})]})]})}function W({items:t,className:a,LinkComponent:s,onNavigate:r}){if(!t.length)return null;const l=(i,n)=>{const d=m("text-sm transition-colors",n?"font-medium text-admin-text":"text-admin-muted hover:text-admin-text");return!i.path||n?e.jsx("span",{className:d,children:i.label}):s?e.jsx(s,{to:i.path,className:d,children:i.label}):e.jsx("button",{type:"button",className:d,onClick:()=>r==null?void 0:r(i.path),children:i.label})};return e.jsxs("nav",{"aria-label":"Breadcrumb",className:m("flex items-center gap-1.5",a),children:[e.jsx(x.Home,{className:"h-4 w-4 text-admin-muted shrink-0","aria-hidden":!0}),t.map((i,n)=>{const d=n===t.length-1;return e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx(x.ChevronRight,{className:"h-3.5 w-3.5 text-admin-muted","aria-hidden":!0}),l(i,d)]},`${i.label}-${n}`)})]})}function X({placeholder:t="Search...",onSearch:a,className:s}){const[r,l]=u.useState(""),i=n=>{n.preventDefault(),a==null||a(r.trim())};return e.jsxs("form",{onSubmit:i,className:m("relative w-full max-w-md",s),children:[e.jsx(x.Search,{className:"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-admin-muted","aria-hidden":!0}),e.jsx("input",{type:"search",value:r,onChange:n=>l(n.target.value),placeholder:t,className:m("h-10 w-full rounded-xl border border-admin-border bg-admin-bg pl-10 pr-4 text-sm text-admin-text","placeholder:text-admin-muted focus:border-admin-primary focus:outline-none focus:ring-2 focus:ring-admin-primary/20"),"aria-label":"Search"})]})}function Y({notifications:t=[],className:a}){const[s,r]=u.useState(!1),l=u.useRef(null),i=t.filter(n=>!n.read).length;return u.useEffect(()=>{const n=d=>{l.current&&!l.current.contains(d.target)&&r(!1)};return document.addEventListener("mousedown",n),()=>document.removeEventListener("mousedown",n)},[]),e.jsxs("div",{ref:l,className:m("relative",a),children:[e.jsxs("button",{type:"button",onClick:()=>r(n=>!n),className:m("relative inline-flex h-9 w-9 items-center justify-center rounded-lg border border-admin-border","bg-admin-surface text-admin-muted transition-colors hover:bg-admin-bg hover:text-admin-text","focus-visible:ring-2 focus-visible:ring-admin-primary"),"aria-label":`Notifications${i?`, ${i} unread`:""}`,"aria-expanded":s,children:[e.jsx(x.Bell,{className:"h-4 w-4","aria-hidden":!0}),i>0&&e.jsx("span",{className:"absolute -right-0.5 -top-0.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-red-500 px-1 text-[10px] font-bold text-white",children:i>9?"9+":i})]}),s&&e.jsxs("div",{className:"absolute right-0 top-full z-50 mt-2 w-80 rounded-xl border border-admin-border bg-admin-surface shadow-admin-lg animate-fade-in",children:[e.jsx("div",{className:"border-b border-admin-border px-4 py-3",children:e.jsx("p",{className:"text-sm font-semibold text-admin-text",children:"Notifications"})}),e.jsx("ul",{className:"max-h-72 overflow-y-auto p-2",children:t.length===0?e.jsx("li",{className:"px-3 py-6 text-center text-sm text-admin-muted",children:"No notifications"}):t.map(n=>e.jsxs("li",{className:m("rounded-lg px-3 py-2.5 transition-colors hover:bg-admin-bg",!n.read&&"bg-admin-primary/5"),children:[e.jsx("p",{className:"text-sm font-medium text-admin-text",children:n.title}),n.description&&e.jsx("p",{className:"mt-0.5 text-xs text-admin-muted line-clamp-2",children:n.description}),n.time&&e.jsx("p",{className:"mt-1 text-[11px] text-admin-muted",children:n.time})]},n.id))})]})]})}function _(){const{darkMode:t,toggleDarkMode:a,setDarkMode:s}=w();return{isDark:t,toggle:a,setDarkMode:s}}function K({className:t}){const{isDark:a,toggle:s}=_();return e.jsx("button",{type:"button",onClick:s,className:m("inline-flex h-9 w-9 items-center justify-center rounded-lg border border-admin-border","bg-admin-surface text-admin-muted transition-colors hover:bg-admin-bg hover:text-admin-text","focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-admin-primary focus-visible:ring-offset-2",t),"aria-label":a?"Switch to light mode":"Switch to dark mode",children:a?e.jsx(x.Sun,{className:"h-4 w-4","aria-hidden":!0}):e.jsx(x.Moon,{className:"h-4 w-4","aria-hidden":!0})})}function V({user:t,onLogout:a,onSettings:s,className:r}){const[l,i]=u.useState(!1),n=u.useRef(null);u.useEffect(()=>{const o=b=>{n.current&&!n.current.contains(b.target)&&i(!1)};return document.addEventListener("mousedown",o),()=>document.removeEventListener("mousedown",o)},[]);const d=t.name.split(" ").map(o=>o[0]).join("").slice(0,2).toUpperCase();return e.jsxs("div",{ref:n,className:m("relative",r),children:[e.jsxs("button",{type:"button",onClick:()=>i(o=>!o),className:m("flex items-center gap-2 rounded-xl border border-admin-border bg-admin-surface px-2 py-1.5","transition-colors hover:bg-admin-bg focus-visible:ring-2 focus-visible:ring-admin-primary"),"aria-expanded":l,"aria-haspopup":"menu",children:[t.avatar?e.jsx("img",{src:t.avatar,alt:"",className:"h-8 w-8 rounded-lg object-cover"}):e.jsx("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-admin-primary text-xs font-semibold text-white",children:d}),e.jsxs("div",{className:"hidden text-left sm:block",children:[e.jsx("p",{className:"text-sm font-medium text-admin-text leading-tight",children:t.name}),e.jsx("p",{className:"text-xs text-admin-muted leading-tight",children:t.email})]}),e.jsx(x.ChevronDown,{className:"hidden h-4 w-4 text-admin-muted sm:block","aria-hidden":!0})]}),l&&e.jsxs("div",{role:"menu",className:"absolute right-0 top-full z-50 mt-2 w-56 rounded-xl border border-admin-border bg-admin-surface p-1.5 shadow-admin-lg animate-fade-in",children:[e.jsxs("button",{type:"button",role:"menuitem",className:"flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-admin-text hover:bg-admin-bg",onClick:()=>{s==null||s(),i(!1)},children:[e.jsx(x.Settings,{className:"h-4 w-4 text-admin-muted"}),"Settings"]}),e.jsxs("button",{type:"button",role:"menuitem",className:"flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-admin-text hover:bg-admin-bg",children:[e.jsx(x.User,{className:"h-4 w-4 text-admin-muted"}),"Profile"]}),e.jsx("hr",{className:"my-1 border-admin-border"}),e.jsxs("button",{type:"button",role:"menuitem",className:"flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 hover:bg-red-50 dark:hover:bg-red-950/30",onClick:()=>{a==null||a(),i(!1)},children:[e.jsx(x.LogOut,{className:"h-4 w-4"}),"Log out"]})]})]})}function Z({user:t,notifications:a=[],onSearch:s,searchPlaceholder:r="Search...",showSearch:l=!0,className:i,breadcrumbs:n=[],onMenuClick:d,sidebarCollapsed:o,onToggleSidebar:b}){return e.jsxs("header",{className:m("sticky top-0 z-40 flex h-16 shrink-0 items-center gap-4 border-b border-admin-border","admin-glass bg-admin-surface px-4 lg:px-6",i),children:[e.jsx("button",{type:"button",className:"rounded-lg p-2 text-admin-muted hover:bg-admin-bg lg:hidden",onClick:d,"aria-label":"Open menu",children:e.jsx(x.Menu,{className:"h-5 w-5"})}),e.jsx("button",{type:"button",className:"hidden rounded-lg p-2 text-admin-muted hover:bg-admin-bg lg:inline-flex",onClick:b,"aria-label":o?"Expand sidebar":"Collapse sidebar",children:o?e.jsx(x.PanelLeftOpen,{className:"h-5 w-5"}):e.jsx(x.PanelLeftClose,{className:"h-5 w-5"})}),e.jsx("div",{className:"hidden min-w-0 flex-1 md:block",children:e.jsx(W,{items:n})}),e.jsxs("div",{className:"flex flex-1 items-center justify-end gap-2 sm:gap-3",children:[l&&e.jsx("div",{className:"hidden flex-1 sm:flex sm:max-w-md",children:e.jsx(X,{placeholder:r,onSearch:s})}),e.jsx(K,{}),e.jsx(Y,{notifications:a}),t&&e.jsx(V,{user:t})]})]})}function I({items:t,collapsed:a,appName:s="Admin",appLogo:r,className:l,onNavigate:i,activePath:n,LinkComponent:d}){const{collapsed:o,toggle:b,closeMobile:f}=M(),{permissions:v,activePath:h}=w(),c=a??o,p=n??h,N=L(t,v),S=g=>{i==null||i(g),f()};return e.jsxs("aside",{className:m("hidden lg:flex flex-col border-r border-admin-border bg-admin-surface transition-all duration-300 ease-in-out",c?"w-[var(--admin-sidebar-collapsed)]":"w-[var(--admin-sidebar-width)]",l),"aria-label":"Sidebar navigation",children:[e.jsxs("div",{className:m("flex h-16 items-center border-b border-admin-border px-4",c?"justify-center":"justify-between gap-2"),children:[e.jsxs("div",{className:m("flex items-center gap-3 min-w-0",c&&"justify-center"),children:[r??e.jsx("div",{className:"flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-admin-primary text-sm font-bold text-white shadow-admin",children:s.charAt(0)}),!c&&e.jsx("span",{className:"truncate text-base font-semibold text-admin-text",children:s})]}),!c&&e.jsx("button",{type:"button",onClick:b,className:"rounded-lg p-2 text-admin-muted hover:bg-admin-bg hover:text-admin-text focus-visible:ring-2 focus-visible:ring-admin-primary","aria-label":"Collapse sidebar",children:e.jsx(x.PanelLeftClose,{className:"h-4 w-4"})})]}),c&&e.jsx("div",{className:"flex justify-center py-2 border-b border-admin-border",children:e.jsx("button",{type:"button",onClick:b,className:"rounded-lg p-2 text-admin-muted hover:bg-admin-bg","aria-label":"Expand sidebar",children:e.jsx(x.PanelLeftOpen,{className:"h-4 w-4"})})}),e.jsx("nav",{className:"flex-1 overflow-y-auto p-3",children:e.jsx(O,{collapsed:c,children:N.map(g=>e.jsx(B,{item:g,collapsed:c,activePath:p,onNavigate:S,LinkComponent:d},g.label+(g.path??"")))})})]})}function F({children:t,sidebarItems:a,appName:s="Admin",appLogo:r,user:l,notifications:i=[],footer:n,showFooter:d=!0,showSearch:o=!0,searchPlaceholder:b,onSearch:f,breadcrumbs:v,contentClassName:h,activePath:c,onNavigate:p,LinkComponent:N,enableRouter:S=!1}){const{sidebarCollapsed:g,toggleSidebar:k,toggleMobile:j,breadcrumbs:C,setBreadcrumbs:A,activePath:y,setActivePath:ee}=w(),{closeMobile:te}=M(),D=c??y,ae=v??C,R=E=>{ee(E),v||A(P(E)),p==null||p(E),te()},se=g?"lg:pl-[var(--admin-sidebar-collapsed)]":"lg:pl-[var(--admin-sidebar-width)]";return e.jsxs("div",{className:"admin-layout-root min-h-screen bg-admin-bg text-admin-text",children:[e.jsx(I,{items:a,appName:s,appLogo:r,activePath:D,onNavigate:R,LinkComponent:N}),e.jsx(Q,{items:a,appName:s,appLogo:r,activePath:D,onNavigate:R,LinkComponent:N}),e.jsxs("div",{className:m("flex min-h-screen flex-col transition-all duration-300",se),children:[e.jsx(Z,{user:l,notifications:i,onSearch:f,searchPlaceholder:b,showSearch:o,breadcrumbs:ae,onMenuClick:j,sidebarCollapsed:g,onToggleSidebar:k}),e.jsx("main",{className:m("flex-1 p-4 lg:p-6",h),children:t}),d&&e.jsx(H,{children:n})]})]})}function de(t){const{storageKey:a="rqdhw3n-admin-layout",defaultCollapsed:s=!1,initialDarkMode:r=!1,permissions:l={},breadcrumbs:i=[],activePath:n="/",enableRouter:d=!1,children:o,...b}=t,f=u.useMemo(()=>i.length?i:P(n),[i,n]);return e.jsx($,{storageKey:a,defaultCollapsed:s,permissions:l,initialBreadcrumbs:f,initialActivePath:n,initialDarkMode:r,children:d?e.jsx(G,{children:e.jsx(F,{...b,enableRouter:d,children:o})}):e.jsx(F,{...b,enableRouter:d,children:o})})}function oe({to:t,className:a,children:s,onClick:r}){return e.jsx(T.NavLink,{to:t,className:a,onClick:r,children:s})}function ce(){return w()}function ue(){const{breadcrumbs:t,setBreadcrumbs:a}=w(),s=u.useCallback(r=>a(r),[a]);return{items:t,setBreadcrumbs:s}}exports.AdminLayout=de;exports.AdminLayoutRouterSync=G;exports.Breadcrumbs=W;exports.Footer=H;exports.LayoutProvider=$;exports.MobileSidebar=Q;exports.Navbar=Z;exports.NavbarSearch=X;exports.NotificationMenu=Y;exports.RouterLink=oe;exports.Sidebar=I;exports.SidebarGroup=O;exports.SidebarItem=B;exports.ThemeToggle=K;exports.UserMenu=V;exports.cn=m;exports.filterSidebarByPermissions=L;exports.generateBreadcrumbsFromPath=P;exports.hasPermission=J;exports.useBreadcrumbs=ue;exports.useDarkMode=_;exports.useLayoutContext=w;exports.useLayoutState=ce;exports.useSidebar=M;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/utils/storage.ts","../src/context/LayoutContext.tsx","../src/hooks/useSidebar.ts","../src/utils/breadcrumbs.ts","../node_modules/clsx/dist/clsx.mjs","../src/utils/cn.ts","../src/components/AdminLayoutRouterSync.tsx","../src/components/Footer.tsx","../src/utils/permissions.ts","../src/components/SidebarGroup.tsx","../src/components/SidebarItem.tsx","../src/components/MobileSidebar.tsx","../src/components/Breadcrumbs.tsx","../src/components/NavbarSearch.tsx","../src/components/NotificationMenu.tsx","../src/hooks/useDarkMode.ts","../src/components/ThemeToggle.tsx","../src/components/UserMenu.tsx","../src/components/Navbar.tsx","../src/components/Sidebar.tsx","../src/components/AdminLayout.tsx","../src/components/RouterLink.tsx","../src/hooks/useLayoutState.ts","../src/hooks/useBreadcrumbs.ts"],"sourcesContent":["import type { LayoutState } from '../types'\r\n\r\nexport type PersistedLayout = Pick<LayoutState, 'sidebarCollapsed' | 'darkMode'>\r\n\r\nexport function loadLayoutState(key: string): Partial<PersistedLayout> {\r\n if (typeof window === 'undefined') return {}\r\n try {\r\n const raw = localStorage.getItem(key)\r\n return raw ? (JSON.parse(raw) as Partial<PersistedLayout>) : {}\r\n } catch {\r\n return {}\r\n }\r\n}\r\n\r\nexport function saveLayoutState(key: string, state: PersistedLayout): void {\r\n if (typeof window === 'undefined') return\r\n try {\r\n localStorage.setItem(key, JSON.stringify(state))\r\n } catch {\r\n /* ignore quota errors */\r\n }\r\n}\r\n","import {\r\n createContext,\r\n useCallback,\r\n useContext,\r\n useEffect,\r\n useMemo,\r\n useState,\r\n type ReactNode,\r\n} from 'react'\r\nimport type { BreadcrumbItem, LayoutContextValue, PermissionsMap } from '../types'\r\nimport { loadLayoutState, saveLayoutState } from '../utils/storage'\r\n\r\nconst LayoutContext = createContext<LayoutContextValue | null>(null)\r\n\r\nexport type LayoutProviderProps = {\r\n children: ReactNode\r\n storageKey?: string\r\n defaultCollapsed?: boolean\r\n permissions?: PermissionsMap\r\n initialBreadcrumbs?: BreadcrumbItem[]\r\n initialActivePath?: string\r\n initialDarkMode?: boolean\r\n}\r\n\r\nexport function LayoutProvider({\r\n children,\r\n storageKey = 'rqdhw3n-admin-layout',\r\n defaultCollapsed = false,\r\n permissions = {},\r\n initialBreadcrumbs = [],\r\n initialActivePath = '/',\r\n initialDarkMode,\r\n}: LayoutProviderProps) {\r\n const persisted = loadLayoutState(storageKey)\r\n\r\n const [sidebarCollapsed, setSidebarCollapsed] = useState(\r\n persisted.sidebarCollapsed ?? defaultCollapsed,\r\n )\r\n const [mobileOpen, setMobileOpen] = useState(false)\r\n const [darkMode, setDarkMode] = useState(\r\n persisted.darkMode ?? initialDarkMode ?? false,\r\n )\r\n const [breadcrumbs, setBreadcrumbs] = useState<BreadcrumbItem[]>(initialBreadcrumbs)\r\n const [activePath, setActivePath] = useState(initialActivePath)\r\n\r\n useEffect(() => {\r\n saveLayoutState(storageKey, { sidebarCollapsed, darkMode })\r\n }, [storageKey, sidebarCollapsed, darkMode])\r\n\r\n useEffect(() => {\r\n const root = document.documentElement\r\n if (darkMode) root.classList.add('dark')\r\n else root.classList.remove('dark')\r\n }, [darkMode])\r\n\r\n const toggleSidebar = useCallback(() => setSidebarCollapsed((v) => !v), [])\r\n const toggleMobile = useCallback(() => setMobileOpen((v) => !v), [])\r\n const toggleDarkMode = useCallback(() => setDarkMode((v) => !v), [])\r\n\r\n const value = useMemo<LayoutContextValue>(\r\n () => ({\r\n sidebarCollapsed,\r\n mobileOpen,\r\n darkMode,\r\n toggleSidebar,\r\n setSidebarCollapsed,\r\n toggleMobile,\r\n setMobileOpen,\r\n toggleDarkMode,\r\n setDarkMode,\r\n permissions,\r\n breadcrumbs,\r\n setBreadcrumbs,\r\n activePath,\r\n setActivePath,\r\n }),\r\n [\r\n sidebarCollapsed,\r\n mobileOpen,\r\n darkMode,\r\n toggleSidebar,\r\n toggleMobile,\r\n toggleDarkMode,\r\n permissions,\r\n breadcrumbs,\r\n activePath,\r\n ],\r\n )\r\n\r\n return <LayoutContext.Provider value={value}>{children}</LayoutContext.Provider>\r\n}\r\n\r\nexport function useLayoutContext(): LayoutContextValue {\r\n const ctx = useContext(LayoutContext)\r\n if (!ctx) {\r\n throw new Error('useLayoutContext must be used within LayoutProvider / AdminLayout')\r\n }\r\n return ctx\r\n}\r\n","import { useLayoutContext } from '../context/LayoutContext'\r\n\r\nexport function useSidebar() {\r\n const {\r\n sidebarCollapsed,\r\n mobileOpen,\r\n toggleSidebar,\r\n setSidebarCollapsed,\r\n toggleMobile,\r\n setMobileOpen,\r\n } = useLayoutContext()\r\n\r\n return {\r\n collapsed: sidebarCollapsed,\r\n mobileOpen,\r\n toggle: toggleSidebar,\r\n setCollapsed: setSidebarCollapsed,\r\n toggleMobile,\r\n setMobileOpen,\r\n closeMobile: () => setMobileOpen(false),\r\n }\r\n}\r\n","import type { BreadcrumbItem } from '../types'\r\n\r\nexport function generateBreadcrumbsFromPath(pathname: string): BreadcrumbItem[] {\r\n const segments = pathname.split('/').filter(Boolean)\r\n if (!segments.length) return [{ label: 'Home', path: '/' }]\r\n\r\n return segments.map((seg, i) => {\r\n const path = '/' + segments.slice(0, i + 1).join('/')\r\n const label = seg\r\n .replace(/-/g, ' ')\r\n .replace(/\\b\\w/g, (c) => c.toUpperCase())\r\n return { label, path: i < segments.length - 1 ? path : undefined }\r\n })\r\n}\r\n","function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","import clsx, { type ClassValue } from 'clsx'\r\n\r\nexport function cn(...inputs: ClassValue[]): string {\r\n return clsx(inputs)\r\n}\r\n","import { useEffect, type ReactNode } from 'react'\r\nimport { useLocation } from 'react-router-dom'\r\nimport { useLayoutContext } from '../context/LayoutContext'\r\nimport { generateBreadcrumbsFromPath } from '../utils/breadcrumbs'\r\n\r\nexport type AdminLayoutRouterSyncProps = {\r\n children: ReactNode\r\n}\r\n\r\nexport function AdminLayoutRouterSync({ children }: AdminLayoutRouterSyncProps) {\r\n const { pathname } = useLocation()\r\n const { setActivePath, setBreadcrumbs, breadcrumbs: manualBreadcrumbs } = useLayoutContext()\r\n\r\n useEffect(() => {\r\n setActivePath(pathname)\r\n if (!manualBreadcrumbs.length) {\r\n setBreadcrumbs(generateBreadcrumbsFromPath(pathname))\r\n }\r\n }, [pathname, setActivePath, setBreadcrumbs, manualBreadcrumbs.length])\r\n\r\n return <>{children}</>\r\n}\r\n","import { cn } from '../utils/cn'\r\n\r\nexport type FooterProps = {\r\n children?: React.ReactNode\r\n className?: string\r\n}\r\n\r\nexport function Footer({ children, className }: FooterProps) {\r\n return (\r\n <footer\r\n className={cn(\r\n 'mt-auto border-t border-admin-border bg-admin-surface px-6 py-4 text-sm text-admin-muted',\r\n className,\r\n )}\r\n >\r\n {children ?? (\r\n <p className='text-center'>\r\n © {new Date().getFullYear()} Admin Layout · Built with @rqdhw3n/react-admin-layout\r\n </p>\r\n )}\r\n </footer>\r\n )\r\n}\r\n","import type { PermissionsMap, SidebarItemType } from '../types'\r\n\r\nexport function parsePermission(permission: string): { resource: string; action: string } {\r\n const dot = permission.indexOf('.')\r\n if (dot === -1) return { resource: permission, action: 'view' }\r\n return {\r\n resource: permission.slice(0, dot),\r\n action: permission.slice(dot + 1),\r\n }\r\n}\r\n\r\nexport function hasPermission(\r\n permissions: PermissionsMap,\r\n permission?: string,\r\n): boolean {\r\n if (!permission) return true\r\n const { resource, action } = parsePermission(permission)\r\n const allowed = permissions[resource]\r\n if (!allowed?.length) return false\r\n return allowed.includes(action) || allowed.includes('*')\r\n}\r\n\r\nexport function filterSidebarByPermissions(\r\n items: SidebarItemType[],\r\n permissions: PermissionsMap,\r\n): SidebarItemType[] {\r\n return items\r\n .filter((item) => hasPermission(permissions, item.permission))\r\n .map((item) => ({\r\n ...item,\r\n children: item.children\r\n ? filterSidebarByPermissions(item.children, permissions)\r\n : undefined,\r\n }))\r\n .filter((item) => !item.children?.length || item.children.length > 0 || item.path)\r\n}\r\n","import type { ReactNode } from 'react'\r\nimport { cn } from '../utils/cn'\r\n\r\nexport type SidebarGroupProps = {\r\n label?: string\r\n children: ReactNode\r\n collapsed?: boolean\r\n className?: string\r\n}\r\n\r\nexport function SidebarGroup({ label, children, collapsed, className }: SidebarGroupProps) {\r\n return (\r\n <div className={cn('mb-4', className)}>\r\n {label && !collapsed && (\r\n <p className='mb-2 px-3 text-[11px] font-semibold uppercase tracking-wider text-admin-muted'>\r\n {label}\r\n </p>\r\n )}\r\n <ul className='space-y-0.5'>{children}</ul>\r\n </div>\r\n )\r\n}\r\n","import { ChevronDown } from 'lucide-react'\r\nimport { useState } from 'react'\r\nimport type { SidebarItemType } from '../types'\r\nimport { cn } from '../utils/cn'\r\n\r\nexport type SidebarItemProps = {\r\n item: SidebarItemType\r\n collapsed?: boolean\r\n depth?: number\r\n activePath?: string\r\n onNavigate?: (path: string) => void\r\n LinkComponent?: React.ComponentType<{\r\n to: string\r\n className?: string\r\n children: React.ReactNode\r\n onClick?: () => void\r\n }>\r\n onItemClick?: () => void\r\n}\r\n\r\nfunction isActive(path: string | undefined, activePath: string): boolean {\r\n if (!path) return false\r\n return activePath === path || activePath.startsWith(`${path}/`)\r\n}\r\n\r\nexport function SidebarItem({\r\n item,\r\n collapsed = false,\r\n depth = 0,\r\n activePath = '/',\r\n onNavigate,\r\n LinkComponent,\r\n onItemClick,\r\n}: SidebarItemProps) {\r\n const hasChildren = Boolean(item.children?.length)\r\n const active = item.path ? isActive(item.path, activePath) : false\r\n const childActive = item.children?.some((c) => c.path && isActive(c.path, activePath))\r\n const [open, setOpen] = useState(active || childActive)\r\n\r\n const Icon = item.icon\r\n\r\n const baseClass = cn(\r\n 'group flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-all duration-200',\r\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-admin-primary',\r\n active || childActive\r\n ? 'bg-admin-primary text-white shadow-sm'\r\n : 'text-admin-muted hover:bg-admin-bg hover:text-admin-text',\r\n item.disabled && 'pointer-events-none opacity-50',\r\n depth > 0 && 'text-[13px] py-2',\r\n )\r\n\r\n const content = (\r\n <>\r\n {Icon && (\r\n <Icon\r\n className={cn('h-[18px] w-[18px] shrink-0', active || childActive ? 'text-white' : '')}\r\n aria-hidden\r\n />\r\n )}\r\n {!collapsed && (\r\n <>\r\n <span className='flex-1 truncate text-left'>{item.label}</span>\r\n {item.badge != null && (\r\n <span\r\n className={cn(\r\n 'rounded-full px-2 py-0.5 text-[11px] font-semibold',\r\n active ? 'bg-white/20 text-white' : 'bg-admin-primary/10 text-admin-primary',\r\n )}\r\n >\r\n {item.badge}\r\n </span>\r\n )}\r\n {hasChildren && (\r\n <ChevronDown\r\n className={cn('h-4 w-4 shrink-0 transition-transform', open && 'rotate-180')}\r\n aria-hidden\r\n />\r\n )}\r\n </>\r\n )}\r\n </>\r\n )\r\n\r\n const handleClick = () => {\r\n if (hasChildren) {\r\n setOpen((v) => !v)\r\n return\r\n }\r\n if (item.path) {\r\n onNavigate?.(item.path)\r\n onItemClick?.()\r\n }\r\n }\r\n\r\n const row =\r\n item.path && !hasChildren && LinkComponent ? (\r\n <LinkComponent\r\n to={item.path}\r\n className={baseClass}\r\n onClick={() => {\r\n onItemClick?.()\r\n }}\r\n >\r\n {content}\r\n </LinkComponent>\r\n ) : (\r\n <button type='button' className={baseClass} onClick={handleClick} disabled={item.disabled}>\r\n {content}\r\n </button>\r\n )\r\n\r\n return (\r\n <li>\r\n {row}\r\n {hasChildren && open && !collapsed && (\r\n <ul className='mt-1 space-y-0.5 border-l border-admin-border ml-5 pl-2'>\r\n {item.children!.map((child) => (\r\n <SidebarItem\r\n key={child.label + (child.path ?? '')}\r\n item={child}\r\n collapsed={collapsed}\r\n depth={depth + 1}\r\n activePath={activePath}\r\n onNavigate={onNavigate}\r\n LinkComponent={LinkComponent}\r\n onItemClick={onItemClick}\r\n />\r\n ))}\r\n </ul>\r\n )}\r\n </li>\r\n )\r\n}\r\n","import { X } from 'lucide-react'\r\nimport { useEffect } from 'react'\r\nimport { useSidebar } from '../hooks/useSidebar'\r\nimport { useLayoutContext } from '../context/LayoutContext'\r\nimport type { SidebarProps } from '../types'\r\nimport { filterSidebarByPermissions } from '../utils/permissions'\r\nimport { cn } from '../utils/cn'\r\nimport { SidebarGroup } from './SidebarGroup'\r\nimport { SidebarItem } from './SidebarItem'\r\n\r\nexport type MobileSidebarProps = SidebarProps\r\n\r\nexport function MobileSidebar({\r\n items,\r\n appName = 'Admin',\r\n appLogo,\r\n onNavigate,\r\n activePath: activePathProp,\r\n LinkComponent,\r\n}: MobileSidebarProps) {\r\n const { mobileOpen, closeMobile } = useSidebar()\r\n const { permissions, activePath: ctxPath } = useLayoutContext()\r\n const activePath = activePathProp ?? ctxPath\r\n const filtered = filterSidebarByPermissions(items, permissions)\r\n\r\n useEffect(() => {\r\n if (!mobileOpen) return\r\n const onKey = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') closeMobile()\r\n }\r\n document.addEventListener('keydown', onKey)\r\n document.body.style.overflow = 'hidden'\r\n return () => {\r\n document.removeEventListener('keydown', onKey)\r\n document.body.style.overflow = ''\r\n }\r\n }, [mobileOpen, closeMobile])\r\n\r\n if (!mobileOpen) return null\r\n\r\n const handleNavigate = (path: string) => {\r\n onNavigate?.(path)\r\n closeMobile()\r\n }\r\n\r\n return (\r\n <div className='fixed inset-0 z-50 lg:hidden' role='dialog' aria-modal='true'>\r\n <button\r\n type='button'\r\n className='absolute inset-0 bg-slate-900/50 backdrop-blur-sm animate-fade-in'\r\n aria-label='Close menu'\r\n onClick={closeMobile}\r\n />\r\n <aside\r\n className={cn(\r\n 'absolute left-0 top-0 flex h-full w-[min(280px,85vw)] flex-col',\r\n 'border-r border-admin-border bg-admin-surface shadow-admin-lg animate-slide-in',\r\n )}\r\n >\r\n <div className='flex h-16 items-center justify-between border-b border-admin-border px-4'>\r\n <div className='flex items-center gap-3'>\r\n {appLogo ?? (\r\n <div className='flex h-9 w-9 items-center justify-center rounded-xl bg-admin-primary text-sm font-bold text-white'>\r\n {appName.charAt(0)}\r\n </div>\r\n )}\r\n <span className='font-semibold text-admin-text'>{appName}</span>\r\n </div>\r\n <button\r\n type='button'\r\n onClick={closeMobile}\r\n className='rounded-lg p-2 text-admin-muted hover:bg-admin-bg'\r\n aria-label='Close sidebar'\r\n >\r\n <X className='h-5 w-5' />\r\n </button>\r\n </div>\r\n <nav className='flex-1 overflow-y-auto p-3'>\r\n <SidebarGroup>\r\n {filtered.map((item) => (\r\n <SidebarItem\r\n key={item.label + (item.path ?? '')}\r\n item={item}\r\n activePath={activePath}\r\n onNavigate={handleNavigate}\r\n LinkComponent={LinkComponent}\r\n onItemClick={closeMobile}\r\n />\r\n ))}\r\n </SidebarGroup>\r\n </nav>\r\n </aside>\r\n </div>\r\n )\r\n}\r\n","import { ChevronRight, Home } from 'lucide-react'\r\nimport type { BreadcrumbItem } from '../types'\r\nimport { cn } from '../utils/cn'\r\n\r\nexport type BreadcrumbsProps = {\r\n items: BreadcrumbItem[]\r\n className?: string\r\n LinkComponent?: React.ComponentType<{\r\n to: string\r\n className?: string\r\n children: React.ReactNode\r\n }>\r\n onNavigate?: (path: string) => void\r\n}\r\n\r\nexport function Breadcrumbs({\r\n items,\r\n className,\r\n LinkComponent,\r\n onNavigate,\r\n}: BreadcrumbsProps) {\r\n if (!items.length) return null\r\n\r\n const renderLink = (item: BreadcrumbItem, isLast: boolean) => {\r\n const classNames = cn(\r\n 'text-sm transition-colors',\r\n isLast ? 'font-medium text-admin-text' : 'text-admin-muted hover:text-admin-text',\r\n )\r\n\r\n if (!item.path || isLast) {\r\n return <span className={classNames}>{item.label}</span>\r\n }\r\n\r\n if (LinkComponent) {\r\n return (\r\n <LinkComponent to={item.path} className={classNames}>\r\n {item.label}\r\n </LinkComponent>\r\n )\r\n }\r\n\r\n return (\r\n <button type='button' className={classNames} onClick={() => onNavigate?.(item.path!)}>\r\n {item.label}\r\n </button>\r\n )\r\n }\r\n\r\n return (\r\n <nav aria-label='Breadcrumb' className={cn('flex items-center gap-1.5', className)}>\r\n <Home className='h-4 w-4 text-admin-muted shrink-0' aria-hidden />\r\n {items.map((item, index) => {\r\n const isLast = index === items.length - 1\r\n return (\r\n <span key={`${item.label}-${index}`} className='flex items-center gap-1.5'>\r\n <ChevronRight className='h-3.5 w-3.5 text-admin-muted' aria-hidden />\r\n {renderLink(item, isLast)}\r\n </span>\r\n )\r\n })}\r\n </nav>\r\n )\r\n}\r\n","import { Search } from 'lucide-react'\r\nimport { useState, type FormEvent } from 'react'\r\nimport { cn } from '../utils/cn'\r\n\r\nexport type NavbarSearchProps = {\r\n placeholder?: string\r\n onSearch?: (query: string) => void\r\n className?: string\r\n}\r\n\r\nexport function NavbarSearch({\r\n placeholder = 'Search...',\r\n onSearch,\r\n className,\r\n}: NavbarSearchProps) {\r\n const [query, setQuery] = useState('')\r\n\r\n const handleSubmit = (e: FormEvent) => {\r\n e.preventDefault()\r\n onSearch?.(query.trim())\r\n }\r\n\r\n return (\r\n <form onSubmit={handleSubmit} className={cn('relative w-full max-w-md', className)}>\r\n <Search\r\n className='pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-admin-muted'\r\n aria-hidden\r\n />\r\n <input\r\n type='search'\r\n value={query}\r\n onChange={(e) => setQuery(e.target.value)}\r\n placeholder={placeholder}\r\n className={cn(\r\n 'h-10 w-full rounded-xl border border-admin-border bg-admin-bg pl-10 pr-4 text-sm text-admin-text',\r\n 'placeholder:text-admin-muted focus:border-admin-primary focus:outline-none focus:ring-2 focus:ring-admin-primary/20',\r\n )}\r\n aria-label='Search'\r\n />\r\n </form>\r\n )\r\n}\r\n","import { Bell } from 'lucide-react'\r\nimport { useEffect, useRef, useState } from 'react'\r\nimport type { NotificationItem } from '../types'\r\nimport { cn } from '../utils/cn'\r\n\r\nexport type NotificationMenuProps = {\r\n notifications?: NotificationItem[]\r\n className?: string\r\n}\r\n\r\nexport function NotificationMenu({ notifications = [], className }: NotificationMenuProps) {\r\n const [open, setOpen] = useState(false)\r\n const ref = useRef<HTMLDivElement>(null)\r\n const unread = notifications.filter((n) => !n.read).length\r\n\r\n useEffect(() => {\r\n const handler = (e: MouseEvent) => {\r\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false)\r\n }\r\n document.addEventListener('mousedown', handler)\r\n return () => document.removeEventListener('mousedown', handler)\r\n }, [])\r\n\r\n return (\r\n <div ref={ref} className={cn('relative', className)}>\r\n <button\r\n type='button'\r\n onClick={() => setOpen((v) => !v)}\r\n className={cn(\r\n 'relative inline-flex h-9 w-9 items-center justify-center rounded-lg border border-admin-border',\r\n 'bg-admin-surface text-admin-muted transition-colors hover:bg-admin-bg hover:text-admin-text',\r\n 'focus-visible:ring-2 focus-visible:ring-admin-primary',\r\n )}\r\n aria-label={`Notifications${unread ? `, ${unread} unread` : ''}`}\r\n aria-expanded={open}\r\n >\r\n <Bell className='h-4 w-4' aria-hidden />\r\n {unread > 0 && (\r\n <span className='absolute -right-0.5 -top-0.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-red-500 px-1 text-[10px] font-bold text-white'>\r\n {unread > 9 ? '9+' : unread}\r\n </span>\r\n )}\r\n </button>\r\n\r\n {open && (\r\n <div className='absolute right-0 top-full z-50 mt-2 w-80 rounded-xl border border-admin-border bg-admin-surface shadow-admin-lg animate-fade-in'>\r\n <div className='border-b border-admin-border px-4 py-3'>\r\n <p className='text-sm font-semibold text-admin-text'>Notifications</p>\r\n </div>\r\n <ul className='max-h-72 overflow-y-auto p-2'>\r\n {notifications.length === 0 ? (\r\n <li className='px-3 py-6 text-center text-sm text-admin-muted'>No notifications</li>\r\n ) : (\r\n notifications.map((n) => (\r\n <li\r\n key={n.id}\r\n className={cn(\r\n 'rounded-lg px-3 py-2.5 transition-colors hover:bg-admin-bg',\r\n !n.read && 'bg-admin-primary/5',\r\n )}\r\n >\r\n <p className='text-sm font-medium text-admin-text'>{n.title}</p>\r\n {n.description && (\r\n <p className='mt-0.5 text-xs text-admin-muted line-clamp-2'>{n.description}</p>\r\n )}\r\n {n.time && <p className='mt-1 text-[11px] text-admin-muted'>{n.time}</p>}\r\n </li>\r\n ))\r\n )}\r\n </ul>\r\n </div>\r\n )}\r\n </div>\r\n )\r\n}\r\n","import { useLayoutContext } from '../context/LayoutContext'\r\n\r\nexport function useDarkMode() {\r\n const { darkMode, toggleDarkMode, setDarkMode } = useLayoutContext()\r\n return {\r\n isDark: darkMode,\r\n toggle: toggleDarkMode,\r\n setDarkMode,\r\n }\r\n}\r\n","import { Moon, Sun } from 'lucide-react'\r\nimport { useDarkMode } from '../hooks/useDarkMode'\r\nimport { cn } from '../utils/cn'\r\n\r\nexport type ThemeToggleProps = {\r\n className?: string\r\n}\r\n\r\nexport function ThemeToggle({ className }: ThemeToggleProps) {\r\n const { isDark, toggle } = useDarkMode()\r\n\r\n return (\r\n <button\r\n type='button'\r\n onClick={toggle}\r\n className={cn(\r\n 'inline-flex h-9 w-9 items-center justify-center rounded-lg border border-admin-border',\r\n 'bg-admin-surface text-admin-muted transition-colors hover:bg-admin-bg hover:text-admin-text',\r\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-admin-primary focus-visible:ring-offset-2',\r\n className,\r\n )}\r\n aria-label={isDark ? 'Switch to light mode' : 'Switch to dark mode'}\r\n >\r\n {isDark ? <Sun className='h-4 w-4' aria-hidden /> : <Moon className='h-4 w-4' aria-hidden />}\r\n </button>\r\n )\r\n}\r\n","import { ChevronDown, LogOut, Settings, User } from 'lucide-react'\r\nimport { useEffect, useRef, useState } from 'react'\r\nimport type { AdminUser } from '../types'\r\nimport { cn } from '../utils/cn'\r\n\r\nexport type UserMenuProps = {\r\n user: AdminUser\r\n onLogout?: () => void\r\n onSettings?: () => void\r\n className?: string\r\n}\r\n\r\nexport function UserMenu({ user, onLogout, onSettings, className }: UserMenuProps) {\r\n const [open, setOpen] = useState(false)\r\n const ref = useRef<HTMLDivElement>(null)\r\n\r\n useEffect(() => {\r\n const handler = (e: MouseEvent) => {\r\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false)\r\n }\r\n document.addEventListener('mousedown', handler)\r\n return () => document.removeEventListener('mousedown', handler)\r\n }, [])\r\n\r\n const initials = user.name\r\n .split(' ')\r\n .map((n) => n[0])\r\n .join('')\r\n .slice(0, 2)\r\n .toUpperCase()\r\n\r\n return (\r\n <div ref={ref} className={cn('relative', className)}>\r\n <button\r\n type='button'\r\n onClick={() => setOpen((v) => !v)}\r\n className={cn(\r\n 'flex items-center gap-2 rounded-xl border border-admin-border bg-admin-surface px-2 py-1.5',\r\n 'transition-colors hover:bg-admin-bg focus-visible:ring-2 focus-visible:ring-admin-primary',\r\n )}\r\n aria-expanded={open}\r\n aria-haspopup='menu'\r\n >\r\n {user.avatar ? (\r\n <img src={user.avatar} alt='' className='h-8 w-8 rounded-lg object-cover' />\r\n ) : (\r\n <div className='flex h-8 w-8 items-center justify-center rounded-lg bg-admin-primary text-xs font-semibold text-white'>\r\n {initials}\r\n </div>\r\n )}\r\n <div className='hidden text-left sm:block'>\r\n <p className='text-sm font-medium text-admin-text leading-tight'>{user.name}</p>\r\n <p className='text-xs text-admin-muted leading-tight'>{user.email}</p>\r\n </div>\r\n <ChevronDown className='hidden h-4 w-4 text-admin-muted sm:block' aria-hidden />\r\n </button>\r\n\r\n {open && (\r\n <div\r\n role='menu'\r\n className='absolute right-0 top-full z-50 mt-2 w-56 rounded-xl border border-admin-border bg-admin-surface p-1.5 shadow-admin-lg animate-fade-in'\r\n >\r\n <button\r\n type='button'\r\n role='menuitem'\r\n className='flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-admin-text hover:bg-admin-bg'\r\n onClick={() => {\r\n onSettings?.()\r\n setOpen(false)\r\n }}\r\n >\r\n <Settings className='h-4 w-4 text-admin-muted' />\r\n Settings\r\n </button>\r\n <button\r\n type='button'\r\n role='menuitem'\r\n className='flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-admin-text hover:bg-admin-bg'\r\n >\r\n <User className='h-4 w-4 text-admin-muted' />\r\n Profile\r\n </button>\r\n <hr className='my-1 border-admin-border' />\r\n <button\r\n type='button'\r\n role='menuitem'\r\n className='flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 hover:bg-red-50 dark:hover:bg-red-950/30'\r\n onClick={() => {\r\n onLogout?.()\r\n setOpen(false)\r\n }}\r\n >\r\n <LogOut className='h-4 w-4' />\r\n Log out\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n )\r\n}\r\n","import { Menu, PanelLeftClose, PanelLeftOpen } from 'lucide-react'\r\nimport type { NavbarProps } from '../types'\r\nimport { cn } from '../utils/cn'\r\nimport { Breadcrumbs } from './Breadcrumbs'\r\nimport { NavbarSearch } from './NavbarSearch'\r\nimport { NotificationMenu } from './NotificationMenu'\r\nimport { ThemeToggle } from './ThemeToggle'\r\nimport { UserMenu } from './UserMenu'\r\n\r\nexport function Navbar({\r\n user,\r\n notifications = [],\r\n onSearch,\r\n searchPlaceholder = 'Search...',\r\n showSearch = true,\r\n className,\r\n breadcrumbs = [],\r\n onMenuClick,\r\n sidebarCollapsed,\r\n onToggleSidebar,\r\n}: NavbarProps) {\r\n return (\r\n <header\r\n className={cn(\r\n 'sticky top-0 z-40 flex h-16 shrink-0 items-center gap-4 border-b border-admin-border',\r\n 'admin-glass bg-admin-surface px-4 lg:px-6',\r\n className,\r\n )}\r\n >\r\n <button\r\n type='button'\r\n className='rounded-lg p-2 text-admin-muted hover:bg-admin-bg lg:hidden'\r\n onClick={onMenuClick}\r\n aria-label='Open menu'\r\n >\r\n <Menu className='h-5 w-5' />\r\n </button>\r\n\r\n <button\r\n type='button'\r\n className='hidden rounded-lg p-2 text-admin-muted hover:bg-admin-bg lg:inline-flex'\r\n onClick={onToggleSidebar}\r\n aria-label={sidebarCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}\r\n >\r\n {sidebarCollapsed ? (\r\n <PanelLeftOpen className='h-5 w-5' />\r\n ) : (\r\n <PanelLeftClose className='h-5 w-5' />\r\n )}\r\n </button>\r\n\r\n <div className='hidden min-w-0 flex-1 md:block'>\r\n <Breadcrumbs items={breadcrumbs} />\r\n </div>\r\n\r\n <div className='flex flex-1 items-center justify-end gap-2 sm:gap-3'>\r\n {showSearch && (\r\n <div className='hidden flex-1 sm:flex sm:max-w-md'>\r\n <NavbarSearch placeholder={searchPlaceholder} onSearch={onSearch} />\r\n </div>\r\n )}\r\n <ThemeToggle />\r\n <NotificationMenu notifications={notifications} />\r\n {user && <UserMenu user={user} />}\r\n </div>\r\n </header>\r\n )\r\n}\r\n","import { PanelLeftClose, PanelLeftOpen } from 'lucide-react'\r\nimport { useSidebar } from '../hooks/useSidebar'\r\nimport { useLayoutContext } from '../context/LayoutContext'\r\nimport type { SidebarProps } from '../types'\r\nimport { filterSidebarByPermissions } from '../utils/permissions'\r\nimport { cn } from '../utils/cn'\r\nimport { SidebarGroup } from './SidebarGroup'\r\nimport { SidebarItem } from './SidebarItem'\r\n\r\nexport function Sidebar({\r\n items,\r\n collapsed: collapsedProp,\r\n appName = 'Admin',\r\n appLogo,\r\n className,\r\n onNavigate,\r\n activePath: activePathProp,\r\n LinkComponent,\r\n}: SidebarProps) {\r\n const { collapsed: ctxCollapsed, toggle, closeMobile } = useSidebar()\r\n const { permissions, activePath: ctxPath } = useLayoutContext()\r\n\r\n const collapsed = collapsedProp ?? ctxCollapsed\r\n const activePath = activePathProp ?? ctxPath\r\n const filtered = filterSidebarByPermissions(items, permissions)\r\n\r\n const handleNavigate = (path: string) => {\r\n onNavigate?.(path)\r\n closeMobile()\r\n }\r\n\r\n return (\r\n <aside\r\n className={cn(\r\n 'hidden lg:flex flex-col border-r border-admin-border bg-admin-surface transition-all duration-300 ease-in-out',\r\n collapsed ? 'w-[var(--admin-sidebar-collapsed)]' : 'w-[var(--admin-sidebar-width)]',\r\n className,\r\n )}\r\n aria-label='Sidebar navigation'\r\n >\r\n <div\r\n className={cn(\r\n 'flex h-16 items-center border-b border-admin-border px-4',\r\n collapsed ? 'justify-center' : 'justify-between gap-2',\r\n )}\r\n >\r\n <div className={cn('flex items-center gap-3 min-w-0', collapsed && 'justify-center')}>\r\n {appLogo ?? (\r\n <div className='flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-admin-primary text-sm font-bold text-white shadow-admin'>\r\n {appName.charAt(0)}\r\n </div>\r\n )}\r\n {!collapsed && (\r\n <span className='truncate text-base font-semibold text-admin-text'>{appName}</span>\r\n )}\r\n </div>\r\n {!collapsed && (\r\n <button\r\n type='button'\r\n onClick={toggle}\r\n className='rounded-lg p-2 text-admin-muted hover:bg-admin-bg hover:text-admin-text focus-visible:ring-2 focus-visible:ring-admin-primary'\r\n aria-label='Collapse sidebar'\r\n >\r\n <PanelLeftClose className='h-4 w-4' />\r\n </button>\r\n )}\r\n </div>\r\n\r\n {collapsed && (\r\n <div className='flex justify-center py-2 border-b border-admin-border'>\r\n <button\r\n type='button'\r\n onClick={toggle}\r\n className='rounded-lg p-2 text-admin-muted hover:bg-admin-bg'\r\n aria-label='Expand sidebar'\r\n >\r\n <PanelLeftOpen className='h-4 w-4' />\r\n </button>\r\n </div>\r\n )}\r\n\r\n <nav className='flex-1 overflow-y-auto p-3'>\r\n <SidebarGroup collapsed={collapsed}>\r\n {filtered.map((item) => (\r\n <SidebarItem\r\n key={item.label + (item.path ?? '')}\r\n item={item}\r\n collapsed={collapsed}\r\n activePath={activePath}\r\n onNavigate={handleNavigate}\r\n LinkComponent={LinkComponent}\r\n />\r\n ))}\r\n </SidebarGroup>\r\n </nav>\r\n </aside>\r\n )\r\n}\r\n","import { useMemo } from 'react'\r\nimport { LayoutProvider } from '../context/LayoutContext'\r\nimport { useLayoutContext } from '../context/LayoutContext'\r\nimport { useSidebar } from '../hooks/useSidebar'\r\nimport type { AdminLayoutProps } from '../types'\r\nimport { generateBreadcrumbsFromPath } from '../utils/breadcrumbs'\r\nimport { cn } from '../utils/cn'\r\nimport { AdminLayoutRouterSync } from './AdminLayoutRouterSync'\r\nimport { Footer } from './Footer'\r\nimport { MobileSidebar } from './MobileSidebar'\r\nimport { Navbar } from './Navbar'\r\nimport { Sidebar } from './Sidebar'\r\n\r\nfunction AdminLayoutInner({\r\n children,\r\n sidebarItems,\r\n appName = 'Admin',\r\n appLogo,\r\n user,\r\n notifications = [],\r\n footer,\r\n showFooter = true,\r\n showSearch = true,\r\n searchPlaceholder,\r\n onSearch,\r\n breadcrumbs: breadcrumbsProp,\r\n contentClassName,\r\n activePath: activePathProp,\r\n onNavigate,\r\n LinkComponent,\r\n enableRouter: _enableRouter = false,\r\n}: AdminLayoutProps) {\r\n const {\r\n sidebarCollapsed,\r\n toggleSidebar,\r\n toggleMobile,\r\n breadcrumbs: ctxBreadcrumbs,\r\n setBreadcrumbs,\r\n activePath: ctxPath,\r\n setActivePath,\r\n } = useLayoutContext()\r\n const { closeMobile } = useSidebar()\r\n\r\n const activePath = activePathProp ?? ctxPath\r\n const breadcrumbs = breadcrumbsProp ?? ctxBreadcrumbs\r\n\r\n const handleNavigate = (path: string) => {\r\n setActivePath(path)\r\n if (!breadcrumbsProp) {\r\n setBreadcrumbs(generateBreadcrumbsFromPath(path))\r\n }\r\n onNavigate?.(path)\r\n closeMobile()\r\n }\r\n\r\n const mainOffset = sidebarCollapsed\r\n ? 'lg:pl-[var(--admin-sidebar-collapsed)]'\r\n : 'lg:pl-[var(--admin-sidebar-width)]'\r\n\r\n return (\r\n <div className='admin-layout-root min-h-screen bg-admin-bg text-admin-text'>\r\n <Sidebar\r\n items={sidebarItems}\r\n appName={appName}\r\n appLogo={appLogo}\r\n activePath={activePath}\r\n onNavigate={handleNavigate}\r\n LinkComponent={LinkComponent}\r\n />\r\n <MobileSidebar\r\n items={sidebarItems}\r\n appName={appName}\r\n appLogo={appLogo}\r\n activePath={activePath}\r\n onNavigate={handleNavigate}\r\n LinkComponent={LinkComponent}\r\n />\r\n\r\n <div className={cn('flex min-h-screen flex-col transition-all duration-300', mainOffset)}>\r\n <Navbar\r\n user={user}\r\n notifications={notifications}\r\n onSearch={onSearch}\r\n searchPlaceholder={searchPlaceholder}\r\n showSearch={showSearch}\r\n breadcrumbs={breadcrumbs}\r\n onMenuClick={toggleMobile}\r\n sidebarCollapsed={sidebarCollapsed}\r\n onToggleSidebar={toggleSidebar}\r\n />\r\n\r\n <main className={cn('flex-1 p-4 lg:p-6', contentClassName)}>{children}</main>\r\n\r\n {showFooter && <Footer>{footer}</Footer>}\r\n </div>\r\n </div>\r\n )\r\n}\r\n\r\nexport function AdminLayout(props: AdminLayoutProps) {\r\n const {\r\n storageKey = 'rqdhw3n-admin-layout',\r\n defaultCollapsed = false,\r\n initialDarkMode = false,\r\n permissions = {},\r\n breadcrumbs: initialBreadcrumbs = [],\r\n activePath: initialActivePath = '/',\r\n enableRouter = false,\r\n children,\r\n ...rest\r\n } = props\r\n\r\n const initialBc = useMemo(\r\n () =>\r\n initialBreadcrumbs.length\r\n ? initialBreadcrumbs\r\n : generateBreadcrumbsFromPath(initialActivePath),\r\n [initialBreadcrumbs, initialActivePath],\r\n )\r\n\r\n return (\r\n <LayoutProvider\r\n storageKey={storageKey}\r\n defaultCollapsed={defaultCollapsed}\r\n permissions={permissions}\r\n initialBreadcrumbs={initialBc}\r\n initialActivePath={initialActivePath}\r\n initialDarkMode={initialDarkMode}\r\n >\r\n {enableRouter ? (\r\n <AdminLayoutRouterSync>\r\n <AdminLayoutInner {...rest} enableRouter={enableRouter}>\r\n {children}\r\n </AdminLayoutInner>\r\n </AdminLayoutRouterSync>\r\n ) : (\r\n <AdminLayoutInner {...rest} enableRouter={enableRouter}>\r\n {children}\r\n </AdminLayoutInner>\r\n )}\r\n </LayoutProvider>\r\n )\r\n}\r\n","import { NavLink } from 'react-router-dom'\r\nimport type { ReactNode } from 'react'\r\n\r\nexport type RouterLinkProps = {\r\n to: string\r\n className?: string\r\n children: ReactNode\r\n onClick?: () => void\r\n}\r\n\r\nexport function RouterLink({ to, className, children, onClick }: RouterLinkProps) {\r\n return (\r\n <NavLink to={to} className={className} onClick={onClick}>\r\n {children}\r\n </NavLink>\r\n )\r\n}\r\n","import { useLayoutContext } from '../context/LayoutContext'\r\n\r\nexport function useLayoutState() {\r\n return useLayoutContext()\r\n}\r\n","import { useCallback } from 'react'\r\nimport { useLayoutContext } from '../context/LayoutContext'\r\nimport type { BreadcrumbItem } from '../types'\r\n\r\nexport function useBreadcrumbs() {\r\n const { breadcrumbs, setBreadcrumbs } = useLayoutContext()\r\n\r\n const update = useCallback(\r\n (items: BreadcrumbItem[]) => setBreadcrumbs(items),\r\n [setBreadcrumbs],\r\n )\r\n\r\n return {\r\n items: breadcrumbs,\r\n setBreadcrumbs: update,\r\n }\r\n}\r\n"],"names":["loadLayoutState","key","raw","saveLayoutState","state","LayoutContext","createContext","LayoutProvider","children","storageKey","defaultCollapsed","permissions","initialBreadcrumbs","initialActivePath","initialDarkMode","persisted","sidebarCollapsed","setSidebarCollapsed","useState","mobileOpen","setMobileOpen","darkMode","setDarkMode","breadcrumbs","setBreadcrumbs","activePath","setActivePath","useEffect","root","toggleSidebar","useCallback","v","toggleMobile","toggleDarkMode","value","useMemo","jsx","useLayoutContext","ctx","useContext","useSidebar","generateBreadcrumbsFromPath","pathname","segments","seg","i","path","c","r","e","t","f","n","o","clsx","cn","inputs","AdminLayoutRouterSync","useLocation","manualBreadcrumbs","Footer","className","jsxs","parsePermission","permission","dot","hasPermission","resource","action","allowed","filterSidebarByPermissions","items","item","_a","SidebarGroup","label","collapsed","isActive","SidebarItem","depth","onNavigate","LinkComponent","onItemClick","hasChildren","active","childActive","_b","open","setOpen","Icon","baseClass","content","Fragment","ChevronDown","handleClick","row","child","MobileSidebar","appName","appLogo","activePathProp","closeMobile","ctxPath","filtered","onKey","handleNavigate","X","Breadcrumbs","renderLink","isLast","classNames","Home","index","ChevronRight","NavbarSearch","placeholder","onSearch","query","setQuery","handleSubmit","Search","NotificationMenu","notifications","ref","useRef","unread","handler","Bell","useDarkMode","ThemeToggle","isDark","toggle","Sun","Moon","UserMenu","user","onLogout","onSettings","initials","Settings","User","LogOut","Navbar","searchPlaceholder","showSearch","onMenuClick","onToggleSidebar","Menu","PanelLeftOpen","PanelLeftClose","Sidebar","collapsedProp","ctxCollapsed","AdminLayoutInner","sidebarItems","footer","showFooter","breadcrumbsProp","contentClassName","_enableRouter","ctxBreadcrumbs","mainOffset","AdminLayout","props","enableRouter","rest","initialBc","RouterLink","to","onClick","NavLink","useLayoutState","useBreadcrumbs","update"],"mappings":"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","x_google_ignoreList":[4]}
@@ -0,0 +1,258 @@
1
+ import { ClassValue } from 'clsx';
2
+ import { JSX } from 'react/jsx-runtime';
3
+ import { LucideIcon } from 'lucide-react';
4
+ import { ReactNode } from 'react';
5
+
6
+ export declare function AdminLayout(props: AdminLayoutProps): JSX.Element;
7
+
8
+ export declare type AdminLayoutProps = {
9
+ children: ReactNode;
10
+ sidebarItems: SidebarItemType[];
11
+ appName?: string;
12
+ appLogo?: ReactNode;
13
+ user?: AdminUser;
14
+ notifications?: NotificationItem[];
15
+ permissions?: PermissionsMap;
16
+ breadcrumbs?: BreadcrumbItem[];
17
+ footer?: ReactNode;
18
+ showFooter?: boolean;
19
+ showSearch?: boolean;
20
+ searchPlaceholder?: string;
21
+ onSearch?: (query: string) => void;
22
+ defaultCollapsed?: boolean;
23
+ initialDarkMode?: boolean;
24
+ storageKey?: string;
25
+ className?: string;
26
+ contentClassName?: string;
27
+ activePath?: string;
28
+ onNavigate?: (path: string) => void;
29
+ LinkComponent?: SidebarProps['LinkComponent'];
30
+ enableRouter?: boolean;
31
+ };
32
+
33
+ export declare function AdminLayoutRouterSync({ children }: AdminLayoutRouterSyncProps): JSX.Element;
34
+
35
+ declare type AdminLayoutRouterSyncProps = {
36
+ children: ReactNode;
37
+ };
38
+
39
+ export declare type AdminUser = {
40
+ name: string;
41
+ email: string;
42
+ avatar?: string;
43
+ };
44
+
45
+ export declare type BreadcrumbItem = {
46
+ label: string;
47
+ path?: string;
48
+ };
49
+
50
+ export declare function Breadcrumbs({ items, className, LinkComponent, onNavigate, }: BreadcrumbsProps): JSX.Element | null;
51
+
52
+ export declare type BreadcrumbsProps = {
53
+ items: BreadcrumbItem[];
54
+ className?: string;
55
+ LinkComponent?: React.ComponentType<{
56
+ to: string;
57
+ className?: string;
58
+ children: React.ReactNode;
59
+ }>;
60
+ onNavigate?: (path: string) => void;
61
+ };
62
+
63
+ export declare function cn(...inputs: ClassValue[]): string;
64
+
65
+ export declare function filterSidebarByPermissions(items: SidebarItemType[], permissions: PermissionsMap): SidebarItemType[];
66
+
67
+ export declare function Footer({ children, className }: FooterProps): JSX.Element;
68
+
69
+ export declare type FooterProps = {
70
+ children?: React.ReactNode;
71
+ className?: string;
72
+ };
73
+
74
+ export declare function generateBreadcrumbsFromPath(pathname: string): BreadcrumbItem[];
75
+
76
+ export declare function hasPermission(permissions: PermissionsMap, permission?: string): boolean;
77
+
78
+ export declare type LayoutContextValue = LayoutState & {
79
+ toggleSidebar: () => void;
80
+ setSidebarCollapsed: (v: boolean) => void;
81
+ toggleMobile: () => void;
82
+ setMobileOpen: (v: boolean) => void;
83
+ toggleDarkMode: () => void;
84
+ setDarkMode: (v: boolean) => void;
85
+ permissions: PermissionsMap;
86
+ breadcrumbs: BreadcrumbItem[];
87
+ setBreadcrumbs: (items: BreadcrumbItem[]) => void;
88
+ activePath: string;
89
+ setActivePath: (path: string) => void;
90
+ };
91
+
92
+ export declare function LayoutProvider({ children, storageKey, defaultCollapsed, permissions, initialBreadcrumbs, initialActivePath, initialDarkMode, }: LayoutProviderProps): JSX.Element;
93
+
94
+ declare type LayoutProviderProps = {
95
+ children: ReactNode;
96
+ storageKey?: string;
97
+ defaultCollapsed?: boolean;
98
+ permissions?: PermissionsMap;
99
+ initialBreadcrumbs?: BreadcrumbItem[];
100
+ initialActivePath?: string;
101
+ initialDarkMode?: boolean;
102
+ };
103
+
104
+ export declare type LayoutState = {
105
+ sidebarCollapsed: boolean;
106
+ mobileOpen: boolean;
107
+ darkMode: boolean;
108
+ };
109
+
110
+ export declare function MobileSidebar({ items, appName, appLogo, onNavigate, activePath: activePathProp, LinkComponent, }: MobileSidebarProps): JSX.Element | null;
111
+
112
+ export declare type MobileSidebarProps = SidebarProps;
113
+
114
+ export declare function Navbar({ user, notifications, onSearch, searchPlaceholder, showSearch, className, breadcrumbs, onMenuClick, sidebarCollapsed, onToggleSidebar, }: NavbarProps): JSX.Element;
115
+
116
+ export declare type NavbarProps = {
117
+ appName?: string;
118
+ user?: AdminUser;
119
+ notifications?: NotificationItem[];
120
+ onSearch?: (query: string) => void;
121
+ searchPlaceholder?: string;
122
+ showSearch?: boolean;
123
+ className?: string;
124
+ breadcrumbs?: BreadcrumbItem[];
125
+ onMenuClick?: () => void;
126
+ sidebarCollapsed?: boolean;
127
+ onToggleSidebar?: () => void;
128
+ };
129
+
130
+ export declare function NavbarSearch({ placeholder, onSearch, className, }: NavbarSearchProps): JSX.Element;
131
+
132
+ export declare type NavbarSearchProps = {
133
+ placeholder?: string;
134
+ onSearch?: (query: string) => void;
135
+ className?: string;
136
+ };
137
+
138
+ export declare type NotificationItem = {
139
+ id: string;
140
+ title: string;
141
+ description?: string;
142
+ time?: string;
143
+ read?: boolean;
144
+ };
145
+
146
+ export declare function NotificationMenu({ notifications, className }: NotificationMenuProps): JSX.Element;
147
+
148
+ export declare type NotificationMenuProps = {
149
+ notifications?: NotificationItem[];
150
+ className?: string;
151
+ };
152
+
153
+ export declare type PermissionsMap = Record<string, string[]>;
154
+
155
+ export declare function RouterLink({ to, className, children, onClick }: RouterLinkProps): JSX.Element;
156
+
157
+ declare type RouterLinkProps = {
158
+ to: string;
159
+ className?: string;
160
+ children: ReactNode;
161
+ onClick?: () => void;
162
+ };
163
+
164
+ export declare function Sidebar({ items, collapsed: collapsedProp, appName, appLogo, className, onNavigate, activePath: activePathProp, LinkComponent, }: SidebarProps): JSX.Element;
165
+
166
+ export declare function SidebarGroup({ label, children, collapsed, className }: SidebarGroupProps): JSX.Element;
167
+
168
+ export declare type SidebarGroupProps = {
169
+ label?: string;
170
+ children: ReactNode;
171
+ collapsed?: boolean;
172
+ className?: string;
173
+ };
174
+
175
+ export declare function SidebarItem({ item, collapsed, depth, activePath, onNavigate, LinkComponent, onItemClick, }: SidebarItemProps): JSX.Element;
176
+
177
+ export declare type SidebarItemProps = {
178
+ item: SidebarItemType;
179
+ collapsed?: boolean;
180
+ depth?: number;
181
+ activePath?: string;
182
+ onNavigate?: (path: string) => void;
183
+ LinkComponent?: React.ComponentType<{
184
+ to: string;
185
+ className?: string;
186
+ children: React.ReactNode;
187
+ onClick?: () => void;
188
+ }>;
189
+ onItemClick?: () => void;
190
+ };
191
+
192
+ export declare type SidebarItemType = {
193
+ label: string;
194
+ path?: string;
195
+ icon?: LucideIcon;
196
+ badge?: number | string;
197
+ permission?: string;
198
+ children?: SidebarItemType[];
199
+ disabled?: boolean;
200
+ };
201
+
202
+ export declare type SidebarProps = {
203
+ items: SidebarItemType[];
204
+ collapsed?: boolean;
205
+ appName?: string;
206
+ appLogo?: ReactNode;
207
+ className?: string;
208
+ onNavigate?: (path: string) => void;
209
+ activePath?: string;
210
+ LinkComponent?: React.ComponentType<{
211
+ to: string;
212
+ className?: string;
213
+ children: ReactNode;
214
+ onClick?: () => void;
215
+ }>;
216
+ };
217
+
218
+ export declare function ThemeToggle({ className }: ThemeToggleProps): JSX.Element;
219
+
220
+ export declare type ThemeToggleProps = {
221
+ className?: string;
222
+ };
223
+
224
+ export declare function useBreadcrumbs(): {
225
+ items: BreadcrumbItem[];
226
+ setBreadcrumbs: (items: BreadcrumbItem[]) => void;
227
+ };
228
+
229
+ export declare function useDarkMode(): {
230
+ isDark: boolean;
231
+ toggle: () => void;
232
+ setDarkMode: (v: boolean) => void;
233
+ };
234
+
235
+ export declare function useLayoutContext(): LayoutContextValue;
236
+
237
+ export declare function useLayoutState(): LayoutContextValue;
238
+
239
+ export declare function UserMenu({ user, onLogout, onSettings, className }: UserMenuProps): JSX.Element;
240
+
241
+ export declare type UserMenuProps = {
242
+ user: AdminUser;
243
+ onLogout?: () => void;
244
+ onSettings?: () => void;
245
+ className?: string;
246
+ };
247
+
248
+ export declare function useSidebar(): {
249
+ collapsed: boolean;
250
+ mobileOpen: boolean;
251
+ toggle: () => void;
252
+ setCollapsed: (v: boolean) => void;
253
+ toggleMobile: () => void;
254
+ setMobileOpen: (v: boolean) => void;
255
+ closeMobile: () => void;
256
+ };
257
+
258
+ export { }