spotlibs-components 0.1.14 → 0.1.16

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.
@@ -0,0 +1,834 @@
1
+ "use client";
2
+ import { __objRest, __spreadValues, __spreadProps } from './chunk-YOSPWY5K.mjs';
3
+ import { createContext, useState, useCallback, useEffect, useContext, useRef } from 'react';
4
+ import BoxRaw from '@mui/material/Box';
5
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
+ import { IconChevronDown, IconMenu2, IconUser, IconLogout, IconSettings, IconList, IconFileText, IconLayoutGrid, IconCircle } from '@tabler/icons-react';
7
+ import IconButtonRaw from '@mui/material/IconButton';
8
+ import MenuRaw from '@mui/material/Menu';
9
+ import MenuItemRaw from '@mui/material/MenuItem';
10
+ import TypographyRaw from '@mui/material/Typography';
11
+ import CryptoJS from 'crypto-js';
12
+ import AES from 'crypto-js/aes';
13
+
14
+ var SidebarContext = createContext(void 0);
15
+ function SidebarProvider({ children }) {
16
+ const [isExpanded, setIsExpanded] = useState(true);
17
+ const [isMobileOpen, setIsMobileOpen] = useState(false);
18
+ const [isHovered, setIsHovered] = useState(false);
19
+ const toggleSidebar = useCallback(() => setIsExpanded((prev) => !prev), []);
20
+ const toggleMobileSidebar = useCallback(() => setIsMobileOpen((prev) => !prev), []);
21
+ const handleSetIsHovered = useCallback((hovered) => setIsHovered(hovered), []);
22
+ useEffect(() => {
23
+ const mediaQuery = window.matchMedia("(min-width: 1024px)");
24
+ const handleChange = (e) => {
25
+ if (e.matches) setIsMobileOpen(false);
26
+ };
27
+ mediaQuery.addEventListener("change", handleChange);
28
+ return () => mediaQuery.removeEventListener("change", handleChange);
29
+ }, []);
30
+ return /* @__PURE__ */ jsx(
31
+ SidebarContext.Provider,
32
+ {
33
+ value: {
34
+ isExpanded,
35
+ isMobileOpen,
36
+ isHovered,
37
+ toggleSidebar,
38
+ toggleMobileSidebar,
39
+ setIsHovered: handleSetIsHovered
40
+ },
41
+ children
42
+ }
43
+ );
44
+ }
45
+ function useSidebar() {
46
+ const context = useContext(SidebarContext);
47
+ if (!context) throw new Error("useSidebar must be used within a SidebarProvider");
48
+ return context;
49
+ }
50
+
51
+ // src/components/atoms/colors/primitive/primitive.jsx
52
+ var RAW_COLORS = {
53
+ neutral: {
54
+ 50: "#FFFFFF",
55
+ 100: "#F5F7FB",
56
+ 200: "#E9EEF6",
57
+ 300: "#E0E5EB",
58
+ 400: "#B3BECC",
59
+ 500: "#A3B1C1",
60
+ 600: "#7B90A6",
61
+ 700: "#465668",
62
+ 900: "#181C21"
63
+ },
64
+ blue_cakrawala: {
65
+ 100: "#EAF2FC",
66
+ 200: "#E6EEFF",
67
+ 300: "#83B2EE",
68
+ 400: "#5999E8",
69
+ 500: "#307FE2",
70
+ 600: "#2666B5",
71
+ 700: "#1D4C88",
72
+ 800: "#0E2644",
73
+ 900: "#0A192D"
74
+ },
75
+ blue_mentari: {
76
+ 100: "#E5F3FB",
77
+ 300: "#ADDBF2",
78
+ 400: "#8CD0EE",
79
+ 500: "#71C5E8",
80
+ 600: "#5799B5",
81
+ 700: "#3E7186",
82
+ 900: "#132831"
83
+ },
84
+ blue_neon: {
85
+ 100: "#F0FCFF",
86
+ 300: "#CDF5FE",
87
+ 400: "#9BEBFD",
88
+ 500: "#14D1FB",
89
+ 600: "#04B1D8",
90
+ 700: "#0388A5",
91
+ 900: "#025F73"
92
+ },
93
+ blue_sky: {
94
+ 100: "#EBF8FF",
95
+ 300: "#BDE7FF",
96
+ 400: "#80D1FF",
97
+ 500: "#15A9F4",
98
+ 600: "#0A8BCD",
99
+ 700: "#076A9C",
100
+ 900: "#032436"
101
+ },
102
+ green: {
103
+ 100: "#DEF7EA",
104
+ 300: "#C9F3DB",
105
+ 400: "#A1DDBB",
106
+ 500: "#27AE60",
107
+ 600: "#1E8549",
108
+ 700: "#145C33",
109
+ 900: "#0A2E19"
110
+ },
111
+ red: {
112
+ 100: "#FDEDED",
113
+ 300: "#F8C4C4",
114
+ 400: "#F28D8D",
115
+ 500: "#E84040",
116
+ 600: "#DA1A1A",
117
+ 700: "#AD1414",
118
+ 900: "#320606"
119
+ },
120
+ yellow: {
121
+ 100: "#FFF9EB",
122
+ 300: "#FFEBBD",
123
+ 400: "#FFD980",
124
+ 500: "#FFBE26",
125
+ 600: "#F0A800",
126
+ 700: "#BD8400",
127
+ 900: "#382700"
128
+ },
129
+ briva: {
130
+ 100: "#EFFAFA",
131
+ 300: "#CCF0F0",
132
+ 400: "#9CE2E2",
133
+ 500: "#58CFCF",
134
+ 600: "#37BEBE",
135
+ 700: "#2B9696",
136
+ 900: "#0D2C2C"
137
+ },
138
+ brizzi: {
139
+ 100: "#EBFFF8",
140
+ 300: "#BEFDE8",
141
+ 400: "#83FBD3",
142
+ 500: "#05D78F",
143
+ 600: "#04A46D",
144
+ 700: "#03734D",
145
+ 900: "#013724"
146
+ }
147
+ };
148
+ var PrimitiveColor = Object.entries(RAW_COLORS).reduce(
149
+ (acc, [category, values]) => {
150
+ Object.entries(values).forEach(([key, value]) => {
151
+ if (category === "neutral" || category === "blue_cakrawala" || category === "blue_mentari" || category === "blue_neon" || category === "blue_sky" || category === "green" || category === "red" || category === "yellow" || category === "briva" || category === "brizzi") {
152
+ acc[`color_${category}_${key}`] = value;
153
+ return;
154
+ }
155
+ acc[`color_${key}`] = value;
156
+ });
157
+ return acc;
158
+ },
159
+ {}
160
+ );
161
+
162
+ // src/components/atoms/colors/derived/derived.jsx
163
+ var DerivedColor = {
164
+ /* ================= BACKGROUND ================= */
165
+ color_bg_page: PrimitiveColor.color_neutral_100,
166
+ color_bg_surface: PrimitiveColor.color_neutral_50,
167
+ color_bg_inverse: PrimitiveColor.color_neutral_900,
168
+ color_bg_disabled: PrimitiveColor.color_neutral_300,
169
+ color_bg_brand_primary_strong: PrimitiveColor.color_blue_cakrawala_600,
170
+ color_bg_brand_primary: PrimitiveColor.color_blue_cakrawala_500,
171
+ color_bg_brand_primary_subtle: PrimitiveColor.color_blue_cakrawala_100,
172
+ color_bg_brand_secondary_strong: PrimitiveColor.color_blue_mentari_600,
173
+ color_bg_brand_secondary: PrimitiveColor.color_blue_mentari_500,
174
+ color_bg_brand_secondary_subtle: PrimitiveColor.color_blue_mentari_100,
175
+ color_bg_success_strong: PrimitiveColor.color_green_600,
176
+ color_bg_success: PrimitiveColor.color_green_500,
177
+ color_bg_success_subtle: PrimitiveColor.color_green_300,
178
+ color_bg_danger_strong: PrimitiveColor.color_red_600,
179
+ color_bg_danger: PrimitiveColor.color_red_500,
180
+ color_bg_danger_subtle: PrimitiveColor.color_red_300,
181
+ color_bg_warning_strong: PrimitiveColor.color_yellow_600,
182
+ color_bg_warning: PrimitiveColor.color_yellow_500,
183
+ color_bg_warning_subtle: PrimitiveColor.color_yellow_300,
184
+ /* ================= BORDER ================= */
185
+ color_border_default: PrimitiveColor.color_neutral_300,
186
+ color_border_strong: PrimitiveColor.color_neutral_500,
187
+ color_border_inverse: PrimitiveColor.color_neutral_900,
188
+ color_border_brand_primary: PrimitiveColor.color_blue_cakrawala_500,
189
+ color_border_brand_secondary: PrimitiveColor.color_blue_mentari_500,
190
+ color_border_success: PrimitiveColor.color_green_500,
191
+ color_border_danger: PrimitiveColor.color_red_500,
192
+ color_border_warning: PrimitiveColor.color_yellow_500,
193
+ /* ================= TEXT ================= */
194
+ color_text_default: PrimitiveColor.color_neutral_900,
195
+ color_text_subtle: PrimitiveColor.color_neutral_700,
196
+ color_text_disabled: PrimitiveColor.color_neutral_600,
197
+ color_text_placeholder: PrimitiveColor.color_neutral_400,
198
+ color_text_inverse: PrimitiveColor.color_neutral_50,
199
+ color_text_brand_primary: PrimitiveColor.color_blue_cakrawala_500,
200
+ color_text_brand_secondary: PrimitiveColor.color_blue_mentari_500,
201
+ color_text_success: PrimitiveColor.color_green_500,
202
+ color_text_danger: PrimitiveColor.color_red_500,
203
+ color_text_warning: PrimitiveColor.color_yellow_600,
204
+ /* ================= ICON ================= */
205
+ color_icon_subtle: PrimitiveColor.color_neutral_600,
206
+ color_icon_strong: PrimitiveColor.color_neutral_700,
207
+ color_icon_disabled: PrimitiveColor.color_neutral_200,
208
+ color_icon_inverse: PrimitiveColor.color_neutral_50,
209
+ color_icon_brand_primary: PrimitiveColor.color_blue_cakrawala_500,
210
+ color_icon_brand_secondary: PrimitiveColor.color_blue_mentari_500,
211
+ color_icon_success: PrimitiveColor.color_green_500,
212
+ color_icon_danger: PrimitiveColor.color_red_500,
213
+ color_icon_warning: PrimitiveColor.color_yellow_600
214
+ };
215
+ var _a, _b;
216
+ var Box = (_b = (_a = BoxRaw) == null ? void 0 : _a.default) != null ? _b : BoxRaw;
217
+ var SpacingToken = {
218
+ spacing0: "0px",
219
+ spacing1: "4px",
220
+ spacing2: "8px",
221
+ spacing3: "12px",
222
+ spacing4: "16px",
223
+ spacing5: "20px",
224
+ spacing6: "24px",
225
+ spacing7: "28px",
226
+ spacing8: "32px",
227
+ spacing9: "36px",
228
+ spacing10: "40px"
229
+ };
230
+ var CONTENT_SPACING_TOKENS = {
231
+ spacing_1: {
232
+ mobile: "8px",
233
+ tablet: "16px",
234
+ web: "24px"
235
+ },
236
+ spacing_2: {
237
+ mobile: "16px",
238
+ tablet: "24px",
239
+ web: "32px"
240
+ },
241
+ spacing_3: {
242
+ mobile: "24px",
243
+ tablet: "32px",
244
+ web: "40px"
245
+ }
246
+ };
247
+ var resolveSpacingValue = (value, tokens) => {
248
+ var _a10;
249
+ if (typeof value === "number") return `${value}px`;
250
+ if (typeof value === "string") return (_a10 = tokens[value]) != null ? _a10 : value;
251
+ return 0;
252
+ };
253
+ var Spacing = (_a10) => {
254
+ var _b10 = _a10, {
255
+ size = "spacing2",
256
+ axis = "vertical",
257
+ sx = {}
258
+ } = _b10, rest = __objRest(_b10, [
259
+ "size",
260
+ "axis",
261
+ "sx"
262
+ ]);
263
+ const value = resolveSpacingValue(size, SpacingToken);
264
+ return /* @__PURE__ */ jsx(
265
+ Box,
266
+ __spreadValues({
267
+ "aria-hidden": true,
268
+ sx: __spreadValues(__spreadValues({}, axis === "vertical" ? { height: value } : { width: value, display: "inline-block" }), sx)
269
+ }, rest)
270
+ );
271
+ };
272
+ var ContentSpacing = (_a10) => {
273
+ var _b10 = _a10, {
274
+ size = "spacing_2",
275
+ breakpoint = "web",
276
+ children,
277
+ sx = {}
278
+ } = _b10, rest = __objRest(_b10, [
279
+ "size",
280
+ "breakpoint",
281
+ "children",
282
+ "sx"
283
+ ]);
284
+ var _a11;
285
+ const token = typeof size === "string" ? CONTENT_SPACING_TOKENS[size] : size;
286
+ if (!token) return null;
287
+ const value = (_a11 = token[breakpoint]) != null ? _a11 : token.web;
288
+ return /* @__PURE__ */ jsx(
289
+ Box,
290
+ __spreadProps(__spreadValues({
291
+ sx: __spreadValues({
292
+ padding: value
293
+ }, sx)
294
+ }, rest), {
295
+ children
296
+ })
297
+ );
298
+ };
299
+ var spacing_default = Spacing;
300
+ var _a2, _b2;
301
+ var Box2 = (_b2 = (_a2 = BoxRaw) == null ? void 0 : _a2.default) != null ? _b2 : BoxRaw;
302
+ var ICON_MAP = {
303
+ grid: IconLayoutGrid,
304
+ document: IconFileText,
305
+ list: IconList,
306
+ user: IconUser,
307
+ settings: IconSettings
308
+ };
309
+ function getIcon(name) {
310
+ return ICON_MAP[name] || IconCircle;
311
+ }
312
+ var SIDEBAR_WIDTH_EXPANDED = 290;
313
+ var SIDEBAR_WIDTH_COLLAPSED = 90;
314
+ function AppSidebar({
315
+ menuItems = [],
316
+ currentPath = "",
317
+ logoText = "BRIspot",
318
+ onNavigate
319
+ }) {
320
+ const { isExpanded, isMobileOpen, isHovered, setIsHovered } = useSidebar();
321
+ const [openSubmenus, setOpenSubmenus] = useState({});
322
+ const [isDesktop, setIsDesktop] = useState(true);
323
+ useEffect(() => {
324
+ const mq = window.matchMedia("(min-width: 1024px)");
325
+ setIsDesktop(mq.matches);
326
+ const handler = (e) => setIsDesktop(e.matches);
327
+ mq.addEventListener("change", handler);
328
+ return () => mq.removeEventListener("change", handler);
329
+ }, []);
330
+ const isShowingLabels = isExpanded || isHovered || isMobileOpen;
331
+ const sidebarWidth = isShowingLabels ? SIDEBAR_WIDTH_EXPANDED : SIDEBAR_WIDTH_COLLAPSED;
332
+ const isActive = useCallback((path) => path === currentPath, [currentPath]);
333
+ useEffect(() => {
334
+ const newOpen = {};
335
+ menuItems.forEach((item, index) => {
336
+ var _a10;
337
+ if ((_a10 = item.subItems) == null ? void 0 : _a10.some((sub) => isActive(sub.path))) {
338
+ newOpen[index] = true;
339
+ }
340
+ });
341
+ setOpenSubmenus(newOpen);
342
+ }, [currentPath, menuItems, isActive]);
343
+ const handleSubmenuToggle = (index) => {
344
+ setOpenSubmenus((prev) => __spreadProps(__spreadValues({}, prev), { [index]: !prev[index] }));
345
+ };
346
+ const handleNavigation = (e, path) => {
347
+ if (onNavigate) {
348
+ e.preventDefault();
349
+ onNavigate(path);
350
+ }
351
+ };
352
+ return /* @__PURE__ */ jsxs(
353
+ Box2,
354
+ {
355
+ component: "aside",
356
+ onMouseEnter: () => !isExpanded && setIsHovered(true),
357
+ onMouseLeave: () => setIsHovered(false),
358
+ sx: {
359
+ position: "fixed",
360
+ top: 0,
361
+ left: 0,
362
+ height: "100vh",
363
+ width: sidebarWidth,
364
+ backgroundColor: DerivedColor.color_bg_surface,
365
+ borderRight: `1px solid ${DerivedColor.color_border_default}`,
366
+ transition: "all 300ms ease-in-out",
367
+ zIndex: 50,
368
+ display: "flex",
369
+ flexDirection: "column",
370
+ overflowX: "hidden",
371
+ transform: isDesktop ? "translateX(0)" : isMobileOpen ? "translateX(0)" : "translateX(-100%)"
372
+ },
373
+ children: [
374
+ /* @__PURE__ */ jsx(
375
+ Box2,
376
+ {
377
+ sx: {
378
+ display: "flex",
379
+ alignItems: "center",
380
+ height: "64px",
381
+ px: SpacingToken.spacing5,
382
+ justifyContent: isShowingLabels ? "flex-start" : "center",
383
+ borderBottom: `1px solid ${DerivedColor.color_border_default}`
384
+ },
385
+ children: /* @__PURE__ */ jsx(
386
+ Box2,
387
+ {
388
+ component: "a",
389
+ href: "/",
390
+ onClick: (e) => handleNavigation(e, "/"),
391
+ sx: {
392
+ textDecoration: "none",
393
+ color: DerivedColor.color_text_brand_primary,
394
+ fontWeight: 700,
395
+ fontSize: "18px"
396
+ },
397
+ children: isShowingLabels ? logoText : logoText.charAt(0)
398
+ }
399
+ )
400
+ }
401
+ ),
402
+ /* @__PURE__ */ jsx(Box2, { sx: { flex: 1, overflowY: "auto", px: SpacingToken.spacing2, py: SpacingToken.spacing4 }, children: menuItems.map((item, index) => {
403
+ var _a10;
404
+ const Icon = getIcon(item.icon);
405
+ const hasSubItems = item.subItems && item.subItems.length > 0;
406
+ const isItemActive = item.path ? isActive(item.path) : (_a10 = item.subItems) == null ? void 0 : _a10.some((sub) => isActive(sub.path));
407
+ return /* @__PURE__ */ jsx(Box2, { sx: { mb: "4px" }, children: hasSubItems ? /* @__PURE__ */ jsxs(Fragment, { children: [
408
+ /* @__PURE__ */ jsxs(
409
+ Box2,
410
+ {
411
+ component: "button",
412
+ onClick: () => handleSubmenuToggle(index),
413
+ sx: {
414
+ width: "100%",
415
+ display: "flex",
416
+ alignItems: "center",
417
+ gap: SpacingToken.spacing3,
418
+ px: SpacingToken.spacing3,
419
+ py: SpacingToken.spacing2,
420
+ borderRadius: "8px",
421
+ border: "none",
422
+ cursor: "pointer",
423
+ backgroundColor: isItemActive ? DerivedColor.color_bg_brand_primary_subtle : "transparent",
424
+ color: isItemActive ? DerivedColor.color_text_brand_primary : DerivedColor.color_text_subtle,
425
+ justifyContent: isShowingLabels ? "flex-start" : "center",
426
+ transition: "background-color 200ms",
427
+ "&:hover": {
428
+ backgroundColor: isItemActive ? DerivedColor.color_bg_brand_primary_subtle : "rgba(0, 0, 0, 0.04)"
429
+ }
430
+ },
431
+ children: [
432
+ /* @__PURE__ */ jsx(
433
+ Icon,
434
+ {
435
+ size: 20,
436
+ color: isItemActive ? DerivedColor.color_icon_brand_primary : DerivedColor.color_icon_subtle
437
+ }
438
+ ),
439
+ isShowingLabels && /* @__PURE__ */ jsxs(Fragment, { children: [
440
+ /* @__PURE__ */ jsx(
441
+ Box2,
442
+ {
443
+ component: "span",
444
+ sx: {
445
+ flex: 1,
446
+ textAlign: "left",
447
+ fontSize: "14px",
448
+ fontWeight: 500
449
+ },
450
+ children: item.name
451
+ }
452
+ ),
453
+ /* @__PURE__ */ jsx(
454
+ IconChevronDown,
455
+ {
456
+ size: 16,
457
+ style: {
458
+ transition: "transform 200ms",
459
+ transform: openSubmenus[index] ? "rotate(180deg)" : "rotate(0deg)"
460
+ }
461
+ }
462
+ )
463
+ ] })
464
+ ]
465
+ }
466
+ ),
467
+ /* @__PURE__ */ jsx(
468
+ SubMenu,
469
+ {
470
+ isOpen: isShowingLabels && !!openSubmenus[index],
471
+ subItems: item.subItems,
472
+ isActive,
473
+ onNavigate
474
+ }
475
+ )
476
+ ] }) : item.path && /* @__PURE__ */ jsxs(
477
+ Box2,
478
+ {
479
+ component: "a",
480
+ href: item.path,
481
+ onClick: (e) => handleNavigation(e, item.path),
482
+ sx: {
483
+ display: "flex",
484
+ alignItems: "center",
485
+ gap: SpacingToken.spacing3,
486
+ px: SpacingToken.spacing3,
487
+ py: SpacingToken.spacing2,
488
+ borderRadius: "8px",
489
+ textDecoration: "none",
490
+ justifyContent: isShowingLabels ? "flex-start" : "center",
491
+ backgroundColor: isActive(item.path) ? DerivedColor.color_bg_brand_primary_subtle : "transparent",
492
+ color: isActive(item.path) ? DerivedColor.color_text_brand_primary : DerivedColor.color_text_subtle,
493
+ transition: "background-color 200ms",
494
+ "&:hover": {
495
+ backgroundColor: isActive(item.path) ? DerivedColor.color_bg_brand_primary_subtle : "rgba(0, 0, 0, 0.04)"
496
+ }
497
+ },
498
+ children: [
499
+ /* @__PURE__ */ jsx(
500
+ Icon,
501
+ {
502
+ size: 20,
503
+ color: isActive(item.path) ? DerivedColor.color_icon_brand_primary : DerivedColor.color_icon_subtle
504
+ }
505
+ ),
506
+ isShowingLabels && /* @__PURE__ */ jsx(
507
+ Box2,
508
+ {
509
+ component: "span",
510
+ sx: { fontSize: "14px", fontWeight: 500 },
511
+ children: item.name
512
+ }
513
+ )
514
+ ]
515
+ }
516
+ ) }, `${item.name}-${index}`);
517
+ }) })
518
+ ]
519
+ }
520
+ );
521
+ }
522
+ function SubMenu({ isOpen, subItems, isActive, onNavigate }) {
523
+ const contentRef = useRef(null);
524
+ const [height, setHeight] = useState(0);
525
+ useEffect(() => {
526
+ if (isOpen && contentRef.current) {
527
+ setHeight(contentRef.current.scrollHeight);
528
+ } else {
529
+ setHeight(0);
530
+ }
531
+ }, [isOpen, subItems]);
532
+ const handleNavigation = (e, path) => {
533
+ if (onNavigate) {
534
+ e.preventDefault();
535
+ onNavigate(path);
536
+ }
537
+ };
538
+ return /* @__PURE__ */ jsx(
539
+ Box2,
540
+ {
541
+ sx: {
542
+ overflow: "hidden",
543
+ transition: "height 300ms ease-in-out",
544
+ height: `${height}px`
545
+ },
546
+ children: /* @__PURE__ */ jsx(Box2, { ref: contentRef, sx: { pl: "44px", mt: "4px" }, children: subItems.map((subItem) => /* @__PURE__ */ jsx(
547
+ Box2,
548
+ {
549
+ component: "a",
550
+ href: subItem.path,
551
+ onClick: (e) => handleNavigation(e, subItem.path),
552
+ sx: {
553
+ display: "block",
554
+ px: SpacingToken.spacing3,
555
+ py: "6px",
556
+ borderRadius: "6px",
557
+ textDecoration: "none",
558
+ fontSize: "13px",
559
+ fontWeight: isActive(subItem.path) ? 500 : 400,
560
+ color: isActive(subItem.path) ? DerivedColor.color_text_brand_primary : DerivedColor.color_text_subtle,
561
+ "&:hover": {
562
+ color: DerivedColor.color_text_default
563
+ }
564
+ },
565
+ children: subItem.name
566
+ },
567
+ subItem.path
568
+ )) })
569
+ }
570
+ );
571
+ }
572
+ var _a3, _b3;
573
+ var Box3 = (_b3 = (_a3 = BoxRaw) == null ? void 0 : _a3.default) != null ? _b3 : BoxRaw;
574
+ var _a4, _b4;
575
+ var IconButton = (_b4 = (_a4 = IconButtonRaw) == null ? void 0 : _a4.default) != null ? _b4 : IconButtonRaw;
576
+ var _a5, _b5;
577
+ var Menu = (_b5 = (_a5 = MenuRaw) == null ? void 0 : _a5.default) != null ? _b5 : MenuRaw;
578
+ var _a6, _b6;
579
+ var MenuItem = (_b6 = (_a6 = MenuItemRaw) == null ? void 0 : _a6.default) != null ? _b6 : MenuItemRaw;
580
+ var _a7, _b7;
581
+ var Typography = (_b7 = (_a7 = TypographyRaw) == null ? void 0 : _a7.default) != null ? _b7 : TypographyRaw;
582
+ var SIDEBAR_WIDTH_EXPANDED2 = 290;
583
+ var SIDEBAR_WIDTH_COLLAPSED2 = 90;
584
+ function AppHeader({ username, fullname, logoSrc, onLogout, onNavigate }) {
585
+ const { isExpanded, isHovered, toggleSidebar, toggleMobileSidebar } = useSidebar();
586
+ const [anchorEl, setAnchorEl] = useState(null);
587
+ const [isMobile, setIsMobile] = useState(false);
588
+ useEffect(() => {
589
+ const mq = window.matchMedia("(min-width: 1024px)");
590
+ setIsMobile(!mq.matches);
591
+ const handler = (e) => setIsMobile(!e.matches);
592
+ mq.addEventListener("change", handler);
593
+ return () => mq.removeEventListener("change", handler);
594
+ }, []);
595
+ const handleToggle = () => {
596
+ if (window.innerWidth >= 1024) toggleSidebar();
597
+ else toggleMobileSidebar();
598
+ };
599
+ const handleLogout = () => {
600
+ setAnchorEl(null);
601
+ if (onLogout) onLogout();
602
+ };
603
+ const marginLeft = isMobile ? 0 : isExpanded || isHovered ? SIDEBAR_WIDTH_EXPANDED2 : SIDEBAR_WIDTH_COLLAPSED2;
604
+ return /* @__PURE__ */ jsx(
605
+ Box3,
606
+ {
607
+ component: "header",
608
+ sx: {
609
+ position: "sticky",
610
+ top: 0,
611
+ zIndex: 30,
612
+ display: "flex",
613
+ alignItems: "center",
614
+ height: "64px",
615
+ borderBottom: `1px solid ${DerivedColor.color_border_default}`,
616
+ backgroundColor: DerivedColor.color_bg_surface,
617
+ px: { xs: "16px", lg: "24px" },
618
+ transition: "margin-left 300ms",
619
+ marginLeft: `${marginLeft}px`
620
+ },
621
+ children: /* @__PURE__ */ jsxs(
622
+ Box3,
623
+ {
624
+ sx: {
625
+ display: "flex",
626
+ width: "100%",
627
+ alignItems: "center",
628
+ justifyContent: "space-between"
629
+ },
630
+ children: [
631
+ /* @__PURE__ */ jsxs(Box3, { sx: { display: "flex", alignItems: "center", gap: "12px" }, children: [
632
+ /* @__PURE__ */ jsx(
633
+ IconButton,
634
+ {
635
+ onClick: handleToggle,
636
+ sx: {
637
+ border: `1px solid ${DerivedColor.color_border_default}`,
638
+ borderRadius: "8px",
639
+ width: 40,
640
+ height: 40
641
+ },
642
+ children: /* @__PURE__ */ jsx(IconMenu2, { size: 20 })
643
+ }
644
+ ),
645
+ isMobile && logoSrc && /* @__PURE__ */ jsx(Box3, { component: "img", src: logoSrc, alt: "Logo", sx: { height: 32 } })
646
+ ] }),
647
+ /* @__PURE__ */ jsxs(Box3, { children: [
648
+ /* @__PURE__ */ jsxs(
649
+ IconButton,
650
+ {
651
+ onClick: (e) => setAnchorEl(e.currentTarget),
652
+ sx: { borderRadius: "8px", px: "12px", py: "8px", gap: "8px" },
653
+ children: [
654
+ /* @__PURE__ */ jsx(IconUser, { size: 20 }),
655
+ /* @__PURE__ */ jsx(
656
+ Typography,
657
+ {
658
+ component: "span",
659
+ sx: {
660
+ display: { xs: "none", lg: "inline" },
661
+ fontWeight: 500,
662
+ fontSize: "14px",
663
+ color: DerivedColor.color_text_default
664
+ },
665
+ children: fullname || username || "User"
666
+ }
667
+ )
668
+ ]
669
+ }
670
+ ),
671
+ /* @__PURE__ */ jsxs(
672
+ Menu,
673
+ {
674
+ anchorEl,
675
+ open: Boolean(anchorEl),
676
+ onClose: () => setAnchorEl(null),
677
+ slotProps: { paper: { sx: { width: 220, mt: 1 } } },
678
+ children: [
679
+ /* @__PURE__ */ jsxs(
680
+ Box3,
681
+ {
682
+ sx: {
683
+ px: "16px",
684
+ py: "8px",
685
+ borderBottom: `1px solid ${DerivedColor.color_border_default}`
686
+ },
687
+ children: [
688
+ /* @__PURE__ */ jsx(Typography, { sx: { fontSize: "14px", fontWeight: 500 }, children: fullname || "User" }),
689
+ username && /* @__PURE__ */ jsx(Typography, { sx: { fontSize: "12px", color: DerivedColor.color_text_subtle }, children: username })
690
+ ]
691
+ }
692
+ ),
693
+ /* @__PURE__ */ jsxs(MenuItem, { onClick: handleLogout, sx: { gap: "8px" }, children: [
694
+ /* @__PURE__ */ jsx(IconLogout, { size: 16 }),
695
+ "Logout"
696
+ ] })
697
+ ]
698
+ }
699
+ )
700
+ ] })
701
+ ]
702
+ }
703
+ )
704
+ }
705
+ );
706
+ }
707
+ var _a8, _b8;
708
+ var Box4 = (_b8 = (_a8 = BoxRaw) == null ? void 0 : _a8.default) != null ? _b8 : BoxRaw;
709
+ function Backdrop({ onClick }) {
710
+ const { isMobileOpen, toggleMobileSidebar } = useSidebar();
711
+ const handleClick = useCallback(() => {
712
+ if (onClick) onClick();
713
+ else toggleMobileSidebar();
714
+ }, [onClick, toggleMobileSidebar]);
715
+ return /* @__PURE__ */ jsx(
716
+ Box4,
717
+ {
718
+ onClick: handleClick,
719
+ "aria-hidden": "true",
720
+ sx: {
721
+ position: "fixed",
722
+ inset: 0,
723
+ zIndex: 40,
724
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
725
+ transition: "opacity 300ms",
726
+ opacity: isMobileOpen ? 1 : 0,
727
+ pointerEvents: isMobileOpen ? "auto" : "none",
728
+ display: { xs: "block", lg: "none" }
729
+ }
730
+ }
731
+ );
732
+ }
733
+ var _a9, _b9;
734
+ var Box5 = (_b9 = (_a9 = BoxRaw) == null ? void 0 : _a9.default) != null ? _b9 : BoxRaw;
735
+ var SIDEBAR_WIDTH_EXPANDED3 = 290;
736
+ var SIDEBAR_WIDTH_COLLAPSED3 = 90;
737
+ function LayoutShell({
738
+ menuItems = [],
739
+ username,
740
+ fullname,
741
+ currentPath = "",
742
+ excludedRoutes = ["/login", "/403"],
743
+ logoText = "BRIspot",
744
+ logoSrc,
745
+ onLogout,
746
+ onNavigate,
747
+ children
748
+ }) {
749
+ const { isExpanded, isHovered } = useSidebar();
750
+ const [isMobile, setIsMobile] = useState(false);
751
+ useEffect(() => {
752
+ const mq = window.matchMedia("(min-width: 1024px)");
753
+ setIsMobile(!mq.matches);
754
+ const handler = (e) => setIsMobile(!e.matches);
755
+ mq.addEventListener("change", handler);
756
+ return () => mq.removeEventListener("change", handler);
757
+ }, []);
758
+ const isExcluded = excludedRoutes.some(
759
+ (route) => currentPath === route || currentPath.startsWith(`${route}/`)
760
+ );
761
+ if (isExcluded) return /* @__PURE__ */ jsx(Fragment, { children });
762
+ const marginLeft = isMobile ? 0 : isExpanded || isHovered ? SIDEBAR_WIDTH_EXPANDED3 : SIDEBAR_WIDTH_COLLAPSED3;
763
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
764
+ /* @__PURE__ */ jsx(
765
+ AppSidebar,
766
+ {
767
+ menuItems,
768
+ currentPath,
769
+ logoText,
770
+ onNavigate
771
+ }
772
+ ),
773
+ /* @__PURE__ */ jsx(
774
+ AppHeader,
775
+ {
776
+ username,
777
+ fullname,
778
+ logoSrc,
779
+ onLogout,
780
+ onNavigate
781
+ }
782
+ ),
783
+ /* @__PURE__ */ jsx(Backdrop, {}),
784
+ /* @__PURE__ */ jsx(
785
+ Box5,
786
+ {
787
+ component: "main",
788
+ sx: {
789
+ transition: "margin-left 300ms",
790
+ marginLeft: `${marginLeft}px`
791
+ },
792
+ children
793
+ }
794
+ )
795
+ ] });
796
+ }
797
+ function safeDecrypt(encryptedText, secretKey) {
798
+ try {
799
+ const bytes = AES.decrypt(encryptedText, secretKey);
800
+ const result = bytes.toString(CryptoJS.enc.Utf8);
801
+ return result || null;
802
+ } catch (e) {
803
+ return null;
804
+ }
805
+ }
806
+ function parseAccessMenu(encryptedValue, secretKey) {
807
+ if (!encryptedValue) return [];
808
+ const decrypted = safeDecrypt(encryptedValue, secretKey);
809
+ if (!decrypted) return [];
810
+ let raw;
811
+ try {
812
+ raw = JSON.parse(decrypted);
813
+ } catch (e) {
814
+ return [];
815
+ }
816
+ if (!(raw == null ? void 0 : raw.menu) || !Array.isArray(raw.menu)) return [];
817
+ return raw.menu.map((item) => {
818
+ var _a10;
819
+ const menuItem = { name: item.menu_name, icon: (_a10 = item.menu_icon) != null ? _a10 : "" };
820
+ if (item.menu_url) menuItem.path = item.menu_url;
821
+ if (item.sub_menu && Array.isArray(item.sub_menu)) {
822
+ menuItem.subItems = item.sub_menu.map((sub) => ({
823
+ name: sub.menu_name,
824
+ path: sub.menu_url,
825
+ icon: sub.menu_icon
826
+ }));
827
+ }
828
+ return menuItem;
829
+ });
830
+ }
831
+
832
+ export { AppHeader, AppSidebar, Backdrop, CONTENT_SPACING_TOKENS, ContentSpacing, DerivedColor, LayoutShell, PrimitiveColor, SidebarProvider, SpacingToken, parseAccessMenu, spacing_default, useSidebar };
833
+ //# sourceMappingURL=chunk-G2BF4U5I.mjs.map
834
+ //# sourceMappingURL=chunk-G2BF4U5I.mjs.map