@ramses1er/cbk-toolkit 1.4.2 → 1.4.4
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/dist/index.js +158 -78
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -49,88 +49,94 @@ function SideNav({
|
|
|
49
49
|
}, [isMobileOpen]);
|
|
50
50
|
const closeMobileNav = () => setIsMobileOpen(false);
|
|
51
51
|
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-screen", children: [
|
|
52
|
-
/* @__PURE__ */ jsxs(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
) : brand.logo),
|
|
62
|
-
brand.name && /* @__PURE__ */ jsx("p", { className: "text-gray-500 text-base font-semibold", children: brand.name })
|
|
63
|
-
] }) }),
|
|
64
|
-
/* @__PURE__ */ jsx("nav", { className: "flex-1 p-4 overflow-y-auto", children: /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: mainItems.map((item) => {
|
|
65
|
-
const active = isActive(item.href, currentPath);
|
|
66
|
-
const isExpanded = expandedSection === item.id;
|
|
67
|
-
const hasSubItems = item.subItems && item.subItems.length > 0;
|
|
68
|
-
return /* @__PURE__ */ jsxs("li", { children: [
|
|
69
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
70
|
-
/* @__PURE__ */ jsxs(
|
|
71
|
-
"a",
|
|
52
|
+
/* @__PURE__ */ jsxs(
|
|
53
|
+
"aside",
|
|
54
|
+
{
|
|
55
|
+
className: `w-64 bg-white border-r border-gray-200 flex flex-col fixed h-full z-50 transition-transform duration-300 ease-in-out md:translate-x-0 ${isMobileOpen ? "translate-x-0" : "-translate-x-full"}`,
|
|
56
|
+
children: [
|
|
57
|
+
brand && /* @__PURE__ */ jsx("div", { className: "p-[6.5px] border-b border-gray-100", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-row gap-2 items-center", children: [
|
|
58
|
+
brand.logo && (typeof brand.logo === "string" ? /* @__PURE__ */ jsx(
|
|
59
|
+
"img",
|
|
72
60
|
{
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
className:
|
|
76
|
-
children: [
|
|
77
|
-
item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsx("span", { className: "text-lg", children: item.icon }) : isValidElement(item.icon) ? item.icon : createElement(
|
|
78
|
-
item.icon,
|
|
79
|
-
{ size: 20 }
|
|
80
|
-
)),
|
|
81
|
-
item.label
|
|
82
|
-
]
|
|
61
|
+
src: brand.logo,
|
|
62
|
+
alt: brand.name ?? "",
|
|
63
|
+
className: "w-12.5 h-12.5"
|
|
83
64
|
}
|
|
84
|
-
),
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
65
|
+
) : brand.logo),
|
|
66
|
+
brand.name && /* @__PURE__ */ jsx("p", { className: "text-gray-500 text-base font-semibold", children: brand.name })
|
|
67
|
+
] }) }),
|
|
68
|
+
/* @__PURE__ */ jsx("nav", { className: "flex-1 p-4 overflow-y-auto", children: /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: mainItems.map((item) => {
|
|
69
|
+
const active = isActive(item.href, currentPath);
|
|
70
|
+
const isExpanded = expandedSection === item.id;
|
|
71
|
+
const hasSubItems = item.subItems && item.subItems.length > 0;
|
|
72
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
73
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
74
|
+
/* @__PURE__ */ jsxs(
|
|
75
|
+
"a",
|
|
93
76
|
{
|
|
94
|
-
|
|
95
|
-
|
|
77
|
+
href: item.href,
|
|
78
|
+
onClick: closeMobileNav,
|
|
79
|
+
className: `flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors flex-1 ${active ? "bg-gray-200 text-black" : "text-gray-500 hover:bg-gray-100"}`,
|
|
80
|
+
children: [
|
|
81
|
+
item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsx("span", { className: "text-lg", children: item.icon }) : isValidElement(item.icon) ? item.icon : createElement(
|
|
82
|
+
item.icon,
|
|
83
|
+
{ size: 20 }
|
|
84
|
+
)),
|
|
85
|
+
item.label
|
|
86
|
+
]
|
|
96
87
|
}
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
88
|
+
),
|
|
89
|
+
active && hasSubItems && /* @__PURE__ */ jsx(
|
|
90
|
+
"button",
|
|
91
|
+
{
|
|
92
|
+
onClick: () => toggleSection(item.id),
|
|
93
|
+
className: `p-1.5 rounded-lg transition-colors ${active ? "text-black hover:bg-gray-100" : "text-gray-500 hover:bg-gray-100"}`,
|
|
94
|
+
title: isExpanded ? "R\xE9duire" : "D\xE9velopper",
|
|
95
|
+
children: toggleIcon ? /* @__PURE__ */ jsx(
|
|
96
|
+
"span",
|
|
97
|
+
{
|
|
98
|
+
className: `inline-block transition-transform duration-200 ${isExpanded ? "rotate-0" : "-rotate-90"}`,
|
|
99
|
+
children: toggleIcon
|
|
100
|
+
}
|
|
101
|
+
) : /* @__PURE__ */ jsx("span", { className: "text-xs", children: isExpanded ? "\u25BC" : "\u25B6" })
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
] }),
|
|
105
|
+
active && hasSubItems && /* @__PURE__ */ jsx(
|
|
106
|
+
"div",
|
|
107
107
|
{
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
className: `grid transition-all duration-300 ease-in-out ${isExpanded ? "grid-rows-[1fr]" : "grid-rows-[0fr]"}`,
|
|
109
|
+
children: /* @__PURE__ */ jsx("div", { className: "overflow-hidden", children: /* @__PURE__ */ jsx("ul", { className: "ml-4 mt-1 space-y-1 pl-2", children: item.subItems.map((sub) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
110
|
+
"a",
|
|
111
|
+
{
|
|
112
|
+
href: sub.href,
|
|
113
|
+
onClick: closeMobileNav,
|
|
114
|
+
className: `flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${isExactActive(sub.href, currentPath) ? "bg-gray-200 text-black" : "text-gray-500 hover:bg-gray-100"}`,
|
|
115
|
+
children: sub.label
|
|
116
|
+
}
|
|
117
|
+
) }, sub.id)) }) })
|
|
112
118
|
}
|
|
113
|
-
)
|
|
114
|
-
}
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
119
|
+
)
|
|
120
|
+
] }, item.id);
|
|
121
|
+
}) }) }),
|
|
122
|
+
footer && footer.length > 0 && /* @__PURE__ */ jsx("div", { className: "p-4 border-t border-gray-100 space-y-1", children: footer.map((item) => /* @__PURE__ */ jsxs(
|
|
123
|
+
"a",
|
|
124
|
+
{
|
|
125
|
+
href: item.href,
|
|
126
|
+
onClick: closeMobileNav,
|
|
127
|
+
className: "flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-100 transition-colors",
|
|
128
|
+
children: [
|
|
129
|
+
typeof item.icon === "string" ? /* @__PURE__ */ jsx("span", { className: "text-lg", children: item.icon }) : isValidElement(item.icon) ? item.icon : createElement(item.icon, {
|
|
130
|
+
size: 20
|
|
131
|
+
}),
|
|
132
|
+
item.label
|
|
133
|
+
]
|
|
134
|
+
},
|
|
128
135
|
item.label
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
] }),
|
|
136
|
+
)) })
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
),
|
|
134
140
|
isMobileOpen && /* @__PURE__ */ jsx(
|
|
135
141
|
"div",
|
|
136
142
|
{
|
|
@@ -149,7 +155,41 @@ function SideNav({
|
|
|
149
155
|
onClick: () => setIsMobileOpen(!isMobileOpen),
|
|
150
156
|
"aria-label": isMobileOpen ? "Fermer le menu" : "Menu",
|
|
151
157
|
"aria-expanded": isMobileOpen,
|
|
152
|
-
children: isMobileOpen ? /* @__PURE__ */ jsx(
|
|
158
|
+
children: isMobileOpen ? /* @__PURE__ */ jsx(
|
|
159
|
+
"svg",
|
|
160
|
+
{
|
|
161
|
+
className: "w-5 h-5",
|
|
162
|
+
fill: "none",
|
|
163
|
+
viewBox: "0 0 24 24",
|
|
164
|
+
stroke: "currentColor",
|
|
165
|
+
strokeWidth: 2,
|
|
166
|
+
children: /* @__PURE__ */ jsx(
|
|
167
|
+
"path",
|
|
168
|
+
{
|
|
169
|
+
strokeLinecap: "round",
|
|
170
|
+
strokeLinejoin: "round",
|
|
171
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
) : /* @__PURE__ */ jsx(
|
|
176
|
+
"svg",
|
|
177
|
+
{
|
|
178
|
+
className: "w-5 h-5",
|
|
179
|
+
fill: "none",
|
|
180
|
+
viewBox: "0 0 24 24",
|
|
181
|
+
stroke: "currentColor",
|
|
182
|
+
strokeWidth: 2,
|
|
183
|
+
children: /* @__PURE__ */ jsx(
|
|
184
|
+
"path",
|
|
185
|
+
{
|
|
186
|
+
strokeLinecap: "round",
|
|
187
|
+
strokeLinejoin: "round",
|
|
188
|
+
d: "M4 6h16M4 12h16M4 18h16"
|
|
189
|
+
}
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
)
|
|
153
193
|
}
|
|
154
194
|
),
|
|
155
195
|
/* @__PURE__ */ jsx("h1", { className: "text-base font-semibold text-gray-500", children: headerTitle })
|
|
@@ -163,10 +203,50 @@ function SideNav({
|
|
|
163
203
|
onClick: () => setIsMobileOpen(!isMobileOpen),
|
|
164
204
|
"aria-label": isMobileOpen ? "Fermer le menu" : "Menu",
|
|
165
205
|
"aria-expanded": isMobileOpen,
|
|
166
|
-
children: isMobileOpen ? /* @__PURE__ */ jsx(
|
|
206
|
+
children: isMobileOpen ? /* @__PURE__ */ jsx(
|
|
207
|
+
"svg",
|
|
208
|
+
{
|
|
209
|
+
className: "w-5 h-5",
|
|
210
|
+
fill: "none",
|
|
211
|
+
viewBox: "0 0 24 24",
|
|
212
|
+
stroke: "currentColor",
|
|
213
|
+
strokeWidth: 2,
|
|
214
|
+
children: /* @__PURE__ */ jsx(
|
|
215
|
+
"path",
|
|
216
|
+
{
|
|
217
|
+
strokeLinecap: "round",
|
|
218
|
+
strokeLinejoin: "round",
|
|
219
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
) : /* @__PURE__ */ jsx(
|
|
224
|
+
"svg",
|
|
225
|
+
{
|
|
226
|
+
className: "w-5 h-5",
|
|
227
|
+
fill: "none",
|
|
228
|
+
viewBox: "0 0 24 24",
|
|
229
|
+
stroke: "currentColor",
|
|
230
|
+
strokeWidth: 2,
|
|
231
|
+
children: /* @__PURE__ */ jsx(
|
|
232
|
+
"path",
|
|
233
|
+
{
|
|
234
|
+
strokeLinecap: "round",
|
|
235
|
+
strokeLinejoin: "round",
|
|
236
|
+
d: "M4 6h16M4 12h16M4 18h16"
|
|
237
|
+
}
|
|
238
|
+
)
|
|
239
|
+
}
|
|
240
|
+
)
|
|
167
241
|
}
|
|
168
242
|
),
|
|
169
|
-
/* @__PURE__ */ jsx(
|
|
243
|
+
/* @__PURE__ */ jsx(
|
|
244
|
+
"main",
|
|
245
|
+
{
|
|
246
|
+
className: (headerTitle ? "p-6 pt-20" : "p-6") + " overflow-x-auto",
|
|
247
|
+
children
|
|
248
|
+
}
|
|
249
|
+
)
|
|
170
250
|
] })
|
|
171
251
|
] });
|
|
172
252
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../packages/ui/src/layouts/side-nav.tsx","../packages/ui/src/config/create-side-nav.tsx","../packages/utils/src/fetcher.ts","../packages/lib/src/http-error.ts","../packages/lib/src/handle-server-error.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport {\r\n ReactNode,\r\n useState,\r\n useEffect,\r\n createElement,\r\n isValidElement,\r\n type ComponentType,\r\n} from \"react\";\r\n\r\ntype IconType = ReactNode | ComponentType<{ size?: number }>;\r\n\r\nexport interface NavItem {\r\n id: string;\r\n label: string;\r\n title?: string;\r\n icon?: IconType;\r\n href: string;\r\n subItems?: NavItem[];\r\n}\r\n\r\nexport interface SideNavStaticConfig {\r\n brand?: {\r\n logo?: ReactNode;\r\n name?: string;\r\n tagline?: string;\r\n };\r\n mainItems: NavItem[];\r\n title?: string;\r\n footer?: { icon?: IconType; label: string; href: string }[];\r\n toggleIcon?: ReactNode;\r\n}\r\n\r\nexport interface SideNavProps extends SideNavStaticConfig {\r\n children: ReactNode;\r\n currentPath: string;\r\n}\r\n\r\nfunction isActive(href: string, currentPath: string) {\r\n return currentPath === href || currentPath.startsWith(href + \"/\");\r\n}\r\n\r\nfunction isExactActive(href: string, currentPath: string) {\r\n return currentPath === href;\r\n}\r\n\r\nexport function SideNav({\r\n children,\r\n title,\r\n mainItems,\r\n currentPath,\r\n brand,\r\n footer,\r\n toggleIcon,\r\n}: SideNavProps) {\r\n const activeMain = mainItems.find((item) => isActive(item.href, currentPath));\r\n const headerTitle = title ?? activeMain?.title ?? activeMain?.label;\r\n const [expandedSection, setExpandedSection] = useState<string | null>(\r\n activeMain?.id ?? null,\r\n );\r\n\r\n const toggleSection = (id: string) => {\r\n setExpandedSection((prev) => (prev === id ? null : id));\r\n };\r\n\r\n const [isMobileOpen, setIsMobileOpen] = useState(false);\r\n\r\n useEffect(() => {\r\n const handleEscape = (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\") setIsMobileOpen(false);\r\n };\r\n document.addEventListener(\"keydown\", handleEscape);\r\n return () => document.removeEventListener(\"keydown\", handleEscape);\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (isMobileOpen) {\r\n document.body.style.overflow = \"hidden\";\r\n } else {\r\n document.body.style.overflow = \"\";\r\n }\r\n return () => {\r\n document.body.style.overflow = \"\";\r\n };\r\n }, [isMobileOpen]);\r\n\r\n const closeMobileNav = () => setIsMobileOpen(false);\r\n\r\n return (\r\n <div className=\"flex min-h-screen\">\r\n <aside className={`w-64 bg-white border-r border-gray-200 flex flex-col fixed h-full max-md:z-50 max-md:transition-transform max-md:duration-300 max-md:ease-in-out ${\r\n isMobileOpen ? \"max-md:translate-x-0\" : \"max-md:-translate-x-full\"\r\n }`}>\r\n {brand && (\r\n <div className=\"p-[6.5px] border-b border-gray-100\">\r\n <div className=\"flex flex-row gap-2 items-center\">\r\n {brand.logo &&\r\n (typeof brand.logo === \"string\" ? (\r\n <img\r\n src={brand.logo}\r\n alt={brand.name ?? \"\"}\r\n className=\"w-12.5 h-12.5\"\r\n />\r\n ) : (\r\n brand.logo\r\n ))}\r\n {brand.name && (\r\n <p className=\"text-gray-500 text-base font-semibold\">\r\n {brand.name}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n <nav className=\"flex-1 p-4 overflow-y-auto\">\r\n <ul className=\"space-y-1\">\r\n {mainItems.map((item) => {\r\n const active = isActive(item.href, currentPath);\r\n const isExpanded = expandedSection === item.id;\r\n const hasSubItems = item.subItems && item.subItems.length > 0;\r\n\r\n return (\r\n <li key={item.id}>\r\n <div className=\"flex items-center gap-1\">\r\n <a\r\n href={item.href}\r\n onClick={closeMobileNav}\r\n className={`flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors flex-1 ${\r\n active\r\n ? \"bg-gray-200 text-black\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n >\r\n {item.icon &&\r\n (typeof item.icon === \"string\" ? (\r\n <span className=\"text-lg\">{item.icon}</span>\r\n ) : isValidElement(item.icon) ? (\r\n item.icon\r\n ) : (\r\n createElement(\r\n item.icon as ComponentType<{ size?: number }>,\r\n { size: 20 },\r\n )\r\n ))}\r\n {item.label}\r\n </a>\r\n {active && hasSubItems && (\r\n <button\r\n onClick={() => toggleSection(item.id)}\r\n className={`p-1.5 rounded-lg transition-colors ${\r\n active\r\n ? \"text-black hover:bg-gray-100\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n title={isExpanded ? \"Réduire\" : \"Développer\"}\r\n >\r\n {toggleIcon ? (\r\n <span\r\n className={`inline-block transition-transform duration-200 ${\r\n isExpanded ? \"rotate-0\" : \"-rotate-90\"\r\n }`}\r\n >\r\n {toggleIcon}\r\n </span>\r\n ) : (\r\n <span className=\"text-xs\">\r\n {isExpanded ? \"▼\" : \"▶\"}\r\n </span>\r\n )}\r\n </button>\r\n )}\r\n </div>\r\n\r\n {active && hasSubItems && (\r\n <div\r\n className={`grid transition-all duration-300 ease-in-out ${\r\n isExpanded ? \"grid-rows-[1fr]\" : \"grid-rows-[0fr]\"\r\n }`}\r\n >\r\n <div className=\"overflow-hidden\">\r\n <ul className=\"ml-4 mt-1 space-y-1 pl-2\">\r\n {item.subItems!.map((sub) => (\r\n <li key={sub.id}>\r\n <a\r\n href={sub.href}\r\n onClick={closeMobileNav}\r\n className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${\r\n isExactActive(sub.href, currentPath)\r\n ? \"bg-gray-200 text-black\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n >\r\n {sub.label}\r\n </a>\r\n </li>\r\n ))}\r\n </ul>\r\n </div>\r\n </div>\r\n )}\r\n </li>\r\n );\r\n })}\r\n </ul>\r\n </nav>\r\n\r\n {footer && footer.length > 0 && (\r\n <div className=\"p-4 border-t border-gray-100 space-y-1\">\r\n {footer.map((item) => (\r\n <a\r\n key={item.label}\r\n href={item.href}\r\n onClick={closeMobileNav}\r\n className=\"flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-100 transition-colors\"\r\n >\r\n {typeof item.icon === \"string\" ? (\r\n <span className=\"text-lg\">{item.icon}</span>\r\n ) : isValidElement(item.icon) ? (\r\n item.icon\r\n ) : (\r\n createElement(item.icon as ComponentType<{ size?: number }>, {\r\n size: 20,\r\n })\r\n )}\r\n {item.label}\r\n </a>\r\n ))}\r\n </div>\r\n )}\r\n </aside>\r\n\r\n {isMobileOpen && (\r\n <div\r\n className=\"fixed inset-0 z-40 bg-black/50 md:hidden\"\r\n onClick={closeMobileNav}\r\n aria-hidden=\"true\"\r\n />\r\n )}\r\n\r\n <div className=\"flex-1 ml-64 max-md:ml-0 min-w-0\">\r\n {headerTitle && (\r\n <header className=\"h-16 bg-white border-b border-gray-200 flex items-center justify-between px-6 fixed top-0 right-0 left-64 max-md:left-0 z-20\">\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n className=\"md:hidden p-2 -ml-2 rounded-lg hover:bg-gray-100 transition-colors\"\r\n onClick={() => setIsMobileOpen(!isMobileOpen)}\r\n aria-label={isMobileOpen ? \"Fermer le menu\" : \"Menu\"}\r\n aria-expanded={isMobileOpen}\r\n >\r\n {isMobileOpen ? (\r\n <svg className=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\r\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\r\n </svg>\r\n ) : (\r\n <svg className=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\r\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4 6h16M4 12h16M4 18h16\" />\r\n </svg>\r\n )}\r\n </button>\r\n <h1 className=\"text-base font-semibold text-gray-500\">\r\n {headerTitle}\r\n </h1>\r\n </div>\r\n {brand?.tagline && (\r\n <span className=\"text-sm text-gray-500 max-md:hidden\">{brand.tagline}</span>\r\n )}\r\n </header>\r\n )}\r\n {!headerTitle && (\r\n <button\r\n className=\"md:hidden fixed top-4 left-4 z-10 p-2 rounded-lg bg-white border border-gray-200 shadow-sm hover:bg-gray-100 transition-colors\"\r\n onClick={() => setIsMobileOpen(!isMobileOpen)}\r\n aria-label={isMobileOpen ? \"Fermer le menu\" : \"Menu\"}\r\n aria-expanded={isMobileOpen}\r\n >\r\n {isMobileOpen ? (\r\n <svg className=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\r\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\r\n </svg>\r\n ) : (\r\n <svg className=\"w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\r\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4 6h16M4 12h16M4 18h16\" />\r\n </svg>\r\n )}\r\n </button>\r\n )}\r\n <main className={(headerTitle ? \"p-6 pt-20\" : \"p-6\") + \" overflow-x-auto\"}>{children}</main>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { SideNav, type SideNavStaticConfig } from \"../layouts/side-nav\";\n\nexport function createSideNav(config: SideNavStaticConfig) {\n return function ConfiguredSideNav({\n children,\n currentPath,\n }: {\n children: React.ReactNode;\n currentPath: string;\n }) {\n return (\n <SideNav {...config} currentPath={currentPath}>\n {children}\n </SideNav>\n );\n };\n}\n","export class ApiError extends Error {\r\n public status: number;\r\n public code?: string;\r\n public data?: unknown;\r\n\r\n constructor(params: {\r\n message: string;\r\n status: number;\r\n code?: string;\r\n data?: unknown;\r\n }) {\r\n super(params.message);\r\n this.status = params.status;\r\n this.code = params.code;\r\n this.data = params.data;\r\n }\r\n}\r\n\r\ntype BackendErrorShape = {\r\n code?: string;\r\n status?: number;\r\n message?: string;\r\n};\r\n\r\nexport type FetcherOptions = RequestInit & {\r\n skipJsonParsing?: boolean;\r\n};\r\n\r\nexport async function fetcher<T = unknown>(\r\n url: string,\r\n options: FetcherOptions = {},\r\n): Promise<T> {\r\n const { headers, skipJsonParsing = false, ...rest } = options;\r\n\r\n const response = await fetch(url, {\r\n credentials: \"include\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n ...rest,\r\n });\r\n\r\n let responseData: unknown = null;\r\n const contentType = response.headers.get(\"content-type\");\r\n\r\n if (!skipJsonParsing && contentType?.includes(\"application/json\")) {\r\n responseData = await response.json();\r\n }\r\n\r\n if (!response.ok) {\r\n const backendError = responseData as BackendErrorShape;\r\n\r\n throw new ApiError({\r\n message: backendError?.message || \"Une erreur est survenue\",\r\n status: backendError?.status || response.status,\r\n code: backendError?.code,\r\n data: responseData,\r\n });\r\n }\r\n\r\n return responseData as T;\r\n}\r\n","export class HttpError extends Error {\r\n status: number;\r\n code?: string;\r\n\r\n constructor(message: string, status = 400, code?: string) {\r\n super(message);\r\n\r\n this.name = \"HttpError\";\r\n this.status = status;\r\n this.code = code;\r\n\r\n Object.setPrototypeOf(this, HttpError.prototype);\r\n }\r\n}\r\n","import { HttpError } from \"./http-error\";\r\n\r\nconst GENERIC_MESSAGE = \"Erreur serveur\";\r\n\r\nfunction shouldShowDetails(showDetails?: boolean): boolean {\r\n return showDetails ?? process.env.NODE_ENV !== \"production\";\r\n}\r\n\r\nfunction sanitizedResponse(\r\n message: string,\r\n code: string,\r\n status: number,\r\n showDetails?: boolean,\r\n) {\r\n return Response.json(\r\n {\r\n message: showDetails ? message : GENERIC_MESSAGE,\r\n code: showDetails ? code : \"INTERNAL_ERROR\",\r\n status,\r\n },\r\n { status },\r\n );\r\n}\r\n\r\n/**\r\n * Transforme n'importe quelle erreur en réponse JSON standardisée\r\n * @param error L'erreur levée\r\n * @param defaultStatus Statut HTTP par défaut si non défini\r\n * @param showDetails Force l'affichage des détails (true) ou le mode sécurisé (false). Par défaut : automatique selon NODE_ENV\r\n * @returns Response JSON\r\n */\r\nexport function handleServerError(\r\n error: unknown,\r\n defaultStatus = 500,\r\n showDetails?: boolean,\r\n) {\r\n const details = shouldShowDetails(showDetails);\r\n\r\n console.error(\"Erreur capturée :\", error);\r\n\r\n // Cas HttpError personnalisé — toujours visible (erreur intentionnelle)\r\n if (error instanceof HttpError) {\r\n const status = error.status ?? defaultStatus;\r\n return Response.json(\r\n {\r\n message: error.message,\r\n code: error.code ?? \"INTERNAL_ERROR\",\r\n status,\r\n },\r\n { status },\r\n );\r\n }\r\n\r\n // Cas classique : objet Error\r\n if (error instanceof Error) {\r\n return sanitizedResponse(\r\n error.message,\r\n \"INTERNAL_ERROR\",\r\n defaultStatus,\r\n details,\r\n );\r\n }\r\n\r\n // Cas objet brut ou autre type\r\n if (typeof error === \"object\" && error !== null) {\r\n return sanitizedResponse(\r\n JSON.stringify(error),\r\n \"INTERNAL_ERROR\",\r\n defaultStatus,\r\n details,\r\n );\r\n }\r\n\r\n // Cas fallback : string ou autre\r\n return sanitizedResponse(\r\n String(error),\r\n \"INTERNAL_ERROR\",\r\n defaultStatus,\r\n details,\r\n );\r\n}\r\n"],"mappings":"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","names":["jsx"]}
|
|
1
|
+
{"version":3,"sources":["../packages/ui/src/layouts/side-nav.tsx","../packages/ui/src/config/create-side-nav.tsx","../packages/utils/src/fetcher.ts","../packages/lib/src/http-error.ts","../packages/lib/src/handle-server-error.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport {\r\n ReactNode,\r\n useState,\r\n useEffect,\r\n createElement,\r\n isValidElement,\r\n type ComponentType,\r\n} from \"react\";\r\n\r\ntype IconType = ReactNode | ComponentType<{ size?: number }>;\r\n\r\nexport interface NavItem {\r\n id: string;\r\n label: string;\r\n title?: string;\r\n icon?: IconType;\r\n href: string;\r\n subItems?: NavItem[];\r\n}\r\n\r\nexport interface SideNavStaticConfig {\r\n brand?: {\r\n logo?: ReactNode;\r\n name?: string;\r\n tagline?: string;\r\n };\r\n mainItems: NavItem[];\r\n title?: string;\r\n footer?: { icon?: IconType; label: string; href: string }[];\r\n toggleIcon?: ReactNode;\r\n}\r\n\r\nexport interface SideNavProps extends SideNavStaticConfig {\r\n children: ReactNode;\r\n currentPath: string;\r\n}\r\n\r\nfunction isActive(href: string, currentPath: string) {\r\n return currentPath === href || currentPath.startsWith(href + \"/\");\r\n}\r\n\r\nfunction isExactActive(href: string, currentPath: string) {\r\n return currentPath === href;\r\n}\r\n\r\nexport function SideNav({\r\n children,\r\n title,\r\n mainItems,\r\n currentPath,\r\n brand,\r\n footer,\r\n toggleIcon,\r\n}: SideNavProps) {\r\n const activeMain = mainItems.find((item) => isActive(item.href, currentPath));\r\n const headerTitle = title ?? activeMain?.title ?? activeMain?.label;\r\n const [expandedSection, setExpandedSection] = useState<string | null>(\r\n activeMain?.id ?? null,\r\n );\r\n\r\n const toggleSection = (id: string) => {\r\n setExpandedSection((prev) => (prev === id ? null : id));\r\n };\r\n\r\n const [isMobileOpen, setIsMobileOpen] = useState(false);\r\n\r\n useEffect(() => {\r\n const handleEscape = (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\") setIsMobileOpen(false);\r\n };\r\n document.addEventListener(\"keydown\", handleEscape);\r\n return () => document.removeEventListener(\"keydown\", handleEscape);\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (isMobileOpen) {\r\n document.body.style.overflow = \"hidden\";\r\n } else {\r\n document.body.style.overflow = \"\";\r\n }\r\n return () => {\r\n document.body.style.overflow = \"\";\r\n };\r\n }, [isMobileOpen]);\r\n\r\n const closeMobileNav = () => setIsMobileOpen(false);\r\n\r\n return (\r\n <div className=\"flex min-h-screen\">\r\n <aside\r\n className={`w-64 bg-white border-r border-gray-200 flex flex-col fixed h-full z-50 transition-transform duration-300 ease-in-out md:translate-x-0 ${\r\n isMobileOpen ? \"translate-x-0\" : \"-translate-x-full\"\r\n }`}\r\n >\r\n {brand && (\r\n <div className=\"p-[6.5px] border-b border-gray-100\">\r\n <div className=\"flex flex-row gap-2 items-center\">\r\n {brand.logo &&\r\n (typeof brand.logo === \"string\" ? (\r\n <img\r\n src={brand.logo}\r\n alt={brand.name ?? \"\"}\r\n className=\"w-12.5 h-12.5\"\r\n />\r\n ) : (\r\n brand.logo\r\n ))}\r\n {brand.name && (\r\n <p className=\"text-gray-500 text-base font-semibold\">\r\n {brand.name}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n <nav className=\"flex-1 p-4 overflow-y-auto\">\r\n <ul className=\"space-y-1\">\r\n {mainItems.map((item) => {\r\n const active = isActive(item.href, currentPath);\r\n const isExpanded = expandedSection === item.id;\r\n const hasSubItems = item.subItems && item.subItems.length > 0;\r\n\r\n return (\r\n <li key={item.id}>\r\n <div className=\"flex items-center gap-1\">\r\n <a\r\n href={item.href}\r\n onClick={closeMobileNav}\r\n className={`flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors flex-1 ${\r\n active\r\n ? \"bg-gray-200 text-black\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n >\r\n {item.icon &&\r\n (typeof item.icon === \"string\" ? (\r\n <span className=\"text-lg\">{item.icon}</span>\r\n ) : isValidElement(item.icon) ? (\r\n item.icon\r\n ) : (\r\n createElement(\r\n item.icon as ComponentType<{ size?: number }>,\r\n { size: 20 },\r\n )\r\n ))}\r\n {item.label}\r\n </a>\r\n {active && hasSubItems && (\r\n <button\r\n onClick={() => toggleSection(item.id)}\r\n className={`p-1.5 rounded-lg transition-colors ${\r\n active\r\n ? \"text-black hover:bg-gray-100\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n title={isExpanded ? \"Réduire\" : \"Développer\"}\r\n >\r\n {toggleIcon ? (\r\n <span\r\n className={`inline-block transition-transform duration-200 ${\r\n isExpanded ? \"rotate-0\" : \"-rotate-90\"\r\n }`}\r\n >\r\n {toggleIcon}\r\n </span>\r\n ) : (\r\n <span className=\"text-xs\">\r\n {isExpanded ? \"▼\" : \"▶\"}\r\n </span>\r\n )}\r\n </button>\r\n )}\r\n </div>\r\n\r\n {active && hasSubItems && (\r\n <div\r\n className={`grid transition-all duration-300 ease-in-out ${\r\n isExpanded ? \"grid-rows-[1fr]\" : \"grid-rows-[0fr]\"\r\n }`}\r\n >\r\n <div className=\"overflow-hidden\">\r\n <ul className=\"ml-4 mt-1 space-y-1 pl-2\">\r\n {item.subItems!.map((sub) => (\r\n <li key={sub.id}>\r\n <a\r\n href={sub.href}\r\n onClick={closeMobileNav}\r\n className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${\r\n isExactActive(sub.href, currentPath)\r\n ? \"bg-gray-200 text-black\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n >\r\n {sub.label}\r\n </a>\r\n </li>\r\n ))}\r\n </ul>\r\n </div>\r\n </div>\r\n )}\r\n </li>\r\n );\r\n })}\r\n </ul>\r\n </nav>\r\n\r\n {footer && footer.length > 0 && (\r\n <div className=\"p-4 border-t border-gray-100 space-y-1\">\r\n {footer.map((item) => (\r\n <a\r\n key={item.label}\r\n href={item.href}\r\n onClick={closeMobileNav}\r\n className=\"flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-100 transition-colors\"\r\n >\r\n {typeof item.icon === \"string\" ? (\r\n <span className=\"text-lg\">{item.icon}</span>\r\n ) : isValidElement(item.icon) ? (\r\n item.icon\r\n ) : (\r\n createElement(item.icon as ComponentType<{ size?: number }>, {\r\n size: 20,\r\n })\r\n )}\r\n {item.label}\r\n </a>\r\n ))}\r\n </div>\r\n )}\r\n </aside>\r\n\r\n {isMobileOpen && (\r\n <div\r\n className=\"fixed inset-0 z-40 bg-black/50 md:hidden\"\r\n onClick={closeMobileNav}\r\n aria-hidden=\"true\"\r\n />\r\n )}\r\n\r\n <div className=\"flex-1 ml-64 max-md:ml-0 min-w-0\">\r\n {headerTitle && (\r\n <header className=\"h-16 bg-white border-b border-gray-200 flex items-center justify-between px-6 fixed top-0 right-0 left-64 max-md:left-0 z-20\">\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n className=\"md:hidden p-2 -ml-2 rounded-lg hover:bg-gray-100 transition-colors\"\r\n onClick={() => setIsMobileOpen(!isMobileOpen)}\r\n aria-label={isMobileOpen ? \"Fermer le menu\" : \"Menu\"}\r\n aria-expanded={isMobileOpen}\r\n >\r\n {isMobileOpen ? (\r\n <svg\r\n className=\"w-5 h-5\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M6 18L18 6M6 6l12 12\"\r\n />\r\n </svg>\r\n ) : (\r\n <svg\r\n className=\"w-5 h-5\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M4 6h16M4 12h16M4 18h16\"\r\n />\r\n </svg>\r\n )}\r\n </button>\r\n <h1 className=\"text-base font-semibold text-gray-500\">\r\n {headerTitle}\r\n </h1>\r\n </div>\r\n {brand?.tagline && (\r\n <span className=\"text-sm text-gray-500 max-md:hidden\">\r\n {brand.tagline}\r\n </span>\r\n )}\r\n </header>\r\n )}\r\n {!headerTitle && (\r\n <button\r\n className=\"md:hidden fixed top-4 left-4 z-10 p-2 rounded-lg bg-white border border-gray-200 shadow-sm hover:bg-gray-100 transition-colors\"\r\n onClick={() => setIsMobileOpen(!isMobileOpen)}\r\n aria-label={isMobileOpen ? \"Fermer le menu\" : \"Menu\"}\r\n aria-expanded={isMobileOpen}\r\n >\r\n {isMobileOpen ? (\r\n <svg\r\n className=\"w-5 h-5\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M6 18L18 6M6 6l12 12\"\r\n />\r\n </svg>\r\n ) : (\r\n <svg\r\n className=\"w-5 h-5\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n d=\"M4 6h16M4 12h16M4 18h16\"\r\n />\r\n </svg>\r\n )}\r\n </button>\r\n )}\r\n <main\r\n className={(headerTitle ? \"p-6 pt-20\" : \"p-6\") + \" overflow-x-auto\"}\r\n >\r\n {children}\r\n </main>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { SideNav, type SideNavStaticConfig } from \"../layouts/side-nav\";\n\nexport function createSideNav(config: SideNavStaticConfig) {\n return function ConfiguredSideNav({\n children,\n currentPath,\n }: {\n children: React.ReactNode;\n currentPath: string;\n }) {\n return (\n <SideNav {...config} currentPath={currentPath}>\n {children}\n </SideNav>\n );\n };\n}\n","export class ApiError extends Error {\r\n public status: number;\r\n public code?: string;\r\n public data?: unknown;\r\n\r\n constructor(params: {\r\n message: string;\r\n status: number;\r\n code?: string;\r\n data?: unknown;\r\n }) {\r\n super(params.message);\r\n this.status = params.status;\r\n this.code = params.code;\r\n this.data = params.data;\r\n }\r\n}\r\n\r\ntype BackendErrorShape = {\r\n code?: string;\r\n status?: number;\r\n message?: string;\r\n};\r\n\r\nexport type FetcherOptions = RequestInit & {\r\n skipJsonParsing?: boolean;\r\n};\r\n\r\nexport async function fetcher<T = unknown>(\r\n url: string,\r\n options: FetcherOptions = {},\r\n): Promise<T> {\r\n const { headers, skipJsonParsing = false, ...rest } = options;\r\n\r\n const response = await fetch(url, {\r\n credentials: \"include\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n ...rest,\r\n });\r\n\r\n let responseData: unknown = null;\r\n const contentType = response.headers.get(\"content-type\");\r\n\r\n if (!skipJsonParsing && contentType?.includes(\"application/json\")) {\r\n responseData = await response.json();\r\n }\r\n\r\n if (!response.ok) {\r\n const backendError = responseData as BackendErrorShape;\r\n\r\n throw new ApiError({\r\n message: backendError?.message || \"Une erreur est survenue\",\r\n status: backendError?.status || response.status,\r\n code: backendError?.code,\r\n data: responseData,\r\n });\r\n }\r\n\r\n return responseData as T;\r\n}\r\n","export class HttpError extends Error {\r\n status: number;\r\n code?: string;\r\n\r\n constructor(message: string, status = 400, code?: string) {\r\n super(message);\r\n\r\n this.name = \"HttpError\";\r\n this.status = status;\r\n this.code = code;\r\n\r\n Object.setPrototypeOf(this, HttpError.prototype);\r\n }\r\n}\r\n","import { HttpError } from \"./http-error\";\r\n\r\nconst GENERIC_MESSAGE = \"Erreur serveur\";\r\n\r\nfunction shouldShowDetails(showDetails?: boolean): boolean {\r\n return showDetails ?? process.env.NODE_ENV !== \"production\";\r\n}\r\n\r\nfunction sanitizedResponse(\r\n message: string,\r\n code: string,\r\n status: number,\r\n showDetails?: boolean,\r\n) {\r\n return Response.json(\r\n {\r\n message: showDetails ? message : GENERIC_MESSAGE,\r\n code: showDetails ? code : \"INTERNAL_ERROR\",\r\n status,\r\n },\r\n { status },\r\n );\r\n}\r\n\r\n/**\r\n * Transforme n'importe quelle erreur en réponse JSON standardisée\r\n * @param error L'erreur levée\r\n * @param defaultStatus Statut HTTP par défaut si non défini\r\n * @param showDetails Force l'affichage des détails (true) ou le mode sécurisé (false). Par défaut : automatique selon NODE_ENV\r\n * @returns Response JSON\r\n */\r\nexport function handleServerError(\r\n error: unknown,\r\n defaultStatus = 500,\r\n showDetails?: boolean,\r\n) {\r\n const details = shouldShowDetails(showDetails);\r\n\r\n console.error(\"Erreur capturée :\", error);\r\n\r\n // Cas HttpError personnalisé — toujours visible (erreur intentionnelle)\r\n if (error instanceof HttpError) {\r\n const status = error.status ?? defaultStatus;\r\n return Response.json(\r\n {\r\n message: error.message,\r\n code: error.code ?? \"INTERNAL_ERROR\",\r\n status,\r\n },\r\n { status },\r\n );\r\n }\r\n\r\n // Cas classique : objet Error\r\n if (error instanceof Error) {\r\n return sanitizedResponse(\r\n error.message,\r\n \"INTERNAL_ERROR\",\r\n defaultStatus,\r\n details,\r\n );\r\n }\r\n\r\n // Cas objet brut ou autre type\r\n if (typeof error === \"object\" && error !== null) {\r\n return sanitizedResponse(\r\n JSON.stringify(error),\r\n \"INTERNAL_ERROR\",\r\n defaultStatus,\r\n details,\r\n );\r\n }\r\n\r\n // Cas fallback : string ou autre\r\n return sanitizedResponse(\r\n String(error),\r\n \"INTERNAL_ERROR\",\r\n defaultStatus,\r\n details,\r\n );\r\n}\r\n"],"mappings":"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","names":["jsx"]}
|