@gofreego/tsutils 0.1.13 → 0.1.15

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 CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var react = require('react');
4
3
  var material = require('@mui/material');
5
4
  var iconsMaterial = require('@mui/icons-material');
6
5
  var reactRouterDom = require('react-router-dom');
6
+ var react = require('react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
8
  var ReactMarkdown = require('react-markdown');
9
9
  var remarkGfm = require('remark-gfm');
@@ -30,687 +30,99 @@ var __export = (target, all) => {
30
30
  for (var name in all)
31
31
  __defProp(target, name, { get: all[name], enumerable: true });
32
32
  };
33
- var RouterMenuItem = ({ item, depth = 0, expanded, onToggle }) => {
34
- const hasChildren = item.children && item.children.length > 0;
35
- const isExpanded = expanded.has(item.id);
36
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
37
- /* @__PURE__ */ jsxRuntime.jsx(material.ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
38
- material.ListItemButton,
39
- {
40
- component: hasChildren ? "div" : reactRouterDom.NavLink,
41
- to: !hasChildren ? item.path || `/${item.id}` : void 0,
42
- end: false,
43
- onClick: hasChildren ? () => onToggle(item.id) : void 0,
44
- sx: {
45
- pl: 2 + depth * 2,
46
- "&.active": {
47
- backgroundColor: "action.selected",
48
- color: "primary.main",
49
- borderLeft: 3,
50
- borderColor: "primary.main",
51
- fontWeight: "medium",
52
- "& .MuiListItemIcon-root": {
53
- color: "primary.main"
54
- }
55
- },
56
- "&:hover": {
57
- backgroundColor: "action.hover"
58
- },
59
- transition: "all 0.15s"
60
- },
61
- children: [
62
- item.icon && /* @__PURE__ */ jsxRuntime.jsx(material.ListItemIcon, { sx: { minWidth: 40 }, children: item.icon }),
63
- /* @__PURE__ */ jsxRuntime.jsx(
64
- material.ListItemText,
65
- {
66
- primary: item.label,
67
- primaryTypographyProps: {
68
- fontSize: "0.875rem"
69
- }
70
- }
71
- ),
72
- hasChildren && /* @__PURE__ */ jsxRuntime.jsx(material.IconButton, { size: "small", sx: { p: 0 }, children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.ExpandLess, {}) : /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.ExpandMore, {}) })
73
- ]
74
- }
75
- ) }),
76
- hasChildren && /* @__PURE__ */ jsxRuntime.jsx(material.Collapse, { in: isExpanded, timeout: "auto", unmountOnExit: true, children: /* @__PURE__ */ jsxRuntime.jsx(material.List, { component: "div", disablePadding: true, children: item.children.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
77
- RouterMenuItem,
78
- {
79
- item: child,
80
- depth: depth + 1,
81
- expanded,
82
- onToggle
83
- },
84
- child.id
85
- )) }) })
86
- ] });
33
+
34
+ // src/theme/tokens.ts
35
+ var tokens_exports = {};
36
+ __export(tokens_exports, {
37
+ borderRadius: () => borderRadius,
38
+ elevation: () => elevation,
39
+ fontSize: () => fontSize,
40
+ fontWeight: () => fontWeight,
41
+ lineHeight: () => lineHeight,
42
+ spacing: () => spacing,
43
+ transition: () => transition,
44
+ zIndex: () => zIndex
45
+ });
46
+ var spacing = {
47
+ xs: "0.25rem",
48
+ // 4px
49
+ sm: "0.5rem",
50
+ // 8px
51
+ md: "1rem",
52
+ // 16px
53
+ lg: "1.5rem",
54
+ // 24px
55
+ xl: "2rem",
56
+ // 32px
57
+ "2xl": "3rem",
58
+ // 48px
59
+ "3xl": "4rem"
60
+ // 64px
87
61
  };
88
- var flattenMenuRoutes = (items) => {
89
- const routes = [];
90
- const flatten = (menuItems) => {
91
- for (const item of menuItems) {
92
- if (item.path && item.component) {
93
- routes.push({ path: item.path, component: item.component });
94
- }
95
- if (item.children) {
96
- flatten(item.children);
97
- }
98
- }
99
- };
100
- flatten(items);
101
- return routes;
62
+ var borderRadius = {
63
+ none: "0",
64
+ sm: "0.25rem",
65
+ // 4px
66
+ md: "0.375rem",
67
+ // 6px
68
+ lg: "0.5rem",
69
+ // 8px
70
+ xl: "0.75rem",
71
+ // 12px
72
+ "2xl": "1rem",
73
+ // 16px
74
+ full: "9999px"
102
75
  };
103
- var SidebarLayoutRouterInner = ({
104
- menuItems,
105
- sidebarWidth = 250,
106
- className = "",
107
- onMenuChange,
108
- style,
109
- sidebarStyle,
110
- bodyStyle,
111
- defaultExpanded = []
112
- }) => {
113
- const location = reactRouterDom.useLocation();
114
- const [expanded, setExpanded] = react.useState(new Set(defaultExpanded));
115
- const handleToggle = (id) => {
116
- setExpanded((prev) => {
117
- const next = new Set(prev);
118
- if (next.has(id)) {
119
- next.delete(id);
120
- } else {
121
- next.add(id);
122
- }
123
- return next;
124
- });
125
- };
126
- react.useEffect(() => {
127
- if (onMenuChange) {
128
- const findActiveItem = (items) => {
129
- for (const item of items) {
130
- if (item.path && location.pathname === item.path) {
131
- return item;
132
- }
133
- if (item.children) {
134
- const found = findActiveItem(item.children);
135
- if (found) return found;
136
- }
137
- }
138
- return void 0;
139
- };
140
- const activeItem = findActiveItem(menuItems);
141
- if (activeItem) {
142
- onMenuChange(activeItem.id);
143
- }
144
- }
145
- }, [location.pathname, menuItems, onMenuChange]);
146
- const hasComponents = menuItems.some(
147
- (item) => item.component || item.children?.some((child) => child.component)
148
- );
149
- const routes = hasComponents ? flattenMenuRoutes(menuItems) : [];
150
- return /* @__PURE__ */ jsxRuntime.jsxs(
151
- material.Box,
152
- {
153
- className,
154
- sx: {
155
- display: "flex",
156
- height: "100%",
157
- width: "100%",
158
- ...style
159
- },
160
- children: [
161
- /* @__PURE__ */ jsxRuntime.jsx(
162
- material.Drawer,
163
- {
164
- variant: "permanent",
165
- sx: {
166
- width: sidebarWidth,
167
- flexShrink: 0,
168
- "& .MuiDrawer-paper": {
169
- width: sidebarWidth,
170
- boxSizing: "border-box",
171
- position: "relative",
172
- borderRight: "1px solid",
173
- borderColor: "divider",
174
- ...sidebarStyle
175
- }
176
- },
177
- children: /* @__PURE__ */ jsxRuntime.jsx(material.List, { sx: { p: 0 }, children: menuItems.filter((item) => item.label).map((item) => /* @__PURE__ */ jsxRuntime.jsx(
178
- RouterMenuItem,
179
- {
180
- item,
181
- expanded,
182
- onToggle: handleToggle
183
- },
184
- item.id
185
- )) })
186
- }
187
- ),
188
- /* @__PURE__ */ jsxRuntime.jsx(
189
- material.Box,
190
- {
191
- component: "main",
192
- sx: {
193
- flexGrow: 1,
194
- overflow: "auto",
195
- ...bodyStyle
196
- },
197
- children: hasComponents ? /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Routes, { children: routes.map(({ path, component }) => /* @__PURE__ */ jsxRuntime.jsx(
198
- reactRouterDom.Route,
199
- {
200
- path,
201
- element: component
202
- },
203
- path
204
- )) }) : /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Outlet, {})
205
- }
206
- )
207
- ]
208
- }
209
- );
76
+ var fontSize = {
77
+ xs: "0.75rem",
78
+ // 12px
79
+ sm: "0.875rem",
80
+ // 14px
81
+ md: "1rem",
82
+ // 16px
83
+ lg: "1.125rem",
84
+ // 18px
85
+ xl: "1.25rem",
86
+ // 20px
87
+ "2xl": "1.5rem",
88
+ // 24px
89
+ "3xl": "1.875rem",
90
+ // 30px
91
+ "4xl": "2.25rem"
92
+ // 36px
210
93
  };
211
- var SidebarLayoutWithRouter = (props) => {
212
- return (
213
- // @ts-expect-error - future prop exists in v6 for v7 migration, but is removed from v7 types
214
- /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.BrowserRouter, { future: { v7_startTransition: true, v7_relativeSplatPath: true }, children: /* @__PURE__ */ jsxRuntime.jsx(SidebarLayoutRouterInner, { ...props }) })
215
- );
94
+ var fontWeight = {
95
+ light: "300",
96
+ normal: "400",
97
+ medium: "500",
98
+ semibold: "600",
99
+ bold: "700"
216
100
  };
217
- var StateMenuItem = ({ item, selectedId, depth = 0, expanded, onToggle, onClick }) => {
218
- const hasChildren = item.children && item.children.length > 0;
219
- const isExpanded = expanded.has(item.id);
220
- const isActive = item.id === selectedId;
221
- const handleClick = () => {
222
- if (hasChildren) {
223
- onToggle(item.id);
224
- } else {
225
- onClick(item.id);
226
- }
227
- };
228
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
229
- /* @__PURE__ */ jsxRuntime.jsx(material.ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
230
- material.ListItemButton,
231
- {
232
- selected: isActive,
233
- onClick: handleClick,
234
- sx: {
235
- pl: 2 + depth * 2,
236
- "&.Mui-selected": {
237
- backgroundColor: "action.selected",
238
- color: "primary.main",
239
- borderLeft: 3,
240
- borderColor: "primary.main",
241
- fontWeight: "medium",
242
- "& .MuiListItemIcon-root": {
243
- color: "primary.main"
244
- },
245
- "&:hover": {
246
- backgroundColor: "action.selected"
247
- }
248
- },
249
- "&:hover": {
250
- backgroundColor: "action.hover"
251
- },
252
- transition: "all 0.15s"
253
- },
254
- children: [
255
- item.icon && /* @__PURE__ */ jsxRuntime.jsx(material.ListItemIcon, { sx: { minWidth: 40 }, children: item.icon }),
256
- /* @__PURE__ */ jsxRuntime.jsx(
257
- material.ListItemText,
258
- {
259
- primary: item.label,
260
- primaryTypographyProps: {
261
- fontSize: "0.875rem"
262
- }
263
- }
264
- ),
265
- hasChildren && /* @__PURE__ */ jsxRuntime.jsx(material.IconButton, { size: "small", sx: { p: 0 }, children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.ExpandLess, {}) : /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.ExpandMore, {}) })
266
- ]
267
- }
268
- ) }),
269
- hasChildren && /* @__PURE__ */ jsxRuntime.jsx(material.Collapse, { in: isExpanded, timeout: "auto", unmountOnExit: true, children: /* @__PURE__ */ jsxRuntime.jsx(material.List, { component: "div", disablePadding: true, children: item.children.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
270
- StateMenuItem,
271
- {
272
- item: child,
273
- selectedId,
274
- depth: depth + 1,
275
- expanded,
276
- onToggle,
277
- onClick
278
- },
279
- child.id
280
- )) }) })
281
- ] });
101
+ var lineHeight = {
102
+ tight: "1.25",
103
+ normal: "1.5",
104
+ relaxed: "1.75"
282
105
  };
283
- var SidebarLayoutWithState = ({
284
- menuItems,
285
- sidebarWidth = 250,
286
- className = "",
287
- defaultSelected,
288
- onMenuChange,
289
- style,
290
- sidebarStyle,
291
- bodyStyle,
292
- defaultExpanded = []
293
- }) => {
294
- const [selectedId, setSelectedId] = react.useState(
295
- defaultSelected || menuItems[0]?.id
296
- );
297
- const [expanded, setExpanded] = react.useState(new Set(defaultExpanded));
298
- const handleToggle = (id) => {
299
- setExpanded((prev) => {
300
- const next = new Set(prev);
301
- if (next.has(id)) {
302
- next.delete(id);
303
- } else {
304
- next.add(id);
305
- }
306
- return next;
307
- });
308
- };
309
- const handleMenuClick = (id) => {
310
- setSelectedId(id);
311
- if (onMenuChange) {
312
- onMenuChange(id);
313
- }
314
- };
315
- const findActiveItem = (items, id) => {
316
- for (const item of items) {
317
- if (item.id === id) return item;
318
- if (item.children) {
319
- const found = findActiveItem(item.children, id);
320
- if (found) return found;
321
- }
322
- }
323
- return void 0;
324
- };
325
- const activeItem = findActiveItem(menuItems, selectedId);
326
- return /* @__PURE__ */ jsxRuntime.jsxs(
327
- material.Box,
328
- {
329
- className,
330
- sx: {
331
- display: "flex",
332
- height: "100%",
333
- width: "100%",
334
- ...style
335
- },
336
- children: [
337
- /* @__PURE__ */ jsxRuntime.jsx(
338
- material.Drawer,
339
- {
340
- variant: "permanent",
341
- sx: {
342
- width: sidebarWidth,
343
- flexShrink: 0,
344
- "& .MuiDrawer-paper": {
345
- width: sidebarWidth,
346
- boxSizing: "border-box",
347
- position: "relative",
348
- borderRight: "1px solid",
349
- borderColor: "divider",
350
- ...sidebarStyle
351
- }
352
- },
353
- children: /* @__PURE__ */ jsxRuntime.jsx(material.List, { sx: { p: 0 }, children: menuItems.filter((item) => item.label).map((item) => /* @__PURE__ */ jsxRuntime.jsx(
354
- StateMenuItem,
355
- {
356
- item,
357
- selectedId,
358
- expanded,
359
- onToggle: handleToggle,
360
- onClick: handleMenuClick
361
- },
362
- item.id
363
- )) })
364
- }
365
- ),
366
- /* @__PURE__ */ jsxRuntime.jsx(
367
- material.Box,
368
- {
369
- component: "main",
370
- sx: {
371
- flexGrow: 1,
372
- overflow: "auto",
373
- p: 3,
374
- ...bodyStyle
375
- },
376
- children: activeItem?.component || /* @__PURE__ */ jsxRuntime.jsx(
377
- material.Typography,
378
- {
379
- variant: "body2",
380
- color: "text.secondary",
381
- sx: { textAlign: "center", mt: 4 },
382
- children: "No content available for this menu item"
383
- }
384
- )
385
- }
386
- )
387
- ]
388
- }
389
- );
106
+ var elevation = {
107
+ none: "none",
108
+ sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
109
+ md: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
110
+ lg: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
111
+ xl: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)"
390
112
  };
391
- var SidebarLayout = (props) => {
392
- if (props.isRouter) {
393
- return /* @__PURE__ */ jsxRuntime.jsx(SidebarLayoutWithRouter, { ...props });
394
- }
395
- return /* @__PURE__ */ jsxRuntime.jsx(SidebarLayoutWithState, { ...props });
113
+ var transition = {
114
+ fast: "150ms",
115
+ normal: "250ms",
116
+ slow: "350ms"
396
117
  };
397
- var highlighterInstance = null;
398
- var highlighterPromise = null;
399
- var getHighlighter = async () => {
400
- if (highlighterInstance) {
401
- return highlighterInstance;
402
- }
403
- if (highlighterPromise) {
404
- return highlighterPromise;
405
- }
406
- highlighterPromise = shiki.createHighlighter({
407
- themes: ["github-light", "github-dark"],
408
- langs: ["js", "ts", "go", "json", "bash", "yaml", "md", "python", "java", "cpp", "c", "html", "css", "sql", "http", "text"]
409
- }).then((highlighter) => {
410
- highlighterInstance = highlighter;
411
- return highlighter;
412
- });
413
- return highlighterPromise;
414
- };
415
- var ReadmeViewer = ({
416
- content,
417
- className = "",
418
- isDark: propIsDark,
419
- muiTheme
420
- }) => {
421
- const isDark = propIsDark !== void 0 ? propIsDark : muiTheme?.palette?.mode === "dark";
422
- const [highlighter, setHighlighter] = react.useState(null);
423
- const [copiedBlocks, setCopiedBlocks] = react.useState(/* @__PURE__ */ new Set());
424
- react.useEffect(() => {
425
- getHighlighter().then(setHighlighter);
426
- }, []);
427
- const copyToClipboard = async (text, blockId) => {
428
- try {
429
- await navigator.clipboard.writeText(text);
430
- setCopiedBlocks((prev) => new Set(prev).add(blockId));
431
- setTimeout(() => {
432
- setCopiedBlocks((prev) => {
433
- const newSet = new Set(prev);
434
- newSet.delete(blockId);
435
- return newSet;
436
- });
437
- }, 2e3);
438
- } catch (err) {
439
- console.error("Failed to copy text: ", err);
440
- }
441
- };
442
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `readme-viewer markdown-body ${className}`, children: [
443
- /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
444
- .shiki-wrapper pre.shiki {
445
- padding: 16px !important;
446
- border-radius: 8px !important;
447
- overflow-x: auto;
448
- margin-bottom: 16px;
449
- border: 1px solid var(--md-sys-color-outline-variant, #e0e0e0);
450
- }
451
- ` }),
452
- /* @__PURE__ */ jsxRuntime.jsx(
453
- ReactMarkdown__default.default,
454
- {
455
- remarkPlugins: [remarkGfm__default.default, remarkMath__default.default],
456
- rehypePlugins: [rehypeKatex__default.default],
457
- components: {
458
- code({ className: className2, children, ...props }) {
459
- const match = /language-(\w+)/.exec(className2 || "");
460
- if (match && highlighter) {
461
- const codeText = String(children).replace(/\n$/, "");
462
- const blockId = `code-${Math.random().toString(36).substr(2, 9)}`;
463
- let highlightedHtml = "";
464
- try {
465
- highlightedHtml = highlighter.codeToHtml(codeText, {
466
- lang: match[1],
467
- theme: isDark ? "github-dark" : "github-light"
468
- });
469
- } catch (e) {
470
- try {
471
- highlightedHtml = highlighter.codeToHtml(codeText, {
472
- lang: "text",
473
- theme: isDark ? "github-dark" : "github-light"
474
- });
475
- } catch (fallbackError) {
476
- highlightedHtml = `<pre><code>${codeText}</code></pre>`;
477
- }
478
- }
479
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
480
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shiki-wrapper", dangerouslySetInnerHTML: { __html: highlightedHtml } }),
481
- /* @__PURE__ */ jsxRuntime.jsx(
482
- "button",
483
- {
484
- onClick: () => copyToClipboard(codeText, blockId),
485
- style: {
486
- position: "absolute",
487
- top: "8px",
488
- right: "8px",
489
- backgroundColor: "var(--md-sys-color-surface-container-high)",
490
- border: "1px solid var(--md-sys-color-outline-variant)",
491
- borderRadius: "4px",
492
- padding: "6px",
493
- fontSize: "14px",
494
- cursor: "pointer",
495
- color: "var(--md-sys-color-on-surface-variant)",
496
- alignItems: "center",
497
- justifyContent: "center",
498
- transition: "all 0.2s ease",
499
- width: "32px",
500
- height: "32px"
501
- },
502
- onMouseEnter: (e) => {
503
- e.currentTarget.style.backgroundColor = isDark ? "var(--md-sys-color-surface-container-highest)" : "var(--md-sys-color-surface-container-high)";
504
- },
505
- onMouseLeave: (e) => {
506
- e.currentTarget.style.backgroundColor = isDark ? "var(--md-sys-color-surface-container-high)" : "var(--md-sys-color-surface-container-highest)";
507
- },
508
- title: copiedBlocks.has(blockId) ? "Copied!" : "Copy code",
509
- children: copiedBlocks.has(blockId) ? /* @__PURE__ */ jsxRuntime.jsx(CheckIcon__default.default, { style: { fontSize: "16px" } }) : /* @__PURE__ */ jsxRuntime.jsx(ContentCopyIcon__default.default, { style: { fontSize: "16px" } })
510
- }
511
- )
512
- ] });
513
- }
514
- return /* @__PURE__ */ jsxRuntime.jsx("code", { className: className2, ...props, children });
515
- }
516
- },
517
- children: content
518
- }
519
- )
520
- ] });
521
- };
522
- var ReadmeViewer_default = ReadmeViewer;
523
- var NotificationContext = react.createContext(void 0);
524
- var NotificationProvider = ({
525
- children,
526
- defaultDuration = 6e3,
527
- maxNotifications = 3,
528
- anchorOrigin = { vertical: "top", horizontal: "right" }
529
- }) => {
530
- const [notifications, setNotifications] = react.useState([]);
531
- const showNotification = react.useCallback((message, type, duration = defaultDuration) => {
532
- const id = `${Date.now()}-${Math.random()}`;
533
- const newNotification = { id, message, type, duration };
534
- setNotifications((prev) => {
535
- const updated = [...prev, newNotification];
536
- if (updated.length > maxNotifications) {
537
- return updated.slice(updated.length - maxNotifications);
538
- }
539
- return updated;
540
- });
541
- }, [defaultDuration, maxNotifications]);
542
- const handleClose = react.useCallback((id) => {
543
- setNotifications((prev) => prev.filter((notif) => notif.id !== id));
544
- }, []);
545
- const success = react.useCallback((message, duration) => {
546
- showNotification(message, "success", duration);
547
- }, [showNotification]);
548
- const error = react.useCallback((message, duration) => {
549
- showNotification(message, "error", duration);
550
- }, [showNotification]);
551
- const warning = react.useCallback((message, duration) => {
552
- showNotification(message, "warning", duration);
553
- }, [showNotification]);
554
- const info = react.useCallback((message, duration) => {
555
- showNotification(message, "info", duration);
556
- }, [showNotification]);
557
- const contextValue = {
558
- showNotification,
559
- success,
560
- error,
561
- warning,
562
- info
563
- };
564
- return /* @__PURE__ */ jsxRuntime.jsxs(NotificationContext.Provider, { value: contextValue, children: [
565
- children,
566
- notifications.map((notification, index) => /* @__PURE__ */ jsxRuntime.jsx(
567
- material.Snackbar,
568
- {
569
- open: true,
570
- autoHideDuration: notification.duration,
571
- onClose: () => handleClose(notification.id),
572
- anchorOrigin,
573
- style: {
574
- marginTop: index * 70
575
- // Stack notifications vertically
576
- },
577
- children: /* @__PURE__ */ jsxRuntime.jsx(
578
- material.Alert,
579
- {
580
- onClose: () => handleClose(notification.id),
581
- severity: notification.type,
582
- variant: "filled",
583
- sx: { width: "100%" },
584
- children: notification.message
585
- }
586
- )
587
- },
588
- notification.id
589
- ))
590
- ] });
591
- };
592
- var useNotification = () => {
593
- const context = react.useContext(NotificationContext);
594
- if (!context) {
595
- throw new Error("useNotification must be used within a NotificationProvider");
596
- }
597
- return context;
598
- };
599
- var ConfirmDialog = ({
600
- open,
601
- title,
602
- message,
603
- confirmText = "Confirm",
604
- cancelText = "Cancel",
605
- confirmColor = "primary",
606
- onConfirm,
607
- onCancel
608
- }) => {
609
- return /* @__PURE__ */ jsxRuntime.jsxs(material.Dialog, { open, onClose: onCancel, maxWidth: "xs", fullWidth: true, slotProps: { paper: { sx: { borderRadius: 4 } } }, children: [
610
- /* @__PURE__ */ jsxRuntime.jsx(material.DialogTitle, { children: /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
611
- /* @__PURE__ */ jsxRuntime.jsx(WarningAmberIcon__default.default, { color: confirmColor }),
612
- title
613
- ] }) }),
614
- /* @__PURE__ */ jsxRuntime.jsx(material.DialogContent, { children: /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body1", children: message }) }),
615
- /* @__PURE__ */ jsxRuntime.jsxs(material.DialogActions, { sx: { px: 3, pb: 2 }, children: [
616
- /* @__PURE__ */ jsxRuntime.jsx(material.Button, { onClick: onCancel, variant: "outlined", children: cancelText }),
617
- /* @__PURE__ */ jsxRuntime.jsx(material.Button, { onClick: onConfirm, variant: "contained", color: confirmColor, autoFocus: true, children: confirmText })
618
- ] })
619
- ] });
620
- };
621
-
622
- // src/theme/tokens.ts
623
- var tokens_exports = {};
624
- __export(tokens_exports, {
625
- borderRadius: () => borderRadius,
626
- elevation: () => elevation,
627
- fontSize: () => fontSize,
628
- fontWeight: () => fontWeight,
629
- lineHeight: () => lineHeight,
630
- spacing: () => spacing,
631
- transition: () => transition,
632
- zIndex: () => zIndex
633
- });
634
- var spacing = {
635
- xs: "0.25rem",
636
- // 4px
637
- sm: "0.5rem",
638
- // 8px
639
- md: "1rem",
640
- // 16px
641
- lg: "1.5rem",
642
- // 24px
643
- xl: "2rem",
644
- // 32px
645
- "2xl": "3rem",
646
- // 48px
647
- "3xl": "4rem"
648
- // 64px
649
- };
650
- var borderRadius = {
651
- none: "0",
652
- sm: "0.25rem",
653
- // 4px
654
- md: "0.375rem",
655
- // 6px
656
- lg: "0.5rem",
657
- // 8px
658
- xl: "0.75rem",
659
- // 12px
660
- "2xl": "1rem",
661
- // 16px
662
- full: "9999px"
663
- };
664
- var fontSize = {
665
- xs: "0.75rem",
666
- // 12px
667
- sm: "0.875rem",
668
- // 14px
669
- md: "1rem",
670
- // 16px
671
- lg: "1.125rem",
672
- // 18px
673
- xl: "1.25rem",
674
- // 20px
675
- "2xl": "1.5rem",
676
- // 24px
677
- "3xl": "1.875rem",
678
- // 30px
679
- "4xl": "2.25rem"
680
- // 36px
681
- };
682
- var fontWeight = {
683
- light: "300",
684
- normal: "400",
685
- medium: "500",
686
- semibold: "600",
687
- bold: "700"
688
- };
689
- var lineHeight = {
690
- tight: "1.25",
691
- normal: "1.5",
692
- relaxed: "1.75"
693
- };
694
- var elevation = {
695
- none: "none",
696
- sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
697
- md: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
698
- lg: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
699
- xl: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)"
700
- };
701
- var transition = {
702
- fast: "150ms",
703
- normal: "250ms",
704
- slow: "350ms"
705
- };
706
- var zIndex = {
707
- dropdown: 1e3,
708
- sticky: 1020,
709
- fixed: 1030,
710
- modalBackdrop: 1040,
711
- modal: 1050,
712
- popover: 1060,
713
- tooltip: 1070
118
+ var zIndex = {
119
+ dropdown: 1e3,
120
+ sticky: 1020,
121
+ fixed: 1030,
122
+ modalBackdrop: 1040,
123
+ modal: 1050,
124
+ popover: 1060,
125
+ tooltip: 1070
714
126
  };
715
127
 
716
128
  // src/theme/light.ts
@@ -848,399 +260,1059 @@ var darkTheme = {
848
260
  transition,
849
261
  zIndex
850
262
  };
851
-
852
- // src/utils/localStorage.ts
853
- var LocalStorage = class {
854
- /**
855
- * Get an item from localStorage
856
- * @param key - The key to retrieve
857
- * @returns The value or null if not found or error occurs
858
- */
859
- static getItem(key) {
860
- try {
861
- if (typeof window === "undefined") {
862
- return null;
263
+
264
+ // src/utils/localStorage.ts
265
+ var LocalStorage = class {
266
+ /**
267
+ * Get an item from localStorage
268
+ * @param key - The key to retrieve
269
+ * @returns The value or null if not found or error occurs
270
+ */
271
+ static getItem(key) {
272
+ try {
273
+ if (typeof window === "undefined") {
274
+ return null;
275
+ }
276
+ const item = window.localStorage.getItem(key);
277
+ if (item === null) {
278
+ return null;
279
+ }
280
+ try {
281
+ return JSON.parse(item);
282
+ } catch {
283
+ return item;
284
+ }
285
+ } catch (error) {
286
+ console.error(`Error getting item from localStorage: ${error}`);
287
+ return null;
288
+ }
289
+ }
290
+ /**
291
+ * Set an item in localStorage
292
+ * @param key - The key to store
293
+ * @param value - The value to store
294
+ * @returns true if successful, false otherwise
295
+ */
296
+ static setItem(key, value) {
297
+ try {
298
+ if (typeof window === "undefined") {
299
+ return false;
300
+ }
301
+ const serializedValue = typeof value === "string" ? value : JSON.stringify(value);
302
+ window.localStorage.setItem(key, serializedValue);
303
+ return true;
304
+ } catch (error) {
305
+ console.error(`Error setting item in localStorage: ${error}`);
306
+ return false;
307
+ }
308
+ }
309
+ /**
310
+ * Remove an item from localStorage
311
+ * @param key - The key to remove
312
+ * @returns true if successful, false otherwise
313
+ */
314
+ static removeItem(key) {
315
+ try {
316
+ if (typeof window === "undefined") {
317
+ return false;
318
+ }
319
+ window.localStorage.removeItem(key);
320
+ return true;
321
+ } catch (error) {
322
+ console.error(`Error removing item from localStorage: ${error}`);
323
+ return false;
324
+ }
325
+ }
326
+ /**
327
+ * Clear all items from localStorage
328
+ * @returns true if successful, false otherwise
329
+ */
330
+ static clear() {
331
+ try {
332
+ if (typeof window === "undefined") {
333
+ return false;
334
+ }
335
+ window.localStorage.clear();
336
+ return true;
337
+ } catch (error) {
338
+ console.error(`Error clearing localStorage: ${error}`);
339
+ return false;
340
+ }
341
+ }
342
+ /**
343
+ * Check if a key exists in localStorage
344
+ * @param key - The key to check
345
+ * @returns true if key exists, false otherwise
346
+ */
347
+ static hasItem(key) {
348
+ try {
349
+ if (typeof window === "undefined") {
350
+ return false;
351
+ }
352
+ return window.localStorage.getItem(key) !== null;
353
+ } catch (error) {
354
+ console.error(`Error checking item in localStorage: ${error}`);
355
+ return false;
356
+ }
357
+ }
358
+ /**
359
+ * Get all keys from localStorage
360
+ * @returns Array of keys
361
+ */
362
+ static keys() {
363
+ try {
364
+ if (typeof window === "undefined") {
365
+ return [];
366
+ }
367
+ return Object.keys(window.localStorage);
368
+ } catch (error) {
369
+ console.error(`Error getting keys from localStorage: ${error}`);
370
+ return [];
371
+ }
372
+ }
373
+ };
374
+ var ThemeContext = react.createContext(void 0);
375
+ var THEME_STORAGE_KEY = "app-theme-mode";
376
+ var getSystemTheme = () => {
377
+ if (typeof window === "undefined") return "light";
378
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
379
+ };
380
+ var applyCssVariables = (theme, resolvedMode) => {
381
+ if (typeof document === "undefined") return;
382
+ const root = document.documentElement;
383
+ root.setAttribute("data-theme", resolvedMode);
384
+ Object.entries(theme.colors).forEach(([key, value]) => {
385
+ root.style.setProperty(`--color-${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`, value);
386
+ });
387
+ Object.entries(theme.spacing).forEach(([key, value]) => {
388
+ root.style.setProperty(`--spacing-${key}`, value);
389
+ });
390
+ Object.entries(theme.borderRadius).forEach(([key, value]) => {
391
+ root.style.setProperty(`--radius-${key}`, value);
392
+ });
393
+ Object.entries(theme.fontSize).forEach(([key, value]) => {
394
+ root.style.setProperty(`--text-${key}`, value);
395
+ });
396
+ Object.entries(theme.fontWeight).forEach(([key, value]) => {
397
+ root.style.setProperty(`--font-${key}`, value);
398
+ });
399
+ Object.entries(theme.lineHeight).forEach(([key, value]) => {
400
+ root.style.setProperty(`--leading-${key}`, value);
401
+ });
402
+ Object.entries(theme.elevation).forEach(([key, value]) => {
403
+ root.style.setProperty(`--shadow-${key}`, value);
404
+ });
405
+ Object.entries(theme.transition).forEach(([key, value]) => {
406
+ root.style.setProperty(`--transition-${key}`, value);
407
+ });
408
+ };
409
+ var ThemeProvider = ({
410
+ children,
411
+ initialTheme,
412
+ initialMode = "system",
413
+ storageKey = THEME_STORAGE_KEY,
414
+ enableCssVariables = true
415
+ }) => {
416
+ const getInitialMode = () => {
417
+ const savedMode = LocalStorage.getItem(storageKey);
418
+ return savedMode || initialMode;
419
+ };
420
+ const [themeMode, setThemeModeState] = react.useState(getInitialMode);
421
+ const [systemTheme, setSystemTheme] = react.useState(getSystemTheme);
422
+ const [customTheme, setCustomTheme] = react.useState(initialTheme);
423
+ const resolvedThemeMode = react.useMemo(() => {
424
+ if (themeMode === "system") return systemTheme;
425
+ return themeMode;
426
+ }, [themeMode, systemTheme]);
427
+ const theme = react.useMemo(() => {
428
+ if (customTheme) return customTheme;
429
+ return resolvedThemeMode === "light" ? lightTheme : darkTheme;
430
+ }, [customTheme, resolvedThemeMode]);
431
+ react.useEffect(() => {
432
+ if (typeof window === "undefined") return;
433
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
434
+ const handleChange = (e) => {
435
+ setSystemTheme(e.matches ? "dark" : "light");
436
+ };
437
+ if (mediaQuery.addEventListener) {
438
+ mediaQuery.addEventListener("change", handleChange);
439
+ return () => mediaQuery.removeEventListener("change", handleChange);
440
+ } else if (mediaQuery.addListener) {
441
+ mediaQuery.addListener(handleChange);
442
+ return () => mediaQuery.removeListener(handleChange);
443
+ }
444
+ }, []);
445
+ react.useEffect(() => {
446
+ if (enableCssVariables) {
447
+ applyCssVariables(theme, resolvedThemeMode);
448
+ }
449
+ }, [theme, resolvedThemeMode, enableCssVariables]);
450
+ react.useEffect(() => {
451
+ LocalStorage.setItem(storageKey, themeMode);
452
+ }, [themeMode, storageKey]);
453
+ const setThemeMode = react.useCallback((mode) => {
454
+ setThemeModeState(mode);
455
+ }, []);
456
+ const setTheme = react.useCallback((newTheme) => {
457
+ setCustomTheme(newTheme);
458
+ }, []);
459
+ const toggleTheme = react.useCallback(() => {
460
+ setThemeModeState((prevMode) => {
461
+ if (prevMode === "light") return "dark";
462
+ if (prevMode === "dark") return "system";
463
+ return "light";
464
+ });
465
+ }, []);
466
+ const contextValue = react.useMemo(() => ({
467
+ theme,
468
+ themeMode,
469
+ resolvedThemeMode,
470
+ setTheme,
471
+ setThemeMode,
472
+ toggleTheme
473
+ }), [theme, themeMode, resolvedThemeMode, setTheme, setThemeMode, toggleTheme]);
474
+ const muiTheme = react.useMemo(() => material.createTheme({
475
+ palette: {
476
+ mode: resolvedThemeMode,
477
+ primary: {
478
+ main: theme.colors.primary
479
+ },
480
+ secondary: {
481
+ main: theme.colors.secondary
482
+ },
483
+ error: {
484
+ main: theme.colors.error
485
+ },
486
+ success: {
487
+ main: theme.colors.success
488
+ },
489
+ background: {
490
+ default: theme.colors.background,
491
+ paper: theme.colors.backgroundSecondary
492
+ },
493
+ text: {
494
+ primary: theme.colors.text,
495
+ secondary: theme.colors.textSecondary
496
+ }
497
+ }
498
+ }), [resolvedThemeMode, theme]);
499
+ return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(material.ThemeProvider, { theme: muiTheme, children: [
500
+ /* @__PURE__ */ jsxRuntime.jsx(material.CssBaseline, {}),
501
+ children
502
+ ] }) });
503
+ };
504
+ var useTheme = () => {
505
+ const context = react.useContext(ThemeContext);
506
+ if (!context) {
507
+ throw new Error("useTheme must be used within a ThemeProvider");
508
+ }
509
+ return context;
510
+ };
511
+ var ThemeToggle = ({
512
+ lightModeTooltip = "Switch to dark mode",
513
+ darkModeTooltip = "Switch to system theme",
514
+ systemModeTooltip = "Switch to light theme",
515
+ showTooltip = true,
516
+ sx,
517
+ ...props
518
+ }) => {
519
+ const { themeMode, toggleTheme } = useTheme();
520
+ const getIcon = () => {
521
+ switch (themeMode) {
522
+ case "light":
523
+ return /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.LightMode, {});
524
+ case "dark":
525
+ return /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.DarkMode, {});
526
+ case "system":
527
+ return /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.BrightnessAuto, {});
528
+ default:
529
+ return /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.BrightnessAuto, {});
530
+ }
531
+ };
532
+ const getTooltip = () => {
533
+ switch (themeMode) {
534
+ case "light":
535
+ return lightModeTooltip;
536
+ case "dark":
537
+ return darkModeTooltip;
538
+ case "system":
539
+ return systemModeTooltip;
540
+ default:
541
+ return lightModeTooltip;
542
+ }
543
+ };
544
+ const button = /* @__PURE__ */ jsxRuntime.jsx(
545
+ material.IconButton,
546
+ {
547
+ onClick: toggleTheme,
548
+ color: "inherit",
549
+ sx: {
550
+ borderRadius: "50%",
551
+ ...sx
552
+ },
553
+ ...props,
554
+ children: getIcon()
555
+ }
556
+ );
557
+ if (!showTooltip) {
558
+ return button;
559
+ }
560
+ return /* @__PURE__ */ jsxRuntime.jsx(material.Tooltip, { title: getTooltip(), arrow: true, children: button });
561
+ };
562
+ function NotFoundPage() {
563
+ const navigate = reactRouterDom.useNavigate();
564
+ const { theme } = useTheme();
565
+ return /* @__PURE__ */ jsxRuntime.jsxs(
566
+ material.Box,
567
+ {
568
+ sx: {
569
+ minHeight: "100vh",
570
+ display: "flex",
571
+ flexDirection: "column",
572
+ alignItems: "center",
573
+ justifyContent: "center",
574
+ backgroundColor: theme.colors.backgroundSecondary,
575
+ gap: 2,
576
+ textAlign: "center",
577
+ px: 2
578
+ },
579
+ children: [
580
+ /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.SentimentDissatisfied, { sx: { fontSize: 72, color: "text.disabled" } }),
581
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "h2", fontWeight: "bold", color: "text.primary", children: "404" }),
582
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "h6", color: "text.secondary", children: "Page not found" }),
583
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body2", color: "text.disabled", sx: { maxWidth: 360 }, children: "The page you're looking for doesn't exist or has been moved." }),
584
+ /* @__PURE__ */ jsxRuntime.jsx(
585
+ material.Button,
586
+ {
587
+ variant: "contained",
588
+ sx: { mt: 2, textTransform: "none" },
589
+ onClick: () => navigate("/", { replace: true }),
590
+ children: "Go to Home"
591
+ }
592
+ )
593
+ ]
594
+ }
595
+ );
596
+ }
597
+
598
+ // src/http/HttpClient.ts
599
+ var HttpClient = class {
600
+ constructor(config = {}) {
601
+ this.baseURL = config.baseURL || "";
602
+ this.timeout = config.timeout || 3e4;
603
+ this.defaultHeaders = config.headers || {};
604
+ }
605
+ buildURL(url, params) {
606
+ const fullURL = url.startsWith("http") ? url : `${this.baseURL}${url}`;
607
+ if (!params) return fullURL;
608
+ const searchParams = new URLSearchParams();
609
+ Object.entries(params).forEach(([key, value]) => {
610
+ searchParams.append(key, String(value));
611
+ });
612
+ return `${fullURL}?${searchParams.toString()}`;
613
+ }
614
+ async request(url, config = {}) {
615
+ const { params, data, timeout = this.timeout, headers = {}, ...restConfig } = config;
616
+ const controller = new AbortController();
617
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
618
+ try {
619
+ const response = await fetch(this.buildURL(url, params), {
620
+ ...restConfig,
621
+ headers: {
622
+ "Content-Type": "application/json",
623
+ ...this.defaultHeaders,
624
+ ...headers
625
+ },
626
+ body: data ? JSON.stringify(data) : void 0,
627
+ signal: controller.signal
628
+ });
629
+ clearTimeout(timeoutId);
630
+ if (!response.ok) {
631
+ const error = new Error(`HTTP Error: ${response.statusText}`);
632
+ error.status = response.status;
633
+ error.statusText = response.statusText;
634
+ try {
635
+ error.data = await response.json();
636
+ } catch {
637
+ error.data = { code: response.status, message: await response.text() };
638
+ }
639
+ throw error;
640
+ }
641
+ const responseData = await response.json();
642
+ return {
643
+ data: responseData,
644
+ status: response.status,
645
+ statusText: response.statusText,
646
+ headers: response.headers
647
+ };
648
+ } catch (error) {
649
+ clearTimeout(timeoutId);
650
+ if (error instanceof Error && error.name === "AbortError") {
651
+ throw new Error("Request timeout");
652
+ }
653
+ throw error;
654
+ }
655
+ }
656
+ setDefaultHeader(key, value) {
657
+ this.defaultHeaders[key] = value;
658
+ }
659
+ removeDefaultHeader(key) {
660
+ delete this.defaultHeaders[key];
661
+ }
662
+ getDefaultHeaders() {
663
+ return { ...this.defaultHeaders };
664
+ }
665
+ get(url, config) {
666
+ return this.request(url, { ...config, method: "GET" });
667
+ }
668
+ post(url, data, config) {
669
+ return this.request(url, { ...config, data, method: "POST" });
670
+ }
671
+ put(url, data, config) {
672
+ return this.request(url, { ...config, data, method: "PUT" });
673
+ }
674
+ patch(url, data, config) {
675
+ return this.request(url, { ...config, data, method: "PATCH" });
676
+ }
677
+ delete(url, config) {
678
+ return this.request(url, { ...config, method: "DELETE" });
679
+ }
680
+ };
681
+ function extractErrorMessage(error) {
682
+ if (error instanceof Error) {
683
+ const httpError = error;
684
+ if (httpError.data) {
685
+ return httpError.data.message;
686
+ }
687
+ return error.message;
688
+ }
689
+ return "An unexpected error occurred";
690
+ }
691
+ function LoginCallbackPage({ authService, navigateTo = "/", onLoginFailed }) {
692
+ const [searchParams] = reactRouterDom.useSearchParams();
693
+ const navigate = reactRouterDom.useNavigate();
694
+ const { theme } = useTheme();
695
+ react.useEffect(() => {
696
+ const loginToken = searchParams.get("login_token");
697
+ if (!loginToken) {
698
+ console.error("Login callback failed: Missing login_token in query parameters");
699
+ onLoginFailed?.();
700
+ return;
701
+ }
702
+ authService.signInWithLoginToken({ loginToken }).then(() => {
703
+ navigate(navigateTo, { replace: true });
704
+ }).catch((err) => {
705
+ console.error("Login callback failed:", extractErrorMessage(err));
706
+ onLoginFailed?.();
707
+ });
708
+ }, []);
709
+ return /* @__PURE__ */ jsxRuntime.jsxs(
710
+ material.Box,
711
+ {
712
+ sx: {
713
+ minHeight: "100vh",
714
+ display: "flex",
715
+ flexDirection: "column",
716
+ alignItems: "center",
717
+ justifyContent: "center",
718
+ background: `linear-gradient(135deg, ${theme.colors.primary} 0%, ${theme.colors.primaryActive} 100%)`,
719
+ gap: 2
720
+ },
721
+ children: [
722
+ /* @__PURE__ */ jsxRuntime.jsx(material.CircularProgress, { sx: { color: theme.colors.surface } }),
723
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body2", sx: { color: theme.colors.surface, opacity: 0.85 }, children: "Signing you in\u2026" })
724
+ ]
725
+ }
726
+ );
727
+ }
728
+ var RouterMenuItem = ({ item, depth = 0, expanded, onToggle }) => {
729
+ const hasChildren = item.children && item.children.length > 0;
730
+ const isExpanded = expanded.has(item.id);
731
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
732
+ /* @__PURE__ */ jsxRuntime.jsx(material.ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
733
+ material.ListItemButton,
734
+ {
735
+ component: hasChildren ? "div" : reactRouterDom.NavLink,
736
+ to: !hasChildren ? item.path || `/${item.id}` : void 0,
737
+ end: false,
738
+ onClick: hasChildren ? () => onToggle(item.id) : void 0,
739
+ sx: {
740
+ pl: 2 + depth * 2,
741
+ "&.active": {
742
+ backgroundColor: "action.selected",
743
+ color: "primary.main",
744
+ borderLeft: 3,
745
+ borderColor: "primary.main",
746
+ fontWeight: "medium",
747
+ "& .MuiListItemIcon-root": {
748
+ color: "primary.main"
749
+ }
750
+ },
751
+ "&:hover": {
752
+ backgroundColor: "action.hover"
753
+ },
754
+ transition: "all 0.15s"
755
+ },
756
+ children: [
757
+ item.icon && /* @__PURE__ */ jsxRuntime.jsx(material.ListItemIcon, { sx: { minWidth: 40 }, children: item.icon }),
758
+ /* @__PURE__ */ jsxRuntime.jsx(
759
+ material.ListItemText,
760
+ {
761
+ primary: item.label,
762
+ primaryTypographyProps: {
763
+ fontSize: "0.875rem"
764
+ }
765
+ }
766
+ ),
767
+ hasChildren && /* @__PURE__ */ jsxRuntime.jsx(material.IconButton, { size: "small", sx: { p: 0 }, children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.ExpandLess, {}) : /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.ExpandMore, {}) })
768
+ ]
863
769
  }
864
- const item = window.localStorage.getItem(key);
865
- if (item === null) {
866
- return null;
770
+ ) }),
771
+ hasChildren && /* @__PURE__ */ jsxRuntime.jsx(material.Collapse, { in: isExpanded, timeout: "auto", unmountOnExit: true, children: /* @__PURE__ */ jsxRuntime.jsx(material.List, { component: "div", disablePadding: true, children: item.children.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
772
+ RouterMenuItem,
773
+ {
774
+ item: child,
775
+ depth: depth + 1,
776
+ expanded,
777
+ onToggle
778
+ },
779
+ child.id
780
+ )) }) })
781
+ ] });
782
+ };
783
+ var flattenMenuRoutes = (items) => {
784
+ const routes = [];
785
+ const flatten = (menuItems) => {
786
+ for (const item of menuItems) {
787
+ if (item.path && item.component) {
788
+ routes.push({ path: item.path, component: item.component });
867
789
  }
868
- try {
869
- return JSON.parse(item);
870
- } catch {
871
- return item;
790
+ if (item.children) {
791
+ flatten(item.children);
872
792
  }
873
- } catch (error) {
874
- console.error(`Error getting item from localStorage: ${error}`);
875
- return null;
876
793
  }
877
- }
878
- /**
879
- * Set an item in localStorage
880
- * @param key - The key to store
881
- * @param value - The value to store
882
- * @returns true if successful, false otherwise
883
- */
884
- static setItem(key, value) {
885
- try {
886
- if (typeof window === "undefined") {
887
- return false;
794
+ };
795
+ flatten(items);
796
+ return routes;
797
+ };
798
+ var SidebarLayoutRouterInner = ({
799
+ menuItems,
800
+ sidebarWidth = 250,
801
+ className = "",
802
+ onMenuChange,
803
+ style,
804
+ sidebarStyle,
805
+ bodyStyle,
806
+ defaultExpanded = []
807
+ }) => {
808
+ const location = reactRouterDom.useLocation();
809
+ const [expanded, setExpanded] = react.useState(new Set(defaultExpanded));
810
+ const handleToggle = (id) => {
811
+ setExpanded((prev) => {
812
+ const next = new Set(prev);
813
+ if (next.has(id)) {
814
+ next.delete(id);
815
+ } else {
816
+ next.add(id);
888
817
  }
889
- const serializedValue = typeof value === "string" ? value : JSON.stringify(value);
890
- window.localStorage.setItem(key, serializedValue);
891
- return true;
892
- } catch (error) {
893
- console.error(`Error setting item in localStorage: ${error}`);
894
- return false;
818
+ return next;
819
+ });
820
+ };
821
+ react.useEffect(() => {
822
+ if (onMenuChange) {
823
+ const findActiveItem = (items) => {
824
+ for (const item of items) {
825
+ if (item.path && location.pathname === item.path) {
826
+ return item;
827
+ }
828
+ if (item.children) {
829
+ const found = findActiveItem(item.children);
830
+ if (found) return found;
831
+ }
832
+ }
833
+ return void 0;
834
+ };
835
+ const activeItem = findActiveItem(menuItems);
836
+ if (activeItem) {
837
+ onMenuChange(activeItem.id);
838
+ }
839
+ }
840
+ }, [location.pathname, menuItems, onMenuChange]);
841
+ const hasComponents = menuItems.some(
842
+ (item) => item.component || item.children?.some((child) => child.component)
843
+ );
844
+ const routes = hasComponents ? flattenMenuRoutes(menuItems) : [];
845
+ return /* @__PURE__ */ jsxRuntime.jsxs(
846
+ material.Box,
847
+ {
848
+ className,
849
+ sx: {
850
+ display: "flex",
851
+ height: "100%",
852
+ width: "100%",
853
+ ...style
854
+ },
855
+ children: [
856
+ /* @__PURE__ */ jsxRuntime.jsx(
857
+ material.Drawer,
858
+ {
859
+ variant: "permanent",
860
+ sx: {
861
+ width: sidebarWidth,
862
+ flexShrink: 0,
863
+ "& .MuiDrawer-paper": {
864
+ width: sidebarWidth,
865
+ boxSizing: "border-box",
866
+ position: "relative",
867
+ borderRight: "1px solid",
868
+ borderColor: "divider",
869
+ ...sidebarStyle
870
+ }
871
+ },
872
+ children: /* @__PURE__ */ jsxRuntime.jsx(material.List, { sx: { p: 0 }, children: menuItems.filter((item) => item.label).map((item) => /* @__PURE__ */ jsxRuntime.jsx(
873
+ RouterMenuItem,
874
+ {
875
+ item,
876
+ expanded,
877
+ onToggle: handleToggle
878
+ },
879
+ item.id
880
+ )) })
881
+ }
882
+ ),
883
+ /* @__PURE__ */ jsxRuntime.jsx(
884
+ material.Box,
885
+ {
886
+ component: "main",
887
+ sx: {
888
+ flexGrow: 1,
889
+ overflow: "auto",
890
+ ...bodyStyle
891
+ },
892
+ children: hasComponents ? /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Routes, { children: routes.map(({ path, component }) => /* @__PURE__ */ jsxRuntime.jsx(
893
+ reactRouterDom.Route,
894
+ {
895
+ path,
896
+ element: component
897
+ },
898
+ path
899
+ )) }) : /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Outlet, {})
900
+ }
901
+ )
902
+ ]
903
+ }
904
+ );
905
+ };
906
+ var SidebarLayoutWithRouter = (props) => {
907
+ return (
908
+ // @ts-expect-error - future prop exists in v6 for v7 migration, but is removed from v7 types
909
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.BrowserRouter, { future: { v7_startTransition: true, v7_relativeSplatPath: true }, children: /* @__PURE__ */ jsxRuntime.jsx(SidebarLayoutRouterInner, { ...props }) })
910
+ );
911
+ };
912
+ var StateMenuItem = ({ item, selectedId, depth = 0, expanded, onToggle, onClick }) => {
913
+ const hasChildren = item.children && item.children.length > 0;
914
+ const isExpanded = expanded.has(item.id);
915
+ const isActive = item.id === selectedId;
916
+ const handleClick = () => {
917
+ if (hasChildren) {
918
+ onToggle(item.id);
919
+ } else {
920
+ onClick(item.id);
895
921
  }
896
- }
897
- /**
898
- * Remove an item from localStorage
899
- * @param key - The key to remove
900
- * @returns true if successful, false otherwise
901
- */
902
- static removeItem(key) {
903
- try {
904
- if (typeof window === "undefined") {
905
- return false;
922
+ };
923
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
924
+ /* @__PURE__ */ jsxRuntime.jsx(material.ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
925
+ material.ListItemButton,
926
+ {
927
+ selected: isActive,
928
+ onClick: handleClick,
929
+ sx: {
930
+ pl: 2 + depth * 2,
931
+ "&.Mui-selected": {
932
+ backgroundColor: "action.selected",
933
+ color: "primary.main",
934
+ borderLeft: 3,
935
+ borderColor: "primary.main",
936
+ fontWeight: "medium",
937
+ "& .MuiListItemIcon-root": {
938
+ color: "primary.main"
939
+ },
940
+ "&:hover": {
941
+ backgroundColor: "action.selected"
942
+ }
943
+ },
944
+ "&:hover": {
945
+ backgroundColor: "action.hover"
946
+ },
947
+ transition: "all 0.15s"
948
+ },
949
+ children: [
950
+ item.icon && /* @__PURE__ */ jsxRuntime.jsx(material.ListItemIcon, { sx: { minWidth: 40 }, children: item.icon }),
951
+ /* @__PURE__ */ jsxRuntime.jsx(
952
+ material.ListItemText,
953
+ {
954
+ primary: item.label,
955
+ primaryTypographyProps: {
956
+ fontSize: "0.875rem"
957
+ }
958
+ }
959
+ ),
960
+ hasChildren && /* @__PURE__ */ jsxRuntime.jsx(material.IconButton, { size: "small", sx: { p: 0 }, children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.ExpandLess, {}) : /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.ExpandMore, {}) })
961
+ ]
906
962
  }
907
- window.localStorage.removeItem(key);
908
- return true;
909
- } catch (error) {
910
- console.error(`Error removing item from localStorage: ${error}`);
911
- return false;
912
- }
913
- }
914
- /**
915
- * Clear all items from localStorage
916
- * @returns true if successful, false otherwise
917
- */
918
- static clear() {
919
- try {
920
- if (typeof window === "undefined") {
921
- return false;
963
+ ) }),
964
+ hasChildren && /* @__PURE__ */ jsxRuntime.jsx(material.Collapse, { in: isExpanded, timeout: "auto", unmountOnExit: true, children: /* @__PURE__ */ jsxRuntime.jsx(material.List, { component: "div", disablePadding: true, children: item.children.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
965
+ StateMenuItem,
966
+ {
967
+ item: child,
968
+ selectedId,
969
+ depth: depth + 1,
970
+ expanded,
971
+ onToggle,
972
+ onClick
973
+ },
974
+ child.id
975
+ )) }) })
976
+ ] });
977
+ };
978
+ var SidebarLayoutWithState = ({
979
+ menuItems,
980
+ sidebarWidth = 250,
981
+ className = "",
982
+ defaultSelected,
983
+ onMenuChange,
984
+ style,
985
+ sidebarStyle,
986
+ bodyStyle,
987
+ defaultExpanded = []
988
+ }) => {
989
+ const [selectedId, setSelectedId] = react.useState(
990
+ defaultSelected || menuItems[0]?.id
991
+ );
992
+ const [expanded, setExpanded] = react.useState(new Set(defaultExpanded));
993
+ const handleToggle = (id) => {
994
+ setExpanded((prev) => {
995
+ const next = new Set(prev);
996
+ if (next.has(id)) {
997
+ next.delete(id);
998
+ } else {
999
+ next.add(id);
922
1000
  }
923
- window.localStorage.clear();
924
- return true;
925
- } catch (error) {
926
- console.error(`Error clearing localStorage: ${error}`);
927
- return false;
1001
+ return next;
1002
+ });
1003
+ };
1004
+ const handleMenuClick = (id) => {
1005
+ setSelectedId(id);
1006
+ if (onMenuChange) {
1007
+ onMenuChange(id);
928
1008
  }
929
- }
930
- /**
931
- * Check if a key exists in localStorage
932
- * @param key - The key to check
933
- * @returns true if key exists, false otherwise
934
- */
935
- static hasItem(key) {
936
- try {
937
- if (typeof window === "undefined") {
938
- return false;
1009
+ };
1010
+ const findActiveItem = (items, id) => {
1011
+ for (const item of items) {
1012
+ if (item.id === id) return item;
1013
+ if (item.children) {
1014
+ const found = findActiveItem(item.children, id);
1015
+ if (found) return found;
939
1016
  }
940
- return window.localStorage.getItem(key) !== null;
941
- } catch (error) {
942
- console.error(`Error checking item in localStorage: ${error}`);
943
- return false;
944
1017
  }
945
- }
946
- /**
947
- * Get all keys from localStorage
948
- * @returns Array of keys
949
- */
950
- static keys() {
951
- try {
952
- if (typeof window === "undefined") {
953
- return [];
954
- }
955
- return Object.keys(window.localStorage);
956
- } catch (error) {
957
- console.error(`Error getting keys from localStorage: ${error}`);
958
- return [];
1018
+ return void 0;
1019
+ };
1020
+ const activeItem = findActiveItem(menuItems, selectedId);
1021
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1022
+ material.Box,
1023
+ {
1024
+ className,
1025
+ sx: {
1026
+ display: "flex",
1027
+ height: "100%",
1028
+ width: "100%",
1029
+ ...style
1030
+ },
1031
+ children: [
1032
+ /* @__PURE__ */ jsxRuntime.jsx(
1033
+ material.Drawer,
1034
+ {
1035
+ variant: "permanent",
1036
+ sx: {
1037
+ width: sidebarWidth,
1038
+ flexShrink: 0,
1039
+ "& .MuiDrawer-paper": {
1040
+ width: sidebarWidth,
1041
+ boxSizing: "border-box",
1042
+ position: "relative",
1043
+ borderRight: "1px solid",
1044
+ borderColor: "divider",
1045
+ ...sidebarStyle
1046
+ }
1047
+ },
1048
+ children: /* @__PURE__ */ jsxRuntime.jsx(material.List, { sx: { p: 0 }, children: menuItems.filter((item) => item.label).map((item) => /* @__PURE__ */ jsxRuntime.jsx(
1049
+ StateMenuItem,
1050
+ {
1051
+ item,
1052
+ selectedId,
1053
+ expanded,
1054
+ onToggle: handleToggle,
1055
+ onClick: handleMenuClick
1056
+ },
1057
+ item.id
1058
+ )) })
1059
+ }
1060
+ ),
1061
+ /* @__PURE__ */ jsxRuntime.jsx(
1062
+ material.Box,
1063
+ {
1064
+ component: "main",
1065
+ sx: {
1066
+ flexGrow: 1,
1067
+ overflow: "auto",
1068
+ p: 3,
1069
+ ...bodyStyle
1070
+ },
1071
+ children: activeItem?.component || /* @__PURE__ */ jsxRuntime.jsx(
1072
+ material.Typography,
1073
+ {
1074
+ variant: "body2",
1075
+ color: "text.secondary",
1076
+ sx: { textAlign: "center", mt: 4 },
1077
+ children: "No content available for this menu item"
1078
+ }
1079
+ )
1080
+ }
1081
+ )
1082
+ ]
959
1083
  }
960
- }
961
- };
962
- var ThemeContext = react.createContext(void 0);
963
- var THEME_STORAGE_KEY = "app-theme-mode";
964
- var getSystemTheme = () => {
965
- if (typeof window === "undefined") return "light";
966
- return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
967
- };
968
- var applyCssVariables = (theme, resolvedMode) => {
969
- if (typeof document === "undefined") return;
970
- const root = document.documentElement;
971
- root.setAttribute("data-theme", resolvedMode);
972
- Object.entries(theme.colors).forEach(([key, value]) => {
973
- root.style.setProperty(`--color-${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`, value);
974
- });
975
- Object.entries(theme.spacing).forEach(([key, value]) => {
976
- root.style.setProperty(`--spacing-${key}`, value);
977
- });
978
- Object.entries(theme.borderRadius).forEach(([key, value]) => {
979
- root.style.setProperty(`--radius-${key}`, value);
980
- });
981
- Object.entries(theme.fontSize).forEach(([key, value]) => {
982
- root.style.setProperty(`--text-${key}`, value);
983
- });
984
- Object.entries(theme.fontWeight).forEach(([key, value]) => {
985
- root.style.setProperty(`--font-${key}`, value);
986
- });
987
- Object.entries(theme.lineHeight).forEach(([key, value]) => {
988
- root.style.setProperty(`--leading-${key}`, value);
989
- });
990
- Object.entries(theme.elevation).forEach(([key, value]) => {
991
- root.style.setProperty(`--shadow-${key}`, value);
992
- });
993
- Object.entries(theme.transition).forEach(([key, value]) => {
994
- root.style.setProperty(`--transition-${key}`, value);
1084
+ );
1085
+ };
1086
+ var SidebarLayout = (props) => {
1087
+ if (props.isRouter) {
1088
+ return /* @__PURE__ */ jsxRuntime.jsx(SidebarLayoutWithRouter, { ...props });
1089
+ }
1090
+ return /* @__PURE__ */ jsxRuntime.jsx(SidebarLayoutWithState, { ...props });
1091
+ };
1092
+ var highlighterInstance = null;
1093
+ var highlighterPromise = null;
1094
+ var getHighlighter = async () => {
1095
+ if (highlighterInstance) {
1096
+ return highlighterInstance;
1097
+ }
1098
+ if (highlighterPromise) {
1099
+ return highlighterPromise;
1100
+ }
1101
+ highlighterPromise = shiki.createHighlighter({
1102
+ themes: ["github-light", "github-dark"],
1103
+ langs: ["js", "ts", "go", "json", "bash", "yaml", "md", "python", "java", "cpp", "c", "html", "css", "sql", "http", "text"]
1104
+ }).then((highlighter) => {
1105
+ highlighterInstance = highlighter;
1106
+ return highlighter;
995
1107
  });
1108
+ return highlighterPromise;
996
1109
  };
997
- var ThemeProvider = ({
998
- children,
999
- initialTheme,
1000
- initialMode = "system",
1001
- storageKey = THEME_STORAGE_KEY,
1002
- enableCssVariables = true
1110
+ var ReadmeViewer = ({
1111
+ content,
1112
+ className = "",
1113
+ isDark: propIsDark,
1114
+ muiTheme
1003
1115
  }) => {
1004
- const getInitialMode = () => {
1005
- const savedMode = LocalStorage.getItem(storageKey);
1006
- return savedMode || initialMode;
1007
- };
1008
- const [themeMode, setThemeModeState] = react.useState(getInitialMode);
1009
- const [systemTheme, setSystemTheme] = react.useState(getSystemTheme);
1010
- const [customTheme, setCustomTheme] = react.useState(initialTheme);
1011
- const resolvedThemeMode = react.useMemo(() => {
1012
- if (themeMode === "system") return systemTheme;
1013
- return themeMode;
1014
- }, [themeMode, systemTheme]);
1015
- const theme = react.useMemo(() => {
1016
- if (customTheme) return customTheme;
1017
- return resolvedThemeMode === "light" ? lightTheme : darkTheme;
1018
- }, [customTheme, resolvedThemeMode]);
1116
+ const isDark = propIsDark !== void 0 ? propIsDark : muiTheme?.palette?.mode === "dark";
1117
+ const [highlighter, setHighlighter] = react.useState(null);
1118
+ const [copiedBlocks, setCopiedBlocks] = react.useState(/* @__PURE__ */ new Set());
1019
1119
  react.useEffect(() => {
1020
- if (typeof window === "undefined") return;
1021
- const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
1022
- const handleChange = (e) => {
1023
- setSystemTheme(e.matches ? "dark" : "light");
1024
- };
1025
- if (mediaQuery.addEventListener) {
1026
- mediaQuery.addEventListener("change", handleChange);
1027
- return () => mediaQuery.removeEventListener("change", handleChange);
1028
- } else if (mediaQuery.addListener) {
1029
- mediaQuery.addListener(handleChange);
1030
- return () => mediaQuery.removeListener(handleChange);
1031
- }
1120
+ getHighlighter().then(setHighlighter);
1032
1121
  }, []);
1033
- react.useEffect(() => {
1034
- if (enableCssVariables) {
1035
- applyCssVariables(theme, resolvedThemeMode);
1122
+ const copyToClipboard = async (text, blockId) => {
1123
+ try {
1124
+ await navigator.clipboard.writeText(text);
1125
+ setCopiedBlocks((prev) => new Set(prev).add(blockId));
1126
+ setTimeout(() => {
1127
+ setCopiedBlocks((prev) => {
1128
+ const newSet = new Set(prev);
1129
+ newSet.delete(blockId);
1130
+ return newSet;
1131
+ });
1132
+ }, 2e3);
1133
+ } catch (err) {
1134
+ console.error("Failed to copy text: ", err);
1036
1135
  }
1037
- }, [theme, resolvedThemeMode, enableCssVariables]);
1038
- react.useEffect(() => {
1039
- LocalStorage.setItem(storageKey, themeMode);
1040
- }, [themeMode, storageKey]);
1041
- const setThemeMode = react.useCallback((mode) => {
1042
- setThemeModeState(mode);
1043
- }, []);
1044
- const setTheme = react.useCallback((newTheme) => {
1045
- setCustomTheme(newTheme);
1046
- }, []);
1047
- const toggleTheme = react.useCallback(() => {
1048
- setThemeModeState((prevMode) => {
1049
- if (prevMode === "light") return "dark";
1050
- if (prevMode === "dark") return "system";
1051
- return "light";
1136
+ };
1137
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `readme-viewer markdown-body ${className}`, children: [
1138
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
1139
+ .shiki-wrapper pre.shiki {
1140
+ padding: 16px !important;
1141
+ border-radius: 8px !important;
1142
+ overflow-x: auto;
1143
+ margin-bottom: 16px;
1144
+ border: 1px solid var(--md-sys-color-outline-variant, #e0e0e0);
1145
+ }
1146
+ ` }),
1147
+ /* @__PURE__ */ jsxRuntime.jsx(
1148
+ ReactMarkdown__default.default,
1149
+ {
1150
+ remarkPlugins: [remarkGfm__default.default, remarkMath__default.default],
1151
+ rehypePlugins: [rehypeKatex__default.default],
1152
+ components: {
1153
+ code({ className: className2, children, ...props }) {
1154
+ const match = /language-(\w+)/.exec(className2 || "");
1155
+ if (match && highlighter) {
1156
+ const codeText = String(children).replace(/\n$/, "");
1157
+ const blockId = `code-${Math.random().toString(36).substr(2, 9)}`;
1158
+ let highlightedHtml = "";
1159
+ try {
1160
+ highlightedHtml = highlighter.codeToHtml(codeText, {
1161
+ lang: match[1],
1162
+ theme: isDark ? "github-dark" : "github-light"
1163
+ });
1164
+ } catch (e) {
1165
+ try {
1166
+ highlightedHtml = highlighter.codeToHtml(codeText, {
1167
+ lang: "text",
1168
+ theme: isDark ? "github-dark" : "github-light"
1169
+ });
1170
+ } catch (fallbackError) {
1171
+ highlightedHtml = `<pre><code>${codeText}</code></pre>`;
1172
+ }
1173
+ }
1174
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
1175
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shiki-wrapper", dangerouslySetInnerHTML: { __html: highlightedHtml } }),
1176
+ /* @__PURE__ */ jsxRuntime.jsx(
1177
+ "button",
1178
+ {
1179
+ onClick: () => copyToClipboard(codeText, blockId),
1180
+ style: {
1181
+ position: "absolute",
1182
+ top: "8px",
1183
+ right: "8px",
1184
+ backgroundColor: "var(--md-sys-color-surface-container-high)",
1185
+ border: "1px solid var(--md-sys-color-outline-variant)",
1186
+ borderRadius: "4px",
1187
+ padding: "6px",
1188
+ fontSize: "14px",
1189
+ cursor: "pointer",
1190
+ color: "var(--md-sys-color-on-surface-variant)",
1191
+ alignItems: "center",
1192
+ justifyContent: "center",
1193
+ transition: "all 0.2s ease",
1194
+ width: "32px",
1195
+ height: "32px"
1196
+ },
1197
+ onMouseEnter: (e) => {
1198
+ e.currentTarget.style.backgroundColor = isDark ? "var(--md-sys-color-surface-container-highest)" : "var(--md-sys-color-surface-container-high)";
1199
+ },
1200
+ onMouseLeave: (e) => {
1201
+ e.currentTarget.style.backgroundColor = isDark ? "var(--md-sys-color-surface-container-high)" : "var(--md-sys-color-surface-container-highest)";
1202
+ },
1203
+ title: copiedBlocks.has(blockId) ? "Copied!" : "Copy code",
1204
+ children: copiedBlocks.has(blockId) ? /* @__PURE__ */ jsxRuntime.jsx(CheckIcon__default.default, { style: { fontSize: "16px" } }) : /* @__PURE__ */ jsxRuntime.jsx(ContentCopyIcon__default.default, { style: { fontSize: "16px" } })
1205
+ }
1206
+ )
1207
+ ] });
1208
+ }
1209
+ return /* @__PURE__ */ jsxRuntime.jsx("code", { className: className2, ...props, children });
1210
+ }
1211
+ },
1212
+ children: content
1213
+ }
1214
+ )
1215
+ ] });
1216
+ };
1217
+ var ReadmeViewer_default = ReadmeViewer;
1218
+ var NotificationContext = react.createContext(void 0);
1219
+ var NotificationProvider = ({
1220
+ children,
1221
+ defaultDuration = 6e3,
1222
+ maxNotifications = 3,
1223
+ anchorOrigin = { vertical: "top", horizontal: "right" }
1224
+ }) => {
1225
+ const [notifications, setNotifications] = react.useState([]);
1226
+ const showNotification = react.useCallback((message, type, duration = defaultDuration) => {
1227
+ const id = `${Date.now()}-${Math.random()}`;
1228
+ const newNotification = { id, message, type, duration };
1229
+ setNotifications((prev) => {
1230
+ const updated = [...prev, newNotification];
1231
+ if (updated.length > maxNotifications) {
1232
+ return updated.slice(updated.length - maxNotifications);
1233
+ }
1234
+ return updated;
1052
1235
  });
1236
+ }, [defaultDuration, maxNotifications]);
1237
+ const handleClose = react.useCallback((id) => {
1238
+ setNotifications((prev) => prev.filter((notif) => notif.id !== id));
1053
1239
  }, []);
1054
- const contextValue = react.useMemo(() => ({
1055
- theme,
1056
- themeMode,
1057
- resolvedThemeMode,
1058
- setTheme,
1059
- setThemeMode,
1060
- toggleTheme
1061
- }), [theme, themeMode, resolvedThemeMode, setTheme, setThemeMode, toggleTheme]);
1062
- const muiTheme = react.useMemo(() => material.createTheme({
1063
- palette: {
1064
- mode: resolvedThemeMode,
1065
- primary: {
1066
- main: theme.colors.primary
1067
- },
1068
- secondary: {
1069
- main: theme.colors.secondary
1070
- },
1071
- error: {
1072
- main: theme.colors.error
1073
- },
1074
- success: {
1075
- main: theme.colors.success
1076
- },
1077
- background: {
1078
- default: theme.colors.background,
1079
- paper: theme.colors.backgroundSecondary
1240
+ const success = react.useCallback((message, duration) => {
1241
+ showNotification(message, "success", duration);
1242
+ }, [showNotification]);
1243
+ const error = react.useCallback((message, duration) => {
1244
+ showNotification(message, "error", duration);
1245
+ }, [showNotification]);
1246
+ const warning = react.useCallback((message, duration) => {
1247
+ showNotification(message, "warning", duration);
1248
+ }, [showNotification]);
1249
+ const info = react.useCallback((message, duration) => {
1250
+ showNotification(message, "info", duration);
1251
+ }, [showNotification]);
1252
+ const contextValue = {
1253
+ showNotification,
1254
+ success,
1255
+ error,
1256
+ warning,
1257
+ info
1258
+ };
1259
+ return /* @__PURE__ */ jsxRuntime.jsxs(NotificationContext.Provider, { value: contextValue, children: [
1260
+ children,
1261
+ notifications.map((notification, index) => /* @__PURE__ */ jsxRuntime.jsx(
1262
+ material.Snackbar,
1263
+ {
1264
+ open: true,
1265
+ autoHideDuration: notification.duration,
1266
+ onClose: () => handleClose(notification.id),
1267
+ anchorOrigin,
1268
+ style: {
1269
+ marginTop: index * 70
1270
+ // Stack notifications vertically
1271
+ },
1272
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1273
+ material.Alert,
1274
+ {
1275
+ onClose: () => handleClose(notification.id),
1276
+ severity: notification.type,
1277
+ variant: "filled",
1278
+ sx: { width: "100%" },
1279
+ children: notification.message
1280
+ }
1281
+ )
1080
1282
  },
1081
- text: {
1082
- primary: theme.colors.text,
1083
- secondary: theme.colors.textSecondary
1084
- }
1085
- }
1086
- }), [resolvedThemeMode, theme]);
1087
- return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(material.ThemeProvider, { theme: muiTheme, children: [
1088
- /* @__PURE__ */ jsxRuntime.jsx(material.CssBaseline, {}),
1089
- children
1090
- ] }) });
1283
+ notification.id
1284
+ ))
1285
+ ] });
1091
1286
  };
1092
- var useTheme = () => {
1093
- const context = react.useContext(ThemeContext);
1287
+ var useNotification = () => {
1288
+ const context = react.useContext(NotificationContext);
1094
1289
  if (!context) {
1095
- throw new Error("useTheme must be used within a ThemeProvider");
1290
+ throw new Error("useNotification must be used within a NotificationProvider");
1096
1291
  }
1097
1292
  return context;
1098
1293
  };
1099
- var ThemeToggle = ({
1100
- lightModeTooltip = "Switch to dark mode",
1101
- darkModeTooltip = "Switch to system theme",
1102
- systemModeTooltip = "Switch to light theme",
1103
- showTooltip = true,
1104
- sx,
1105
- ...props
1294
+ var ConfirmDialog = ({
1295
+ open,
1296
+ title,
1297
+ message,
1298
+ confirmText = "Confirm",
1299
+ cancelText = "Cancel",
1300
+ confirmColor = "primary",
1301
+ onConfirm,
1302
+ onCancel
1106
1303
  }) => {
1107
- const { themeMode, toggleTheme } = useTheme();
1108
- const getIcon = () => {
1109
- switch (themeMode) {
1110
- case "light":
1111
- return /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.LightMode, {});
1112
- case "dark":
1113
- return /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.DarkMode, {});
1114
- case "system":
1115
- return /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.BrightnessAuto, {});
1116
- default:
1117
- return /* @__PURE__ */ jsxRuntime.jsx(iconsMaterial.BrightnessAuto, {});
1118
- }
1119
- };
1120
- const getTooltip = () => {
1121
- switch (themeMode) {
1122
- case "light":
1123
- return lightModeTooltip;
1124
- case "dark":
1125
- return darkModeTooltip;
1126
- case "system":
1127
- return systemModeTooltip;
1128
- default:
1129
- return lightModeTooltip;
1130
- }
1131
- };
1132
- const button = /* @__PURE__ */ jsxRuntime.jsx(
1133
- material.IconButton,
1134
- {
1135
- onClick: toggleTheme,
1136
- color: "inherit",
1137
- sx: {
1138
- borderRadius: "50%",
1139
- ...sx
1140
- },
1141
- ...props,
1142
- children: getIcon()
1143
- }
1144
- );
1145
- if (!showTooltip) {
1146
- return button;
1147
- }
1148
- return /* @__PURE__ */ jsxRuntime.jsx(material.Tooltip, { title: getTooltip(), arrow: true, children: button });
1149
- };
1150
-
1151
- // src/http/HttpClient.ts
1152
- var HttpClient = class {
1153
- constructor(config = {}) {
1154
- this.baseURL = config.baseURL || "";
1155
- this.timeout = config.timeout || 3e4;
1156
- this.defaultHeaders = config.headers || {};
1157
- }
1158
- buildURL(url, params) {
1159
- const fullURL = url.startsWith("http") ? url : `${this.baseURL}${url}`;
1160
- if (!params) return fullURL;
1161
- const searchParams = new URLSearchParams();
1162
- Object.entries(params).forEach(([key, value]) => {
1163
- searchParams.append(key, String(value));
1164
- });
1165
- return `${fullURL}?${searchParams.toString()}`;
1166
- }
1167
- async request(url, config = {}) {
1168
- const { params, data, timeout = this.timeout, headers = {}, ...restConfig } = config;
1169
- const controller = new AbortController();
1170
- const timeoutId = setTimeout(() => controller.abort(), timeout);
1171
- try {
1172
- const response = await fetch(this.buildURL(url, params), {
1173
- ...restConfig,
1174
- headers: {
1175
- "Content-Type": "application/json",
1176
- ...this.defaultHeaders,
1177
- ...headers
1178
- },
1179
- body: data ? JSON.stringify(data) : void 0,
1180
- signal: controller.signal
1181
- });
1182
- clearTimeout(timeoutId);
1183
- if (!response.ok) {
1184
- const error = new Error(`HTTP Error: ${response.statusText}`);
1185
- error.status = response.status;
1186
- error.statusText = response.statusText;
1187
- try {
1188
- error.data = await response.json();
1189
- } catch {
1190
- error.data = { code: response.status, message: await response.text() };
1191
- }
1192
- throw error;
1193
- }
1194
- const responseData = await response.json();
1195
- return {
1196
- data: responseData,
1197
- status: response.status,
1198
- statusText: response.statusText,
1199
- headers: response.headers
1200
- };
1201
- } catch (error) {
1202
- clearTimeout(timeoutId);
1203
- if (error instanceof Error && error.name === "AbortError") {
1204
- throw new Error("Request timeout");
1205
- }
1206
- throw error;
1207
- }
1208
- }
1209
- setDefaultHeader(key, value) {
1210
- this.defaultHeaders[key] = value;
1211
- }
1212
- removeDefaultHeader(key) {
1213
- delete this.defaultHeaders[key];
1214
- }
1215
- getDefaultHeaders() {
1216
- return { ...this.defaultHeaders };
1217
- }
1218
- get(url, config) {
1219
- return this.request(url, { ...config, method: "GET" });
1220
- }
1221
- post(url, data, config) {
1222
- return this.request(url, { ...config, data, method: "POST" });
1223
- }
1224
- put(url, data, config) {
1225
- return this.request(url, { ...config, data, method: "PUT" });
1226
- }
1227
- patch(url, data, config) {
1228
- return this.request(url, { ...config, data, method: "PATCH" });
1229
- }
1230
- delete(url, config) {
1231
- return this.request(url, { ...config, method: "DELETE" });
1232
- }
1304
+ return /* @__PURE__ */ jsxRuntime.jsxs(material.Dialog, { open, onClose: onCancel, maxWidth: "xs", fullWidth: true, slotProps: { paper: { sx: { borderRadius: 4 } } }, children: [
1305
+ /* @__PURE__ */ jsxRuntime.jsx(material.DialogTitle, { children: /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
1306
+ /* @__PURE__ */ jsxRuntime.jsx(WarningAmberIcon__default.default, { color: confirmColor }),
1307
+ title
1308
+ ] }) }),
1309
+ /* @__PURE__ */ jsxRuntime.jsx(material.DialogContent, { children: /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body1", children: message }) }),
1310
+ /* @__PURE__ */ jsxRuntime.jsxs(material.DialogActions, { sx: { px: 3, pb: 2 }, children: [
1311
+ /* @__PURE__ */ jsxRuntime.jsx(material.Button, { onClick: onCancel, variant: "outlined", children: cancelText }),
1312
+ /* @__PURE__ */ jsxRuntime.jsx(material.Button, { onClick: onConfirm, variant: "contained", color: confirmColor, autoFocus: true, children: confirmText })
1313
+ ] })
1314
+ ] });
1233
1315
  };
1234
- function extractErrorMessage(error) {
1235
- if (error instanceof Error) {
1236
- const httpError = error;
1237
- if (httpError.data) {
1238
- return httpError.data.message;
1239
- }
1240
- return error.message;
1241
- }
1242
- return "An unexpected error occurred";
1243
- }
1244
1316
 
1245
1317
  // src/utils/cn.ts
1246
1318
  function cn(...classes) {
@@ -1281,169 +1353,171 @@ function formatDate(date, options = {
1281
1353
  const dateObj = typeof date === "string" || typeof date === "number" ? new Date(date) : date;
1282
1354
  return new Intl.DateTimeFormat("en-US", options).format(dateObj);
1283
1355
  }
1284
- function getCookie(name) {
1285
- if (typeof document === "undefined") return null;
1286
- const value = `; ${document.cookie}`;
1287
- const parts = value.split(`; ${name}=`);
1288
- if (parts.length === 2) return parts.pop()?.split(";").shift() || null;
1289
- return null;
1290
- }
1291
- function decodeJWT(token) {
1292
- try {
1293
- const base64Url = token.split(".")[1];
1294
- if (!base64Url) return null;
1295
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
1296
- const jsonPayload = decodeURIComponent(
1297
- window.atob(base64).split("").map(function(c) {
1298
- return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
1299
- }).join("")
1300
- );
1301
- return JSON.parse(jsonPayload);
1302
- } catch (e) {
1303
- return null;
1356
+
1357
+ // src/auth/sessionManager.ts
1358
+ var SESSION_KEY = "session_details";
1359
+ var SessionManager = class _SessionManager {
1360
+ constructor(client, key = SESSION_KEY) {
1361
+ this.cache = null;
1362
+ this.client = client;
1363
+ this.key = key;
1304
1364
  }
1305
- }
1306
- var AuthContext = react.createContext({
1307
- isAuthenticated: false,
1308
- isLoading: true
1309
- });
1310
- var AuthProvider = ({
1311
- cookieName = "authorization",
1312
- redirectUrl,
1313
- children,
1314
- onAuthFail,
1315
- onAuthSuccess,
1316
- loadingElement = null
1317
- }) => {
1318
- const [authState, setAuthState] = react.useState({
1319
- isAuthenticated: false,
1320
- isLoading: true
1321
- // starts loading until cookie check completes
1322
- });
1323
- const [authFailed, setAuthFailed] = react.useState(false);
1324
- react.useEffect(() => {
1325
- const verifyAuth = () => {
1326
- const token = getCookie(cookieName);
1327
- if (!token) {
1328
- handleFail();
1329
- return;
1330
- }
1331
- const decoded = decodeJWT(token);
1332
- if (!decoded) {
1333
- handleFail();
1334
- return;
1335
- }
1336
- if (decoded.exp) {
1337
- const expirationDate = new Date(decoded.exp * 1e3);
1338
- if (expirationDate < /* @__PURE__ */ new Date()) {
1339
- handleFail();
1340
- return;
1341
- }
1342
- }
1343
- setAuthState({
1344
- isAuthenticated: true,
1345
- isLoading: false
1346
- });
1347
- if (onAuthSuccess) {
1348
- onAuthSuccess();
1349
- }
1350
- };
1351
- verifyAuth();
1352
- }, [cookieName]);
1353
- const handleFail = () => {
1354
- setAuthState({
1355
- isAuthenticated: false,
1356
- isLoading: false
1357
- });
1358
- setAuthFailed(true);
1359
- if (onAuthFail) {
1360
- onAuthFail();
1361
- } else if (redirectUrl && typeof window !== "undefined") {
1362
- window.location.href = redirectUrl;
1365
+ static getInstance(client) {
1366
+ if (!_SessionManager.instance) {
1367
+ _SessionManager.instance = new _SessionManager(client);
1363
1368
  }
1364
- };
1365
- if (authState.isLoading || authFailed && !onAuthFail) {
1366
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingElement });
1369
+ return _SessionManager.instance;
1367
1370
  }
1368
- if (authFailed && onAuthFail) {
1369
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
1371
+ save(session) {
1372
+ this.cache = session;
1373
+ LocalStorage.setItem(this.key, session);
1374
+ this.setAuthToken(session.accessToken);
1375
+ }
1376
+ patch(updates) {
1377
+ const current = this.get();
1378
+ if (!current) return;
1379
+ const updated = { ...current, ...updates };
1380
+ this.cache = updated;
1381
+ LocalStorage.setItem(this.key, updated);
1382
+ if (updates.accessToken) {
1383
+ this.setAuthToken(updates.accessToken);
1384
+ }
1385
+ }
1386
+ clear() {
1387
+ this.cache = null;
1388
+ LocalStorage.removeItem(this.key);
1389
+ this.clearAuthToken();
1390
+ }
1391
+ get() {
1392
+ if (this.cache !== null) return this.cache;
1393
+ this.cache = LocalStorage.getItem(this.key);
1394
+ return this.cache;
1395
+ }
1396
+ getAccessToken() {
1397
+ return this.get()?.accessToken || void 0;
1398
+ }
1399
+ getRefreshToken() {
1400
+ return this.get()?.refreshToken || void 0;
1401
+ }
1402
+ getSessionId() {
1403
+ return this.get()?.sessionId || void 0;
1404
+ }
1405
+ isAuthenticated() {
1406
+ const session = this.get();
1407
+ if (!session?.accessToken) return false;
1408
+ return Number(session.expiresAt) > Date.now() / 1e3;
1409
+ }
1410
+ initialize() {
1411
+ const session = this.get();
1412
+ if (session?.accessToken && Number(session.expiresAt) > Date.now() / 1e3) {
1413
+ this.setAuthToken(session.accessToken);
1414
+ } else {
1415
+ this.clear();
1416
+ }
1417
+ }
1418
+ setAuthToken(token) {
1419
+ this.client.setDefaultHeader("Authorization", `Bearer ${token}`);
1420
+ }
1421
+ clearAuthToken() {
1422
+ this.client.removeDefaultHeader("Authorization");
1370
1423
  }
1371
- return /* @__PURE__ */ jsxRuntime.jsx(AuthContext.Provider, { value: authState, children });
1372
- };
1373
- var useAuth = () => {
1374
- return react.useContext(AuthContext);
1375
1424
  };
1376
1425
 
1377
- // src/auth/PermissionManager.ts
1378
- var PERMISSIONS_STORAGE_KEY = "auth_permissions";
1379
- var PermissionManager = class {
1380
- /**
1381
- * Saves an array of permission strings to local storage.
1382
- * @param permissions Array of permission strings.
1383
- */
1384
- static setPermissions(permissions) {
1385
- this.cachedPermissions = new Set(permissions);
1386
- if (typeof window === "undefined") return;
1387
- try {
1388
- localStorage.setItem(PERMISSIONS_STORAGE_KEY, JSON.stringify(permissions));
1389
- } catch (error) {
1390
- console.error("Failed to save permissions to localStorage", error);
1426
+ // src/auth/AuthService.ts
1427
+ var BASE_URL = "/openauth/v1";
1428
+ var AuthService = class _AuthService {
1429
+ constructor(client) {
1430
+ this.client = client;
1431
+ this.sessionManager = SessionManager.getInstance(client);
1432
+ }
1433
+ static getInstance(client) {
1434
+ if (!_AuthService.instance) {
1435
+ _AuthService.instance = new _AuthService(client);
1391
1436
  }
1437
+ return _AuthService.instance;
1392
1438
  }
1393
- /**
1394
- * Retrieves the currently stored permissions from local storage or memory cache.
1395
- * @returns Array of permission strings, or an empty array if none exist.
1396
- */
1397
- static getPermissions() {
1398
- if (this.cachedPermissions !== null) {
1399
- return Array.from(this.cachedPermissions);
1439
+ async signIn(request) {
1440
+ const response = await this.client.post(
1441
+ `${BASE_URL}/auth/signin`,
1442
+ request
1443
+ );
1444
+ if (response.data.accessToken) {
1445
+ this.sessionManager.save(response.data);
1446
+ }
1447
+ return response.data;
1448
+ }
1449
+ async refreshToken(request) {
1450
+ const refreshToken = this.sessionManager.getRefreshToken();
1451
+ if (!refreshToken) {
1452
+ throw new Error("No refresh token available");
1400
1453
  }
1401
- if (typeof window === "undefined") return [];
1454
+ const response = await this.client.post(
1455
+ `${BASE_URL}/auth/refresh`,
1456
+ { refreshToken, ...request }
1457
+ );
1458
+ if (response.data.accessToken) {
1459
+ this.sessionManager.patch({
1460
+ accessToken: response.data.accessToken,
1461
+ refreshToken: response.data.refreshToken
1462
+ });
1463
+ }
1464
+ return response.data;
1465
+ }
1466
+ async logout(request) {
1402
1467
  try {
1403
- const stored = localStorage.getItem(PERMISSIONS_STORAGE_KEY);
1404
- if (!stored) {
1405
- this.cachedPermissions = /* @__PURE__ */ new Set();
1406
- return [];
1407
- }
1408
- const parsed = JSON.parse(stored);
1409
- const permissionsArray = Array.isArray(parsed) ? parsed : [];
1410
- this.cachedPermissions = new Set(permissionsArray);
1411
- return permissionsArray;
1412
- } catch (error) {
1413
- console.error("Failed to parse permissions from localStorage", error);
1414
- this.cachedPermissions = /* @__PURE__ */ new Set();
1415
- return [];
1468
+ request.sessionId = this.sessionManager.getSessionId();
1469
+ const response = await this.client.post(
1470
+ `${BASE_URL}/auth/logout`,
1471
+ request || {}
1472
+ );
1473
+ return response.data;
1474
+ } finally {
1475
+ this.sessionManager.clear();
1416
1476
  }
1417
1477
  }
1418
- /**
1419
- * Clears all stored permissions from memory and local storage.
1420
- */
1421
- static clearPermissions() {
1422
- this.cachedPermissions = null;
1423
- if (typeof window === "undefined") return;
1424
- localStorage.removeItem(PERMISSIONS_STORAGE_KEY);
1478
+ async generateLoginToken(request) {
1479
+ const response = await this.client.put(
1480
+ `${BASE_URL}/auth/login-token`,
1481
+ request ?? {}
1482
+ );
1483
+ return response.data;
1425
1484
  }
1426
- /**
1427
- * Checks whether the given permission string exists in the currently stored permissions.
1428
- * @param permission The permission string to check for.
1429
- * @returns True if the permission exists, false otherwise.
1430
- */
1431
- static hasPermission(permission) {
1432
- if (this.cachedPermissions === null) {
1433
- this.getPermissions();
1485
+ async signInWithLoginToken(request) {
1486
+ const response = await this.client.post(
1487
+ `${BASE_URL}/auth/signin-with-token`,
1488
+ request
1489
+ );
1490
+ if (response.data.accessToken) {
1491
+ this.sessionManager.save(response.data);
1434
1492
  }
1435
- return this.cachedPermissions.has(permission);
1493
+ return response.data;
1494
+ }
1495
+ isAuthenticated() {
1496
+ return this.sessionManager.isAuthenticated();
1497
+ }
1498
+ getAccessToken() {
1499
+ return this.sessionManager.getAccessToken();
1500
+ }
1501
+ getSessionDetails() {
1502
+ return this.sessionManager.get();
1503
+ }
1504
+ getSessionId() {
1505
+ return this.sessionManager.getSessionId();
1506
+ }
1507
+ initializeAuth() {
1508
+ this.sessionManager.initialize();
1436
1509
  }
1437
1510
  };
1438
- PermissionManager.cachedPermissions = null;
1439
1511
 
1440
- exports.AuthProvider = AuthProvider;
1512
+ exports.AuthService = AuthService;
1441
1513
  exports.ConfirmDialog = ConfirmDialog;
1442
1514
  exports.HttpClient = HttpClient;
1443
1515
  exports.LocalStorage = LocalStorage;
1516
+ exports.LoginCallbackPage = LoginCallbackPage;
1517
+ exports.NotFoundPage = NotFoundPage;
1444
1518
  exports.NotificationProvider = NotificationProvider;
1445
- exports.PermissionManager = PermissionManager;
1446
1519
  exports.ReadmeViewer = ReadmeViewer_default;
1520
+ exports.SessionManager = SessionManager;
1447
1521
  exports.SidebarLayout = SidebarLayout;
1448
1522
  exports.ThemeProvider = ThemeProvider;
1449
1523
  exports.ThemeToggle = ThemeToggle;
@@ -1463,7 +1537,6 @@ exports.spacing = spacing;
1463
1537
  exports.throttle = throttle;
1464
1538
  exports.tokens = tokens_exports;
1465
1539
  exports.transition = transition;
1466
- exports.useAuth = useAuth;
1467
1540
  exports.useNotification = useNotification;
1468
1541
  exports.useTheme = useTheme;
1469
1542
  exports.zIndex = zIndex;