@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.d.mts +230 -106
- package/dist/index.d.ts +230 -106
- package/dist/index.js +1255 -1182
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1255 -1183
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
94
|
+
var fontWeight = {
|
|
95
|
+
light: "300",
|
|
96
|
+
normal: "400",
|
|
97
|
+
medium: "500",
|
|
98
|
+
semibold: "600",
|
|
99
|
+
bold: "700"
|
|
216
100
|
};
|
|
217
|
-
var
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SidebarLayoutWithState, { ...props });
|
|
113
|
+
var transition = {
|
|
114
|
+
fast: "150ms",
|
|
115
|
+
normal: "250ms",
|
|
116
|
+
slow: "350ms"
|
|
396
117
|
};
|
|
397
|
-
var
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
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
|
-
|
|
865
|
-
|
|
866
|
-
|
|
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
|
-
|
|
869
|
-
|
|
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
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
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
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
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
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
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
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
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
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1001
|
+
return next;
|
|
1002
|
+
});
|
|
1003
|
+
};
|
|
1004
|
+
const handleMenuClick = (id) => {
|
|
1005
|
+
setSelectedId(id);
|
|
1006
|
+
if (onMenuChange) {
|
|
1007
|
+
onMenuChange(id);
|
|
928
1008
|
}
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
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
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
return
|
|
967
|
-
};
|
|
968
|
-
var
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
})
|
|
981
|
-
|
|
982
|
-
|
|
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
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
enableCssVariables = true
|
|
1110
|
+
var ReadmeViewer = ({
|
|
1111
|
+
content,
|
|
1112
|
+
className = "",
|
|
1113
|
+
isDark: propIsDark,
|
|
1114
|
+
muiTheme
|
|
1003
1115
|
}) => {
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1006
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
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
|
-
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
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
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
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
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
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
|
|
1093
|
-
const context = react.useContext(
|
|
1287
|
+
var useNotification = () => {
|
|
1288
|
+
const context = react.useContext(NotificationContext);
|
|
1094
1289
|
if (!context) {
|
|
1095
|
-
throw new Error("
|
|
1290
|
+
throw new Error("useNotification must be used within a NotificationProvider");
|
|
1096
1291
|
}
|
|
1097
1292
|
return context;
|
|
1098
1293
|
};
|
|
1099
|
-
var
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
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
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
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
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
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
|
-
|
|
1307
|
-
|
|
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
|
-
|
|
1369
|
-
|
|
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/
|
|
1378
|
-
var
|
|
1379
|
-
var
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
static
|
|
1385
|
-
|
|
1386
|
-
|
|
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
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
if (
|
|
1399
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
this.
|
|
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
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
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
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
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
|
|
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.
|
|
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;
|