uibee 3.3.0 → 3.3.2

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.
Files changed (162) hide show
  1. package/dist/components/alert/alert.d.ts +15 -0
  2. package/dist/components/alert/alert.js +29 -0
  3. package/dist/components/badge/badge.d.ts +16 -0
  4. package/dist/components/badge/badge.js +26 -0
  5. package/dist/components/buttons/button.d.ts +25 -0
  6. package/dist/components/buttons/button.js +44 -0
  7. package/dist/components/code/code.d.ts +23 -0
  8. package/dist/components/code/code.js +39 -0
  9. package/dist/components/confirm/confirmPopup.d.ts +23 -0
  10. package/dist/components/confirm/confirmPopup.js +52 -0
  11. package/dist/components/container/accordion.d.ts +25 -0
  12. package/dist/components/container/accordion.js +41 -0
  13. package/dist/components/container/card.d.ts +13 -0
  14. package/dist/components/container/card.js +10 -0
  15. package/dist/components/container/expandableCard.d.ts +32 -0
  16. package/dist/components/container/expandableCard.js +70 -0
  17. package/dist/components/container/glassCard.d.ts +13 -0
  18. package/dist/components/container/glassCard.js +10 -0
  19. package/dist/components/container/highlight.d.ts +10 -0
  20. package/dist/components/container/highlight.js +10 -0
  21. package/dist/components/container/iconBubble.d.ts +25 -0
  22. package/dist/components/container/iconBubble.js +21 -0
  23. package/dist/components/container/leftBarPanel.d.ts +15 -0
  24. package/dist/components/container/leftBarPanel.js +10 -0
  25. package/dist/components/container/page.d.ts +15 -0
  26. package/dist/components/container/page.js +16 -0
  27. package/dist/components/container/pulseDot.d.ts +12 -0
  28. package/dist/components/container/pulseDot.js +23 -0
  29. package/dist/components/container/statCard.d.ts +18 -0
  30. package/dist/components/container/statCard.js +25 -0
  31. package/dist/components/container/tabs.d.ts +35 -0
  32. package/dist/components/container/tabs.js +36 -0
  33. package/dist/components/empty/emptyState.d.ts +19 -0
  34. package/dist/components/empty/emptyState.js +27 -0
  35. package/dist/components/footer/footer.d.ts +49 -0
  36. package/dist/components/footer/footer.js +109 -0
  37. package/dist/components/footer/loginContent.d.ts +18 -0
  38. package/dist/components/footer/loginContent.js +205 -0
  39. package/dist/components/inputs/checkbox.d.ts +20 -0
  40. package/dist/components/inputs/checkbox.js +76 -0
  41. package/dist/components/inputs/fileInput.d.ts +19 -0
  42. package/dist/components/inputs/fileInput.js +108 -0
  43. package/dist/components/inputs/input.d.ts +16 -0
  44. package/dist/components/inputs/input.js +157 -0
  45. package/dist/components/inputs/multiSelect.d.ts +37 -0
  46. package/dist/components/inputs/multiSelect.js +99 -0
  47. package/dist/components/inputs/radio.d.ts +20 -0
  48. package/dist/components/inputs/radio.js +70 -0
  49. package/dist/components/inputs/range.d.ts +14 -0
  50. package/dist/components/inputs/range.js +60 -0
  51. package/dist/components/inputs/searchInput.d.ts +11 -0
  52. package/dist/components/inputs/searchInput.js +56 -0
  53. package/dist/components/inputs/select.d.ts +42 -0
  54. package/dist/components/inputs/select.js +164 -0
  55. package/dist/components/inputs/shared/colorPickerPopup.js +293 -0
  56. package/dist/components/inputs/shared/dateTimePickerPopup.js +225 -0
  57. package/dist/components/inputs/shared/fieldWrapper.js +33 -0
  58. package/dist/components/inputs/shared/index.js +6 -0
  59. package/dist/components/inputs/shared/inputError.js +17 -0
  60. package/dist/components/inputs/shared/inputInfo.js +13 -0
  61. package/dist/components/inputs/shared/inputLabel.js +19 -0
  62. package/dist/components/inputs/switch.d.ts +14 -0
  63. package/dist/components/inputs/switch.js +37 -0
  64. package/dist/components/inputs/tagInput.d.ts +31 -0
  65. package/dist/components/inputs/tagInput.js +72 -0
  66. package/dist/components/inputs/textarea.d.ts +14 -0
  67. package/dist/components/inputs/textarea.js +76 -0
  68. package/dist/components/inputs/toggle.d.ts +21 -0
  69. package/dist/components/inputs/toggle.js +33 -0
  70. package/dist/components/login/loginPage.d.ts +15 -0
  71. package/dist/components/login/loginPage.js +80 -0
  72. package/dist/components/logo/logo.d.ts +9 -0
  73. package/dist/components/logo/logo.js +138 -0
  74. package/dist/components/logo/logoSmall.d.ts +4 -0
  75. package/dist/components/logo/logoSmall.js +56 -0
  76. package/dist/components/markdownrender/markdownRender.d.ts +16 -0
  77. package/dist/components/markdownrender/markdownRender.js +59 -0
  78. package/dist/components/modal/modal.d.ts +22 -0
  79. package/dist/components/modal/modal.js +59 -0
  80. package/dist/components/navbar/bubble.js +36 -0
  81. package/dist/components/navbar/navbar.d.ts +50 -0
  82. package/dist/components/navbar/navbar.js +99 -0
  83. package/dist/components/navbar/navbarDropdown.d.ts +15 -0
  84. package/dist/components/navbar/navbarDropdown.js +63 -0
  85. package/dist/components/navbar/navbarItem.d.ts +23 -0
  86. package/dist/components/navbar/navbarItem.js +38 -0
  87. package/dist/components/sidebar/sidebar.d.ts +34 -0
  88. package/dist/components/sidebar/sidebar.js +135 -0
  89. package/dist/components/spinner/spinner.d.ts +11 -0
  90. package/dist/components/spinner/spinner.js +16 -0
  91. package/dist/components/table/body.js +253 -0
  92. package/dist/components/table/constants.js +58 -0
  93. package/dist/components/table/empty.js +24 -0
  94. package/dist/components/table/format.js +39 -0
  95. package/dist/components/table/header.js +109 -0
  96. package/dist/components/table/menu.d.ts +18 -0
  97. package/dist/components/table/menu.js +76 -0
  98. package/dist/components/table/pagination.d.ts +14 -0
  99. package/dist/components/table/pagination.js +130 -0
  100. package/dist/components/table/skeleton.js +39 -0
  101. package/dist/components/table/table.d.ts +7 -0
  102. package/dist/components/table/table.js +213 -0
  103. package/dist/components/table/types.d.ts +52 -0
  104. package/dist/components/table/utils.js +9 -0
  105. package/dist/components/toast/toastItem.js +61 -0
  106. package/dist/components/toast/toaster.d.ts +13 -0
  107. package/dist/components/toast/toaster.js +117 -0
  108. package/dist/components/toggle/language.d.ts +10 -0
  109. package/dist/components/toggle/language.js +34 -0
  110. package/dist/components/toggle/theme.d.ts +8 -0
  111. package/dist/components/toggle/theme.js +135 -0
  112. package/dist/components/version/version.d.ts +13 -0
  113. package/dist/components/version/version.js +19 -0
  114. package/dist/components/vulnerability/constants.d.ts +4 -0
  115. package/dist/components/vulnerability/constants.js +17 -0
  116. package/dist/components/vulnerability/severityPill.d.ts +15 -0
  117. package/dist/components/vulnerability/severityPill.js +20 -0
  118. package/dist/{style.css → globals.css} +210 -264
  119. package/dist/hooks/useClickOutside.d.ts +6 -0
  120. package/dist/{useClickOutside-Cmp-RsP3.js → hooks/useClickOutside.js} +1 -1
  121. package/dist/hooks/useDarkMode.d.ts +4 -0
  122. package/dist/hooks/useDarkMode.js +19 -0
  123. package/dist/hooks/useVisibility.d.ts +7 -0
  124. package/dist/hooks/useVisibility.js +25 -0
  125. package/dist/icons/icons.d.ts +420 -0
  126. package/dist/{icons-lZYQ6Vlr.js → icons/icons.js} +1 -1
  127. package/dist/src/components/index.d.ts +51 -905
  128. package/dist/src/components/index.js +49 -4179
  129. package/dist/src/hooks/index.d.ts +3 -14
  130. package/dist/src/hooks/index.js +3 -42
  131. package/dist/src/icons/index.d.ts +1 -419
  132. package/dist/src/icons/index.js +1 -1
  133. package/dist/src/styles/index.js +1 -1
  134. package/dist/src/utils/index.d.ts +5 -37
  135. package/dist/src/utils/index.js +5 -124
  136. package/dist/utils/auth/callback.d.ts +14 -0
  137. package/dist/utils/auth/callback.js +53 -0
  138. package/dist/utils/auth/getDomain.js +6 -0
  139. package/dist/utils/auth/login.d.ts +12 -0
  140. package/dist/utils/auth/login.js +17 -0
  141. package/dist/utils/auth/logout.d.ts +10 -0
  142. package/dist/utils/auth/logout.js +20 -0
  143. package/dist/utils/auth/token.d.ts +10 -0
  144. package/dist/utils/auth/token.js +30 -0
  145. package/dist/utils/logoConsoleOutput/logoConsoleOutput.d.ts +4 -0
  146. package/dist/utils/logoConsoleOutput/logoConsoleOutput.js +11 -0
  147. package/package.json +1 -1
  148. package/src/components/buttons/button.tsx +2 -0
  149. package/src/components/footer/footer.tsx +60 -42
  150. package/src/components/footer/loginContent.tsx +38 -2
  151. package/src/components/index.ts +0 -1
  152. package/src/components/inputs/checkbox.tsx +2 -0
  153. package/src/components/inputs/input.tsx +2 -0
  154. package/src/components/inputs/radio.tsx +2 -0
  155. package/src/components/inputs/range.tsx +2 -0
  156. package/src/components/inputs/shared/colorPickerPopup.tsx +2 -0
  157. package/src/components/inputs/shared/dateTimePickerPopup.tsx +2 -0
  158. package/src/components/inputs/textarea.tsx +2 -0
  159. package/src/components/inputs/toggle.tsx +2 -0
  160. package/src/components/toast/toastItem.tsx +2 -0
  161. package/src/globals.css +5 -0
  162. package/tsdown.config.ts +1 -0
@@ -1,4180 +1,50 @@
1
- "use client";
2
- import { t as useClickOutside$1 } from "../../useClickOutside-Cmp-RsP3.js";
3
- import { D as Facebook, Kt as Wikijs, N as Github, W as Linkedin, x as Discord } from "../../icons-lZYQ6Vlr.js";
4
- import React, { Suspense, createContext, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
5
- import { AlertCircle, AlertTriangle, ArrowUpRight, Calendar, Check, CheckCircle, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, ChevronsUpDown, CircleAlert, CircleHelp, Clock, Copy, EllipsisVertical, ExternalLink, Eye, FileIcon, Globe, Info, LogIn, LogOut, Pencil, Search, TableIcon, TriangleAlert, UploadCloud, User, X } from "lucide-react";
6
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
- import Markdown from "react-markdown";
8
- import remarkGfm from "remark-gfm";
9
- import rehypeHighlight from "rehype-highlight";
10
- import { usePathname, useRouter, useSearchParams } from "next/navigation.js";
11
- import Image from "next/image.js";
12
- import { getCookie, setCookie } from "utilbee";
13
- import Link from "next/link.js";
14
- import { createPortal } from "react-dom";
15
- //#region src/components/inputs/shared/inputLabel.tsx
16
- function InputLabel({ label, name, required, disabled, className }) {
17
- return /* @__PURE__ */ jsxs("label", {
18
- htmlFor: name,
19
- className: `text-sm font-medium text-login-text ${disabled ? "opacity-50 cursor-not-allowed" : ""} ${className || ""}`,
20
- title: label,
21
- children: [
22
- label,
23
- " ",
24
- required && /* @__PURE__ */ jsx("span", {
25
- className: "text-red-500",
26
- children: "*"
27
- })
28
- ]
29
- });
30
- }
31
- //#endregion
32
- //#region src/components/inputs/shared/inputInfo.tsx
33
- function InputInfo({ info }) {
34
- return /* @__PURE__ */ jsx("div", {
35
- className: "text-login-200 hover:text-login-text transition-colors",
36
- "aria-label": info,
37
- title: info,
38
- children: /* @__PURE__ */ jsx(CircleHelp, { className: "w-4 h-4" })
39
- });
40
- }
41
- //#endregion
42
- //#region src/components/inputs/shared/inputError.tsx
43
- function InputError({ error, id }) {
44
- if (!error) return /* @__PURE__ */ jsx("div", { className: "h-4" });
45
- return /* @__PURE__ */ jsx("div", {
46
- className: "h-4",
47
- children: /* @__PURE__ */ jsx("span", {
48
- id,
49
- className: "text-xs text-red-400 ml-1 truncate block",
50
- role: "alert",
51
- title: error,
52
- children: error
53
- })
54
- });
55
- }
56
- //#endregion
57
- //#region src/components/markdownrender/markdownRender.tsx
58
- function makeDefaultComponents() {
59
- return {
60
- h1: ({ ...props }) => /* @__PURE__ */ jsx("h2", { ...props }),
61
- input({ type, checked }) {
62
- if (type !== "checkbox") return /* @__PURE__ */ jsx("input", { type });
63
- return /* @__PURE__ */ jsx("span", {
64
- "data-task-checkbox": true,
65
- className: `inline-flex items-center justify-center w-4 h-4 rounded-xs border-2 shrink-0 align-middle
66
- ${checked ? "bg-login border-login" : "border-login/50"}`,
67
- children: checked && /* @__PURE__ */ jsx("svg", {
68
- viewBox: "0 0 10 8",
69
- className: "w-2.5 h-2.5 fill-none stroke-white stroke-2",
70
- children: /* @__PURE__ */ jsx("polyline", {
71
- points: "1,4 4,7 9,1",
72
- strokeLinecap: "round",
73
- strokeLinejoin: "round"
74
- })
75
- })
76
- });
77
- },
78
- a({ href, children }) {
79
- return /* @__PURE__ */ jsxs("a", {
80
- href,
81
- target: "_blank",
82
- rel: "noopener noreferrer",
83
- className: "inline-flex items-center gap-1 text-login hover:text-login/80 underline underline-offset-2 transition-colors",
84
- children: [children, /* @__PURE__ */ jsx(ExternalLink, { className: "w-3 h-3 shrink-0 opacity-70" })]
85
- });
86
- },
87
- pre({ children }) {
88
- return /* @__PURE__ */ jsx("pre", {
89
- className: "block rounded-lg overflow-auto whitespace-pre-wrap wrap-break-word w-full",
90
- children
91
- });
92
- }
93
- };
94
- }
95
- function MarkdownRender({ MDstr, components, className, size }) {
96
- return /* @__PURE__ */ jsx("div", {
97
- className: className ?? `prose ${size === "sm" ? "prose-sm" : size === "lg" ? "prose-lg" : size === "xl" ? "prose-xl" : ""} prose-custom max-w-none`,
98
- children: /* @__PURE__ */ jsx(Markdown, {
99
- components: {
100
- ...makeDefaultComponents(),
101
- ...components
102
- },
103
- remarkPlugins: [remarkGfm],
104
- rehypePlugins: [rehypeHighlight],
105
- children: MDstr.replace(/\\n/g, "\n")
106
- })
107
- });
108
- }
109
- //#endregion
110
- //#region src/components/inputs/shared/fieldWrapper.tsx
111
- function FieldWrapper({ label, name, required, info, error, description, textSize = "sm", children, className }) {
112
- return /* @__PURE__ */ jsxs("div", {
113
- className: `flex flex-col gap-1 w-full relative ${className || ""}`,
114
- children: [
115
- (label || info) && /* @__PURE__ */ jsxs("div", {
116
- className: "flex items-center justify-between mb-1",
117
- children: [label && /* @__PURE__ */ jsx(InputLabel, {
118
- label,
119
- name,
120
- required,
121
- className: `ml-1 ${textSize === "sm" ? "text-sm!" : "text-base!"}`
122
- }), info && /* @__PURE__ */ jsx(InputInfo, { info })]
123
- }),
124
- description && /* @__PURE__ */ jsx("div", {
125
- className: "text-login-100 **:text-xs! ml-1 mb-1",
126
- children: /* @__PURE__ */ jsx(MarkdownRender, { MDstr: String(description || "") })
127
- }),
128
- children,
129
- /* @__PURE__ */ jsx(InputError, {
130
- error,
131
- id: `${name}-error`
132
- })
133
- ]
134
- });
135
- }
136
- //#endregion
137
- //#region src/components/inputs/shared/colorPickerPopup.tsx
138
- function hexToHsv(hex) {
139
- hex = hex.replace("#", "");
140
- let r = 0, g = 0, b = 0;
141
- if (hex.length === 3) {
142
- r = parseInt(hex[0] + hex[0], 16);
143
- g = parseInt(hex[1] + hex[1], 16);
144
- b = parseInt(hex[2] + hex[2], 16);
145
- } else if (hex.length === 6) {
146
- r = parseInt(hex.substring(0, 2), 16);
147
- g = parseInt(hex.substring(2, 4), 16);
148
- b = parseInt(hex.substring(4, 6), 16);
149
- }
150
- r /= 255;
151
- g /= 255;
152
- b /= 255;
153
- const max = Math.max(r, g, b);
154
- const min = Math.min(r, g, b);
155
- const d = max - min;
156
- let h = 0;
157
- const s = max === 0 ? 0 : d / max;
158
- const v = max;
159
- if (max !== min) {
160
- switch (max) {
161
- case r:
162
- h = (g - b) / d + (g < b ? 6 : 0);
163
- break;
164
- case g:
165
- h = (b - r) / d + 2;
166
- break;
167
- case b:
168
- h = (r - g) / d + 4;
169
- break;
170
- }
171
- h /= 6;
172
- }
173
- return {
174
- h: h * 360,
175
- s: s * 100,
176
- v: v * 100
177
- };
178
- }
179
- function hsvToRgb(h, s, v) {
180
- let r = 0, g = 0, b = 0;
181
- const i = Math.floor(h * 6);
182
- const f = h * 6 - i;
183
- const p = v * (1 - s);
184
- const q = v * (1 - f * s);
185
- const t = v * (1 - (1 - f) * s);
186
- switch (i % 6) {
187
- case 0:
188
- r = v;
189
- g = t;
190
- b = p;
191
- break;
192
- case 1:
193
- r = q;
194
- g = v;
195
- b = p;
196
- break;
197
- case 2:
198
- r = p;
199
- g = v;
200
- b = t;
201
- break;
202
- case 3:
203
- r = p;
204
- g = q;
205
- b = v;
206
- break;
207
- case 4:
208
- r = t;
209
- g = p;
210
- b = v;
211
- break;
212
- case 5:
213
- r = v;
214
- g = p;
215
- b = q;
216
- break;
217
- }
218
- return {
219
- r: Math.round(r * 255),
220
- g: Math.round(g * 255),
221
- b: Math.round(b * 255)
222
- };
223
- }
224
- function hsvToHex(h, s, v) {
225
- const { r, g, b } = hsvToRgb(h / 360, s / 100, v / 100);
226
- function toHex(x) {
227
- const hex = x.toString(16);
228
- return hex.length === 1 ? "0" + hex : hex;
229
- }
230
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
231
- }
232
- const PRESET_COLORS = [
233
- "#f87171",
234
- "#fd8738",
235
- "#fbbf24",
236
- "#facc15",
237
- "#a3e635",
238
- "#4ade80",
239
- "#34d399",
240
- "#2dd4bf",
241
- "#38bdf8",
242
- "#60a5fa",
243
- "#818cf8",
244
- "#a78bfa",
245
- "#c084fc",
246
- "#e879f9",
247
- "#f472b6",
248
- "#fb7185"
249
- ];
250
- function SaturationPicker({ hsv, onChange }) {
251
- const containerRef = useRef(null);
252
- function handleMove(e) {
253
- if (!containerRef.current) return;
254
- const { left, top, width, height } = containerRef.current.getBoundingClientRect();
255
- const x = Math.min(Math.max((e.clientX - left) / width, 0), 1);
256
- const y = Math.min(Math.max((e.clientY - top) / height, 0), 1);
257
- onChange(x * 100, (1 - y) * 100);
258
- }
259
- function handleMouseDown(e) {
260
- handleMove(e);
261
- function moveHandler(e) {
262
- handleMove(e);
263
- }
264
- function upHandler() {
265
- window.removeEventListener("mousemove", moveHandler);
266
- window.removeEventListener("mouseup", upHandler);
267
- }
268
- window.addEventListener("mousemove", moveHandler);
269
- window.addEventListener("mouseup", upHandler);
270
- }
271
- return /* @__PURE__ */ jsxs("div", {
272
- ref: containerRef,
273
- className: "w-full h-32 relative rounded-md overflow-hidden cursor-crosshair mb-3 select-none",
274
- style: { backgroundColor: hsvToHex(hsv.h, 100, 100) },
275
- onMouseDown: handleMouseDown,
276
- children: [
277
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-linear-to-r from-white to-transparent" }),
278
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-linear-to-t from-black to-transparent" }),
279
- /* @__PURE__ */ jsx("div", {
280
- className: `
281
- absolute w-3 h-3 border-2 border-white rounded-full
282
- shadow-md -translate-x-1/2 -translate-y-1/2 pointer-events-none
283
- `,
284
- style: {
285
- left: `${hsv.s}%`,
286
- top: `${100 - hsv.v}%`
287
- }
288
- })
289
- ]
290
- });
291
- }
292
- function HuePicker({ hue, onChange }) {
293
- const containerRef = useRef(null);
294
- function handleMove(e) {
295
- if (!containerRef.current) return;
296
- const { left, width } = containerRef.current.getBoundingClientRect();
297
- onChange(Math.min(Math.max((e.clientX - left) / width, 0), 1) * 360);
298
- }
299
- function handleMouseDown(e) {
300
- handleMove(e);
301
- function moveHandler(e) {
302
- handleMove(e);
303
- }
304
- function upHandler() {
305
- window.removeEventListener("mousemove", moveHandler);
306
- window.removeEventListener("mouseup", upHandler);
307
- }
308
- window.addEventListener("mousemove", moveHandler);
309
- window.addEventListener("mouseup", upHandler);
310
- }
311
- return /* @__PURE__ */ jsx("div", {
312
- ref: containerRef,
313
- className: "w-full h-3 relative rounded-full cursor-pointer mb-4 select-none",
314
- style: { background: "linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%)" },
315
- onMouseDown: handleMouseDown,
316
- children: /* @__PURE__ */ jsx("div", {
317
- className: `
318
- absolute w-4 h-4 bg-white border border-gray-200
319
- rounded-full shadow-sm -translate-x-1/2 -translate-y-1/2
320
- top-1/2 pointer-events-none
321
- `,
322
- style: { left: `${hue / 360 * 100}%` }
323
- })
324
- });
325
- }
326
- function ColorPickerPopup({ value, onChange, onClose, anchorName }) {
327
- const [hsv, setHsv] = useState(() => hexToHsv(value || "#000000"));
328
- const [hexInput, setHexInput] = useState(value || "#000000");
329
- useEffect(() => {
330
- if (value && value !== hexInput) {
331
- setHsv(hexToHsv(value));
332
- setHexInput(value);
333
- }
334
- }, [value]);
335
- function handleColorChange(newHsv) {
336
- setHsv(newHsv);
337
- const hex = hsvToHex(newHsv.h, newHsv.s, newHsv.v);
338
- setHexInput(hex);
339
- onChange(hex);
340
- }
341
- function handleSaturationChange(s, v) {
342
- handleColorChange({
343
- ...hsv,
344
- s,
345
- v
346
- });
347
- }
348
- function handleHueChange(h) {
349
- handleColorChange({
350
- ...hsv,
351
- h
352
- });
353
- }
354
- function manualHexChange(e) {
355
- const val = e.target.value;
356
- setHexInput(val);
357
- if (/^#[0-9A-F]{6}$/i.test(val)) {
358
- setHsv(hexToHsv(val));
359
- onChange(val);
360
- }
361
- }
362
- return /* @__PURE__ */ jsxs("div", {
363
- className: "fixed z-50 bg-login-700 border border-login-500/50 rounded-md shadow-xl p-3 w-64 select-none anchor-popup",
364
- style: {
365
- positionAnchor: anchorName,
366
- positionArea: "bottom span-right",
367
- insetArea: "bottom span-right",
368
- positionTryFallbacks: "flip-block",
369
- margin: "0.25rem 0"
370
- },
371
- children: [
372
- /* @__PURE__ */ jsx(SaturationPicker, {
373
- hsv,
374
- onChange: handleSaturationChange
375
- }),
376
- /* @__PURE__ */ jsx(HuePicker, {
377
- hue: hsv.h,
378
- onChange: handleHueChange
379
- }),
380
- /* @__PURE__ */ jsxs("div", {
381
- className: "flex items-center gap-2 mb-3",
382
- children: [
383
- /* @__PURE__ */ jsx("div", {
384
- className: "text-xs text-login-200 font-mono",
385
- children: "HEX"
386
- }),
387
- /* @__PURE__ */ jsx("input", {
388
- type: "text",
389
- value: hexInput,
390
- onChange: manualHexChange,
391
- className: `
392
- flex-1 min-w-0 bg-login-600 border border-login-500/50 rounded
393
- px-2 py-1 text-sm text-login-text focus:outline-none
394
- focus:border-login/60 focus:ring-1 focus:ring-login/30
395
- `,
396
- spellCheck: false
397
- }),
398
- /* @__PURE__ */ jsx("div", {
399
- className: "w-8 h-8 rounded border border-login-500/50 shrink-0",
400
- style: { backgroundColor: hexInput }
401
- })
402
- ]
403
- }),
404
- /* @__PURE__ */ jsx("div", {
405
- className: "grid grid-cols-8 gap-1.5 pt-3 border-t border-login-500/25",
406
- children: PRESET_COLORS.map((color) => /* @__PURE__ */ jsx("button", {
407
- type: "button",
408
- className: `
409
- w-6 h-6 rounded-sm cursor-pointer hover:scale-110
410
- hover:zIndex-10 transition-transform ring-1 ring-inset ring-black/10
411
- `,
412
- style: { backgroundColor: color },
413
- onClick: () => {
414
- setHsv(hexToHsv(color));
415
- setHexInput(color);
416
- onChange(color);
417
- onClose();
418
- },
419
- title: color
420
- }, color))
421
- })
422
- ]
423
- });
424
- }
425
- //#endregion
426
- //#region src/components/inputs/shared/dateTimePickerPopup.tsx
427
- const DAYS = [
428
- "Mo",
429
- "Tu",
430
- "We",
431
- "Th",
432
- "Fr",
433
- "Sa",
434
- "Su"
435
- ];
436
- const MONTHS = [
437
- "January",
438
- "February",
439
- "March",
440
- "April",
441
- "May",
442
- "June",
443
- "July",
444
- "August",
445
- "September",
446
- "October",
447
- "November",
448
- "December"
449
- ];
450
- function DateTimePickerPopup({ value, onChange, type, onClose, anchorName }) {
451
- const [currentDate, setCurrentDate] = useState(/* @__PURE__ */ new Date());
452
- const [timeInput, setTimeInput] = useState({
453
- hours: value ? value.getHours().toString() : "0",
454
- minutes: value ? value.getMinutes().toString() : "0"
455
- });
456
- useEffect(() => {
457
- if (value) {
458
- setCurrentDate(value);
459
- setTimeInput((prev) => ({
460
- hours: prev.hours === "" && value.getHours() === 0 ? "" : value.getHours().toString(),
461
- minutes: prev.minutes === "" && value.getMinutes() === 0 ? "" : value.getMinutes().toString()
462
- }));
463
- }
464
- }, [value]);
465
- function handleDateSelect(day) {
466
- const newDate = new Date(currentDate);
467
- newDate.setDate(day);
468
- if (value) {
469
- newDate.setHours(value.getHours());
470
- newDate.setMinutes(value.getMinutes());
471
- } else newDate.setHours(0, 0, 0, 0);
472
- onChange(newDate);
473
- if (type === "date" && onClose) onClose();
474
- }
475
- function handleTimeChange(timeUnit, val) {
476
- const newDate = value ? new Date(value) : /* @__PURE__ */ new Date();
477
- if (!value) newDate.setHours(0, 0, 0, 0);
478
- if (timeUnit === "hours") {
479
- if (val < 0 || val > 23) return;
480
- newDate.setHours(val);
481
- }
482
- if (timeUnit === "minutes") {
483
- if (val < 0 || val > 59) return;
484
- newDate.setMinutes(val);
485
- }
486
- onChange(newDate);
487
- }
488
- function onTimeInputChange(unit, val) {
489
- if (val === "") {
490
- setTimeInput((prev) => ({
491
- ...prev,
492
- [unit]: ""
493
- }));
494
- handleTimeChange(unit, 0);
495
- return;
496
- }
497
- if (!/^\d+$/.test(val)) return;
498
- const num = parseInt(val);
499
- if (unit === "hours" && num > 23) return;
500
- if (unit === "minutes" && num > 59) return;
501
- setTimeInput((prev) => ({
502
- ...prev,
503
- [unit]: val
504
- }));
505
- handleTimeChange(unit, num);
506
- }
507
- function onTimeInputBlur(unit) {
508
- if (timeInput[unit] === "") {
509
- const num = unit === "hours" ? value?.getHours() ?? 0 : value?.getMinutes() ?? 0;
510
- setTimeInput((prev) => ({
511
- ...prev,
512
- [unit]: num.toString()
513
- }));
514
- }
515
- }
516
- function getDaysInMonth(year, month) {
517
- return new Date(year, month + 1, 0).getDate();
518
- }
519
- function getFirstDayOfMonth(year, month) {
520
- return new Date(year, month, 1).getDay();
521
- }
522
- function renderCalendar() {
523
- const year = currentDate.getFullYear();
524
- const month = currentDate.getMonth();
525
- const daysInMonth = getDaysInMonth(year, month);
526
- const firstDay = getFirstDayOfMonth(year, month);
527
- const days = [];
528
- const adjustedFirstDay = firstDay === 0 ? 6 : firstDay - 1;
529
- for (let i = 0; i < adjustedFirstDay; i++) days.push(/* @__PURE__ */ jsx("div", { className: "w-8 h-8" }, `empty-${i}`));
530
- for (let i = 1; i <= daysInMonth; i++) {
531
- const isSelected = value && value.getDate() === i && value.getMonth() === month && value.getFullYear() === year;
532
- const isToday = (/* @__PURE__ */ new Date()).getDate() === i && (/* @__PURE__ */ new Date()).getMonth() === month && (/* @__PURE__ */ new Date()).getFullYear() === year;
533
- days.push(/* @__PURE__ */ jsx("button", {
534
- type: "button",
535
- onClick: () => handleDateSelect(i),
536
- className: `
537
- w-8 h-8 flex items-center justify-center rounded-full text-sm
538
- hover:bg-login-600 transition-colors
539
- ${isSelected ? "bg-login! text-white! hover:bg-login!" : ""}
540
- ${!isSelected && isToday ? "text-login! font-bold" : ""}
541
- ${!isSelected && !isToday ? "text-login-text!" : ""}
542
- `,
543
- children: i
544
- }, i));
545
- }
546
- return /* @__PURE__ */ jsxs("div", {
547
- className: "p-2",
548
- children: [
549
- /* @__PURE__ */ jsxs("div", {
550
- className: "flex items-center justify-between mb-2",
551
- children: [
552
- /* @__PURE__ */ jsx("button", {
553
- type: "button",
554
- onClick: () => setCurrentDate(new Date(year, month - 1)),
555
- className: "p-1 hover:bg-login-600 rounded-full text-login-text transition-colors",
556
- children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-4 h-4" })
557
- }),
558
- /* @__PURE__ */ jsxs("span", {
559
- className: "font-medium text-login-text",
560
- children: [
561
- MONTHS[month],
562
- " ",
563
- year
564
- ]
565
- }),
566
- /* @__PURE__ */ jsx("button", {
567
- type: "button",
568
- onClick: () => setCurrentDate(new Date(year, month + 1)),
569
- className: "p-1 hover:bg-login-600 rounded-full text-login-text transition-colors",
570
- children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4" })
571
- })
572
- ]
573
- }),
574
- /* @__PURE__ */ jsx("div", {
575
- className: "grid grid-cols-7 gap-1 mb-1",
576
- children: DAYS.map((d) => /* @__PURE__ */ jsx("div", {
577
- className: "w-8 text-center text-xs text-login-200 font-medium",
578
- children: d
579
- }, d))
580
- }),
581
- /* @__PURE__ */ jsx("div", {
582
- className: "grid grid-cols-7 gap-1",
583
- children: days
584
- })
585
- ]
586
- });
587
- }
588
- function renderTimePicker() {
589
- return /* @__PURE__ */ jsxs("div", {
590
- className: "p-2 border-t border-login-500/25 flex justify-center gap-2",
591
- children: [
592
- /* @__PURE__ */ jsxs("div", {
593
- className: "flex flex-col items-center",
594
- children: [/* @__PURE__ */ jsx("label", {
595
- className: "text-xs text-login-200 mb-1",
596
- children: "Hour"
597
- }), /* @__PURE__ */ jsx("input", {
598
- type: "text",
599
- inputMode: "numeric",
600
- value: timeInput.hours,
601
- onChange: (e) => onTimeInputChange("hours", e.target.value),
602
- onBlur: () => onTimeInputBlur("hours"),
603
- className: `
604
- w-16 p-1 bg-login-600 rounded text-center text-login-text text-sm
605
- border border-login-500/50 focus:border-login/60 focus:ring-1 focus:ring-login/30 outline-none
606
- `
607
- })]
608
- }),
609
- /* @__PURE__ */ jsx("div", {
610
- className: "flex items-end pb-2 text-login-text",
611
- children: ":"
612
- }),
613
- /* @__PURE__ */ jsxs("div", {
614
- className: "flex flex-col items-center",
615
- children: [/* @__PURE__ */ jsx("label", {
616
- className: "text-xs text-login-200 mb-1",
617
- children: "Minute"
618
- }), /* @__PURE__ */ jsx("input", {
619
- type: "text",
620
- inputMode: "numeric",
621
- value: timeInput.minutes,
622
- onChange: (e) => onTimeInputChange("minutes", e.target.value),
623
- onBlur: () => onTimeInputBlur("minutes"),
624
- className: `
625
- w-16 p-1 bg-login-600 rounded text-center text-login-text text-sm
626
- border border-login-500/50 focus:border-login/60 focus:ring-1 focus:ring-login/30 outline-none
627
- `
628
- })]
629
- })
630
- ]
631
- });
632
- }
633
- return /* @__PURE__ */ jsxs("div", {
634
- className: "fixed z-50 bg-login-700 border border-login-500/50 rounded-md shadow-xl p-1 min-w-70 anchor-popup",
635
- style: {
636
- positionAnchor: anchorName,
637
- positionArea: "bottom span-right",
638
- insetArea: "bottom span-right",
639
- positionTryFallbacks: "flip-block",
640
- margin: "0.25rem 0"
641
- },
642
- children: [type !== "time" && renderCalendar(), (type === "time" || type === "datetime-local") && renderTimePicker()]
643
- });
644
- }
645
- //#endregion
646
- //#region src/components/inputs/input.tsx
647
- function Input(props) {
648
- const { name, label, error, className, icon, info, description, textSize = "sm", ...inputProps } = props;
649
- const { type = "text", value } = inputProps;
650
- const localRef = useRef(null);
651
- const [isOpen, setIsOpen] = useState(false);
652
- const anchorName = `--input-${useId().replace(/:/g, "")}`;
653
- const containerRef = useRef(null);
654
- useClickOutside$1(containerRef, () => setIsOpen(false));
655
- const isDateType = [
656
- "date",
657
- "datetime-local",
658
- "time"
659
- ].includes(type);
660
- const isColorType = type === "color";
661
- const isClickableType = isDateType || isColorType;
662
- function handleIconClick() {
663
- if (isClickableType && !inputProps.disabled) setIsOpen(!isOpen);
664
- else if (localRef.current && !inputProps.disabled) localRef.current.focus();
665
- }
666
- function pad(n) {
667
- return n.toString().padStart(2, "0");
668
- }
669
- function handleDateChange(date) {
670
- const onChange = inputProps.onChange;
671
- if (!onChange) return;
672
- const yyyy = date.getFullYear();
673
- const MM = pad(date.getMonth() + 1);
674
- const dd = pad(date.getDate());
675
- const hh = pad(date.getHours());
676
- const mm = pad(date.getMinutes());
677
- let newValue = "";
678
- if (type === "date") newValue = `${yyyy}-${MM}-${dd}`;
679
- else if (type === "time") newValue = `${hh}:${mm}`;
680
- else if (type === "datetime-local") newValue = `${yyyy}-${MM}-${dd}T${hh}:${mm}`;
681
- onChange({ target: {
682
- name,
683
- value: newValue,
684
- type
685
- } });
686
- }
687
- function handleColorChange(color) {
688
- const onChange = inputProps.onChange;
689
- if (!onChange) return;
690
- onChange({ target: {
691
- name,
692
- value: color,
693
- type
694
- } });
695
- }
696
- let displayIcon = icon;
697
- if (!displayIcon && isDateType) if (type === "time") displayIcon = /* @__PURE__ */ jsx(Clock, { className: "w-4 h-4" });
698
- else displayIcon = /* @__PURE__ */ jsx(Calendar, { className: "w-4 h-4" });
699
- else if (!displayIcon && isColorType) displayIcon = /* @__PURE__ */ jsx("div", {
700
- className: "w-4 h-4 rounded border border-login-200",
701
- style: { backgroundColor: value || "#000000" }
702
- });
703
- function getDateValue() {
704
- if (!value) return null;
705
- if (type === "time") {
706
- const date = /* @__PURE__ */ new Date(`2000-01-01T${value}`);
707
- return isNaN(date.getTime()) ? null : date;
708
- }
709
- const date = new Date(value);
710
- return isNaN(date.getTime()) ? null : date;
711
- }
712
- function getDateDisplayValue() {
713
- if (!value || !isDateType) return value;
714
- const date = getDateValue();
715
- if (!date) return value;
716
- const yyyy = date.getFullYear();
717
- const MM = pad(date.getMonth() + 1);
718
- const dd = pad(date.getDate());
719
- const hh = pad(date.getHours());
720
- const mm = pad(date.getMinutes());
721
- if (type === "date") return `${dd}.${MM}.${yyyy}`;
722
- if (type === "time") return `${hh}:${mm}`;
723
- if (type === "datetime-local") return `${dd}.${MM}.${yyyy} ${hh}:${mm}`;
724
- return value;
725
- }
726
- return /* @__PURE__ */ jsx(FieldWrapper, {
727
- label,
728
- name,
729
- required: inputProps.required,
730
- info,
731
- error,
732
- description,
733
- textSize,
734
- className,
735
- children: /* @__PURE__ */ jsxs("div", {
736
- className: "relative flex items-center",
737
- ref: containerRef,
738
- children: [
739
- displayIcon && /* @__PURE__ */ jsx("div", {
740
- className: `
741
- absolute left-3 text-login-200
742
- ${isClickableType && !inputProps.disabled ? "cursor-pointer hover:text-login-text" : "pointer-events-none"}
743
- `,
744
- onClick: handleIconClick,
745
- children: displayIcon
746
- }),
747
- /* @__PURE__ */ jsx("input", {
748
- ...inputProps,
749
- ref: localRef,
750
- id: name,
751
- name: isClickableType ? void 0 : name,
752
- type: isClickableType ? "text" : type,
753
- value: isDateType ? getDateDisplayValue() : value,
754
- readOnly: isClickableType,
755
- onClick: () => isClickableType && !inputProps.disabled && setIsOpen(true),
756
- "aria-describedby": error ? `${name}-error` : void 0,
757
- style: { anchorName },
758
- className: `
759
- w-full rounded-md bg-login-500/50 border border-login-500
760
- text-login-text placeholder-login-200 text-sm
761
- focus:outline-none focus:border-login/60 focus:ring-1 focus:ring-login/30
762
- disabled:opacity-40 disabled:cursor-not-allowed
763
- h-10 py-2 ${displayIcon ? "pl-10 pr-3" : "px-3"}
764
- transition-all duration-150
765
- input-reset
766
- ${error ? "border-red-500/70 focus:border-red-500/70 focus:ring-red-500/30" : ""}
767
- ${isClickableType && !inputProps.disabled ? "cursor-pointer" : ""}
768
- `
769
- }),
770
- isClickableType && /* @__PURE__ */ jsx("input", {
771
- type: "hidden",
772
- name,
773
- value
774
- }),
775
- isOpen && isDateType && !inputProps.disabled && /* @__PURE__ */ jsx(DateTimePickerPopup, {
776
- value: getDateValue(),
777
- onChange: handleDateChange,
778
- type,
779
- onClose: () => setIsOpen(false),
780
- anchorName
781
- }),
782
- isOpen && isColorType && !inputProps.disabled && /* @__PURE__ */ jsx(ColorPickerPopup, {
783
- value: value || "",
784
- onChange: handleColorChange,
785
- onClose: () => setIsOpen(false),
786
- anchorName
787
- })
788
- ]
789
- })
790
- });
791
- }
792
- //#endregion
793
- //#region src/components/inputs/searchInput.tsx
794
- function SearchInput({ placeholder = "Search...", variant = "default" }) {
795
- const router = useRouter();
796
- const pathname = usePathname();
797
- const searchParams = useSearchParams();
798
- const [searchValue, setSearchValue] = useState(searchParams.get("q") || "");
799
- useEffect(() => {
800
- setSearchValue(searchParams.get("q") || "");
801
- }, [searchParams]);
802
- function handleSearch(value) {
803
- setSearchValue(value);
804
- const params = new URLSearchParams(searchParams.toString());
805
- if (value.trim()) params.set("q", value.trim());
806
- else params.delete("q");
807
- params.delete("page");
808
- router.push(`${pathname}?${params.toString()}`);
809
- }
810
- function handleKeyDown(e) {
811
- if (e.key === "Enter") handleSearch(searchValue);
812
- }
813
- function handleChange(e) {
814
- setSearchValue(e.target.value);
815
- }
816
- if (variant === "minimal") return /* @__PURE__ */ jsxs("div", {
817
- className: "relative",
818
- children: [/* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 h-5 w-5" }), /* @__PURE__ */ jsx("input", {
819
- type: "text",
820
- value: searchValue,
821
- onChange: (e) => setSearchValue(e.target.value),
822
- onKeyDown: handleKeyDown,
823
- onBlur: () => handleSearch(searchValue),
824
- placeholder,
825
- className: "pl-10 pr-4 py-2 border-b outline-none w-64"
826
- })]
827
- });
828
- else return /* @__PURE__ */ jsx("div", {
829
- className: "w-fit min-w-48",
830
- children: /* @__PURE__ */ jsx(Input, {
831
- name: "search",
832
- icon: /* @__PURE__ */ jsx(Search, { className: "w-5 h-5" }),
833
- value: searchValue,
834
- onChange: handleChange,
835
- onKeyDown: handleKeyDown,
836
- onBlur: () => handleSearch(searchValue),
837
- placeholder
838
- })
839
- });
840
- }
841
- //#endregion
842
- //#region src/components/inputs/textarea.tsx
843
- function isValidJson(str) {
844
- try {
845
- JSON.parse(str);
846
- return null;
847
- } catch (error) {
848
- return error.message;
849
- }
850
- }
851
- function Textarea(props) {
852
- const { name, label, error, className, info, description, type = "text", rows = 4, textSize = "sm", ...textareaProps } = props;
853
- const { value } = textareaProps;
854
- const [preview, setPreview] = useState(false);
855
- const displayError = (type === "json" && value ? isValidJson(value) : void 0) || error;
856
- return /* @__PURE__ */ jsx(FieldWrapper, {
857
- label,
858
- name,
859
- required: textareaProps.required,
860
- info,
861
- description,
862
- error: displayError,
863
- textSize,
864
- className,
865
- children: /* @__PURE__ */ jsxs("div", {
866
- className: "relative",
867
- children: [
868
- type === "markdown" && /* @__PURE__ */ jsx("div", {
869
- className: "absolute right-2 top-2 z-10 flex gap-2",
870
- children: /* @__PURE__ */ jsx("button", {
871
- type: "button",
872
- onClick: () => setPreview(!preview),
873
- className: "p-1 rounded hover:bg-login-500/50 text-login-text transition-colors",
874
- title: preview ? "Edit" : "Preview",
875
- children: preview ? /* @__PURE__ */ jsx(Pencil, { size: 16 }) : /* @__PURE__ */ jsx(Eye, { size: 16 })
876
- })
877
- }),
878
- type === "markdown" && preview && /* @__PURE__ */ jsx("div", {
879
- className: `
880
- w-full rounded-md bg-login-500/50 border border-login-500
881
- p-3 overflow-y-auto ${error ? "border-red-500/70" : ""}
882
- `,
883
- children: /* @__PURE__ */ jsx(MarkdownRender, { MDstr: String(value || "") })
884
- }),
885
- /* @__PURE__ */ jsx("textarea", {
886
- ...textareaProps,
887
- id: name,
888
- name,
889
- rows,
890
- title: label,
891
- "aria-invalid": !!error,
892
- "aria-describedby": error ? `${name}-error` : void 0,
893
- className: `
894
- ${type === "markdown" && preview ? "hidden" : ""}
895
- w-full rounded-md bg-login-500/50 border border-login-500
896
- text-login-text placeholder-login-200 text-sm
897
- focus:outline-none focus:border-login/60 focus:ring-1 focus:ring-login/30
898
- disabled:opacity-40 disabled:cursor-not-allowed
899
- p-3 pr-10
900
- transition-all duration-150
901
- resize-y
902
- ${error ? "border-red-500/70 focus:border-red-500/70 focus:ring-red-500/30" : ""}
903
- `
904
- })
905
- ]
906
- })
907
- });
908
- }
909
- //#endregion
910
- //#region src/components/inputs/checkbox.tsx
911
- function Checkbox(props) {
912
- const { options, onChange, value, label, description, error, info, name, className, textSize = "sm", ...rest } = props;
913
- const selectedValues = Array.isArray(value) ? value : [];
914
- return /* @__PURE__ */ jsx(FieldWrapper, {
915
- label,
916
- name,
917
- required: rest.required,
918
- info,
919
- description,
920
- error,
921
- textSize,
922
- className,
923
- children: /* @__PURE__ */ jsx("div", {
924
- className: "flex flex-col gap-2",
925
- children: options.map((option) => /* @__PURE__ */ jsx(CheckboxItem, {
926
- name,
927
- value: option.value,
928
- label: option.label,
929
- checked: selectedValues.includes(option.value),
930
- disabled: rest.disabled,
931
- onChange: (e) => {
932
- if (!onChange) return;
933
- const isChecked = e.target.checked;
934
- let newValues = [...selectedValues];
935
- if (isChecked) newValues.push(option.value);
936
- else newValues = newValues.filter((v) => v !== option.value);
937
- onChange(newValues);
938
- },
939
- className: "mb-0"
940
- }, option.value))
941
- })
942
- });
943
- }
944
- function CheckboxItem(props) {
945
- const { name, label, error, ...inputProps } = props;
946
- const id = inputProps.value ? `${name}-${inputProps.value}` : name;
947
- return /* @__PURE__ */ jsxs("div", {
948
- className: "flex items-center gap-2",
949
- children: [/* @__PURE__ */ jsxs("div", {
950
- className: "relative w-5 h-5 shrink-0",
951
- children: [/* @__PURE__ */ jsx("input", {
952
- ...inputProps,
953
- id,
954
- name,
955
- type: "checkbox",
956
- className: `
957
- peer appearance-none rounded border border-login-500 bg-login-500/50
958
- checked:bg-login checked:border-login
959
- focus:outline-none focus:ring-1 focus:ring-login/30
960
- disabled:opacity-40 disabled:cursor-not-allowed
961
- cursor-pointer transition-all duration-150
962
- w-5 h-5 absolute inset-0
963
- ${error ? "border-red-500/70" : ""}
964
- `
965
- }), /* @__PURE__ */ jsx(Check, { className: `
966
- absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2
967
- w-3.5 h-3.5 pointer-events-none text-white opacity-0
968
- peer-checked:opacity-100 transition-opacity duration-200
969
- ` })]
970
- }), label && /* @__PURE__ */ jsx(InputLabel, {
971
- label,
972
- name,
973
- disabled: inputProps.disabled,
974
- className: "select-none cursor-pointer"
975
- })]
976
- });
977
- }
978
- //#endregion
979
- //#region src/components/inputs/select.tsx
980
- function Select({ label, name, value, onChange, options, error, className, disabled, required, placeholder = "Select an option", info, description, clearable = true, searchable = true, textSize = "sm" }) {
981
- const [isOpen, setIsOpen] = useState(false);
982
- const [searchTerm, setSearchTerm] = useState("");
983
- const [selectedOption, setSelectedOption] = useState(options.find((opt) => opt.value === value));
984
- useEffect(() => {
985
- if (!isOpen) setSearchTerm("");
986
- }, [isOpen]);
987
- useEffect(() => {
988
- setSelectedOption(options.find((opt) => opt.value === value));
989
- }, [value, options]);
990
- const containerRef = useRef(null);
991
- useClickOutside$1(containerRef, () => setIsOpen(false));
992
- function handleSelect(option) {
993
- if (disabled) return;
994
- setSelectedOption(option);
995
- setIsOpen(false);
996
- if (onChange) onChange(option.value);
997
- }
998
- function handleClear(e) {
999
- e.stopPropagation();
1000
- if (disabled) return;
1001
- setSelectedOption(void 0);
1002
- if (onChange) onChange(null);
1003
- }
1004
- const filteredOptions = options.filter((option) => option.label.toLowerCase().includes(searchTerm.toLowerCase()));
1005
- return /* @__PURE__ */ jsxs(FieldWrapper, {
1006
- label,
1007
- name,
1008
- required,
1009
- info,
1010
- description,
1011
- error,
1012
- textSize,
1013
- className,
1014
- children: [/* @__PURE__ */ jsxs("div", {
1015
- className: "relative",
1016
- ref: containerRef,
1017
- children: [/* @__PURE__ */ jsxs("button", {
1018
- type: "button",
1019
- onClick: () => !disabled && setIsOpen(!isOpen),
1020
- disabled,
1021
- "aria-haspopup": "listbox",
1022
- "aria-expanded": isOpen,
1023
- "aria-labelledby": label ? void 0 : name,
1024
- className: `
1025
- w-full rounded-md bg-login-500/50 border border-login-500
1026
- text-login-text text-left text-sm
1027
- focus:outline-none focus:border-login/60 focus:ring-1 focus:ring-login/30
1028
- disabled:opacity-40 disabled:cursor-not-allowed
1029
- h-10 py-2 pl-3 pr-10
1030
- transition-all duration-150
1031
- flex items-center justify-between
1032
- ${error ? "border-red-500/70 focus:border-red-500/70 focus:ring-red-500/30" : ""}
1033
- ${!selectedOption ? "text-login-200" : ""}
1034
- `,
1035
- title: label,
1036
- children: [/* @__PURE__ */ jsxs("div", {
1037
- className: "flex items-center gap-2 truncate",
1038
- children: [selectedOption?.image && /* @__PURE__ */ jsx(Image, {
1039
- src: selectedOption.image,
1040
- alt: "",
1041
- width: 30,
1042
- height: 20,
1043
- className: "rounded-xs object-cover shrink-0"
1044
- }), /* @__PURE__ */ jsx("span", {
1045
- className: "truncate",
1046
- children: selectedOption ? selectedOption.label : placeholder
1047
- })]
1048
- }), /* @__PURE__ */ jsxs("div", {
1049
- className: "absolute inset-y-0 right-0 flex items-center px-2 gap-1",
1050
- children: [clearable && selectedOption && !disabled && /* @__PURE__ */ jsx("div", {
1051
- role: "button",
1052
- onClick: handleClear,
1053
- className: `
1054
- p-1 hover:bg-login-500 rounded-full text-login-200
1055
- hover:text-red-400 transition-colors cursor-pointer
1056
- `,
1057
- title: "Clear selection",
1058
- children: /* @__PURE__ */ jsx(X, { className: "w-3 h-3" })
1059
- }), /* @__PURE__ */ jsx("div", {
1060
- className: `
1061
- text-login-200 pointer-events-none
1062
- transition-transform duration-200
1063
- ${isOpen ? "rotate-180" : ""}
1064
- `,
1065
- children: /* @__PURE__ */ jsx(ChevronDown, { className: "w-4 h-4" })
1066
- })]
1067
- })]
1068
- }), isOpen && /* @__PURE__ */ jsxs("div", {
1069
- className: `
1070
- absolute z-50 w-full mt-1 bg-login-700 border border-login-500/50
1071
- rounded-md shadow-xl max-h-60 overflow-hidden flex flex-col
1072
- `,
1073
- children: [searchable && /* @__PURE__ */ jsx("div", {
1074
- className: "p-2 sticky top-0 bg-login-700 border-b border-login-500/20 z-10",
1075
- children: /* @__PURE__ */ jsxs("div", {
1076
- className: "relative",
1077
- children: [/* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-login-200" }), /* @__PURE__ */ jsx("input", {
1078
- type: "text",
1079
- value: searchTerm,
1080
- onChange: (e) => setSearchTerm(e.target.value),
1081
- placeholder: "Search...",
1082
- autoFocus: true,
1083
- className: `
1084
- w-full bg-login-600 border border-login-500/50 rounded-md
1085
- py-1.5 pl-9 pr-3 text-sm text-login-text
1086
- focus:outline-none focus:border-login/60 focus:ring-1 focus:ring-login/30
1087
- `
1088
- })]
1089
- })
1090
- }), /* @__PURE__ */ jsx("div", {
1091
- className: "overflow-auto noscroll",
1092
- children: filteredOptions.length > 0 ? /* @__PURE__ */ jsx("ul", {
1093
- className: "py-1",
1094
- role: "listbox",
1095
- children: filteredOptions.map((option) => /* @__PURE__ */ jsx("li", {
1096
- role: "option",
1097
- "aria-selected": selectedOption?.value === option.value,
1098
- children: /* @__PURE__ */ jsxs("button", {
1099
- type: "button",
1100
- onClick: () => handleSelect(option),
1101
- className: `
1102
- w-full text-left px-3 py-2 text-sm
1103
- hover:bg-login-600 transition-colors duration-150
1104
- flex items-center gap-2
1105
- ${selectedOption?.value === option.value ? "bg-login/15 text-login" : "text-login-text"}
1106
- `,
1107
- children: [option.image && /* @__PURE__ */ jsx(Image, {
1108
- src: option.image,
1109
- alt: "",
1110
- width: 75,
1111
- height: 25,
1112
- className: "rounded-md object-cover shrink-0"
1113
- }), /* @__PURE__ */ jsx("span", {
1114
- className: "truncate",
1115
- children: option.label
1116
- })]
1117
- })
1118
- }, option.value))
1119
- }) : /* @__PURE__ */ jsx("div", {
1120
- className: "px-3 py-2 text-sm text-login-200",
1121
- children: searchTerm ? "No results found" : "No options available"
1122
- })
1123
- })]
1124
- })]
1125
- }), /* @__PURE__ */ jsx("input", {
1126
- type: "hidden",
1127
- name,
1128
- value: selectedOption?.value || "",
1129
- required
1130
- })]
1131
- });
1132
- }
1133
- //#endregion
1134
- //#region src/components/inputs/tagInput.tsx
1135
- function TagInput({ label, name, value = [], onChange, placeholder = "Add...", error, className, disabled, required, info, description, textSize = "sm" }) {
1136
- const [inputValue, setInputValue] = useState("");
1137
- function handleKeyDown(e) {
1138
- if ((e.key === "Enter" || e.key === ",") && inputValue.trim()) {
1139
- e.preventDefault();
1140
- const val = inputValue.trim().replace(/,$/, "");
1141
- if (val && !value.includes(val)) {
1142
- const newValue = [...value, val];
1143
- if (onChange) onChange(newValue);
1144
- }
1145
- setInputValue("");
1146
- } else if (e.key === "Backspace" && !inputValue && value.length > 0) {
1147
- const newValue = value.slice(0, -1);
1148
- if (onChange) onChange(newValue);
1149
- }
1150
- }
1151
- function removeTag(index) {
1152
- if (disabled) return;
1153
- const newValue = value.filter((_, i) => i !== index);
1154
- if (onChange) onChange(newValue);
1155
- }
1156
- return /* @__PURE__ */ jsxs(FieldWrapper, {
1157
- label,
1158
- name,
1159
- required,
1160
- info,
1161
- description,
1162
- error,
1163
- className,
1164
- textSize,
1165
- children: [/* @__PURE__ */ jsxs("div", {
1166
- className: `
1167
- flex flex-wrap gap-2 p-2 rounded-md bg-login-500/50 border border-login-500
1168
- text-login-text min-h-10
1169
- focus-within:border-login/60 focus-within:ring-1 focus-within:ring-login/30
1170
- transition-all duration-150
1171
- ${error ? "border-red-500/70 focus-within:border-red-500/70 focus-within:ring-red-500/30" : ""}
1172
- `,
1173
- children: [value.map((tag, index) => /* @__PURE__ */ jsxs("span", {
1174
- className: "flex items-center gap-1 px-2 py-0.5 bg-login-600 text-login-100 border border-login-500 rounded text-sm",
1175
- children: [tag, !disabled && /* @__PURE__ */ jsx("button", {
1176
- type: "button",
1177
- onClick: () => removeTag(index),
1178
- className: "hover:text-red-200 transition-colors",
1179
- children: /* @__PURE__ */ jsx(X, { size: 14 })
1180
- })]
1181
- }, index)), /* @__PURE__ */ jsx("input", {
1182
- type: "text",
1183
- value: inputValue,
1184
- required: required && value.length === 0,
1185
- onChange: (e) => setInputValue(e.target.value),
1186
- onKeyDown: handleKeyDown,
1187
- disabled,
1188
- placeholder: value.length === 0 ? placeholder : "",
1189
- className: "flex-1 bg-transparent outline-none min-w-30 text-login-text placeholder:text-login-200"
1190
- })]
1191
- }), /* @__PURE__ */ jsx("input", {
1192
- type: "hidden",
1193
- name,
1194
- value: value.join(",")
1195
- })]
1196
- });
1197
- }
1198
- //#endregion
1199
- //#region src/components/inputs/multiSelect.tsx
1200
- function MultiSelect({ label, name, options, value = [], onChange, placeholder = "Select…", error, className, disabled, required, info, description, textSize = "sm" }) {
1201
- const [open, setOpen] = useState(false);
1202
- const containerRef = useRef(null);
1203
- useClickOutside$1(containerRef, () => setOpen(false));
1204
- function toggleOption(optionValue) {
1205
- if (!onChange) return;
1206
- if (value.includes(optionValue)) onChange(value.filter((v) => v !== optionValue));
1207
- else onChange([...value, optionValue]);
1208
- }
1209
- function removeOption(optionValue) {
1210
- if (!onChange) return;
1211
- onChange(value.filter((v) => v !== optionValue));
1212
- }
1213
- return /* @__PURE__ */ jsx(FieldWrapper, {
1214
- label,
1215
- name,
1216
- required,
1217
- info,
1218
- description,
1219
- error,
1220
- className,
1221
- textSize,
1222
- children: /* @__PURE__ */ jsxs("div", {
1223
- ref: containerRef,
1224
- className: "relative w-full",
1225
- children: [
1226
- /* @__PURE__ */ jsxs("div", {
1227
- onClick: () => !disabled && setOpen((o) => !o),
1228
- className: `
1229
- flex min-h-10 cursor-pointer items-center justify-between gap-2
1230
- rounded-md bg-login-500/50 border border-login-500 px-3 py-1.5
1231
- transition-all duration-150 select-none
1232
- ${open ? "border-login/60 ring-1 ring-login/30" : ""}
1233
- ${error ? "border-red-500/70" : ""}
1234
- ${disabled ? "opacity-40 cursor-not-allowed" : ""}
1235
- `,
1236
- children: [/* @__PURE__ */ jsxs("div", {
1237
- className: "flex flex-wrap gap-1.5",
1238
- children: [value.length === 0 && /* @__PURE__ */ jsx("span", {
1239
- className: "text-sm text-login-200",
1240
- children: placeholder
1241
- }), value.map((val) => {
1242
- const option = options.find((o) => o.value === val);
1243
- if (!option) return null;
1244
- return /* @__PURE__ */ jsxs("span", {
1245
- className: "\n flex items-center gap-1 rounded px-2 py-0.5 text-sm\n border border-login-500 bg-login-600 text-login-100\n ",
1246
- children: [option.label, !disabled && /* @__PURE__ */ jsx("button", {
1247
- type: "button",
1248
- onClick: (e) => {
1249
- e.stopPropagation();
1250
- removeOption(val);
1251
- },
1252
- className: "hover:text-red-300 transition-colors",
1253
- children: /* @__PURE__ */ jsx(X, { size: 13 })
1254
- })]
1255
- }, val);
1256
- })]
1257
- }), /* @__PURE__ */ jsx(ChevronDown, {
1258
- size: 16,
1259
- className: `shrink-0 text-login-200 transition-transform duration-150 ${open ? "rotate-180" : ""}`
1260
- })]
1261
- }),
1262
- open && options.length > 0 && /* @__PURE__ */ jsx("div", {
1263
- className: "\n absolute z-50 mt-1 w-full max-h-60 overflow-auto\n rounded-md border border-login-500/50 bg-login-800 shadow-lg\n ",
1264
- children: options.map((option) => {
1265
- const selected = value.includes(option.value);
1266
- return /* @__PURE__ */ jsxs("div", {
1267
- onClick: () => toggleOption(option.value),
1268
- className: `
1269
- flex cursor-pointer items-center justify-between px-3 py-2 text-sm
1270
- hover:bg-login-700 transition-colors select-none
1271
- ${selected ? "text-login-50" : "text-login-100"}
1272
- `,
1273
- children: [/* @__PURE__ */ jsx("span", { children: option.label }), selected && /* @__PURE__ */ jsx(Check, {
1274
- size: 14,
1275
- className: "text-login shrink-0"
1276
- })]
1277
- }, option.value);
1278
- })
1279
- }),
1280
- /* @__PURE__ */ jsx("input", {
1281
- type: "hidden",
1282
- name,
1283
- value: value.join(",")
1284
- })
1285
- ]
1286
- })
1287
- });
1288
- }
1289
- //#endregion
1290
- //#region src/components/inputs/switch.tsx
1291
- function Switch(props) {
1292
- const { name, label, error, info, description, className, switchOnly, textSize = "sm", ...inputProps } = props;
1293
- return /* @__PURE__ */ jsx(FieldWrapper, {
1294
- label,
1295
- name,
1296
- required: inputProps.required,
1297
- info,
1298
- error,
1299
- description,
1300
- textSize,
1301
- className,
1302
- children: /* @__PURE__ */ jsxs("label", {
1303
- className: `group/sw inline-flex items-center cursor-pointer ${switchOnly ? "h-fit" : "h-10"}`,
1304
- children: [/* @__PURE__ */ jsx("input", {
1305
- ...inputProps,
1306
- type: "checkbox",
1307
- id: name,
1308
- name,
1309
- className: "sr-only"
1310
- }), /* @__PURE__ */ jsx("div", {
1311
- className: `
1312
- relative flex items-center w-11 h-6 rounded-full transition-colors
1313
- bg-login-600 group-has-[input:checked]/sw:bg-login
1314
- ${inputProps.disabled ? "opacity-40 cursor-not-allowed" : ""}
1315
- ${error ? "ring-1 ring-red-500/60" : ""}
1316
- `,
1317
- children: /* @__PURE__ */ jsx("span", { className: "\n absolute inset-y-0 my-auto left-0.5 h-5 w-5\n rounded-full bg-white shadow-sm transition-all\n group-has-[input:checked]/sw:translate-x-full\n " })
1318
- })]
1319
- })
1320
- });
1321
- }
1322
- //#endregion
1323
- //#region src/components/inputs/radio.tsx
1324
- function Radio(props) {
1325
- const { options, onChange, value, label, description, error, info, name, className, textSize = "sm", ...rest } = props;
1326
- return /* @__PURE__ */ jsx(FieldWrapper, {
1327
- label,
1328
- name,
1329
- required: rest.required,
1330
- info,
1331
- description,
1332
- error,
1333
- textSize,
1334
- className,
1335
- children: /* @__PURE__ */ jsx("div", {
1336
- className: "flex flex-col gap-2",
1337
- children: options.map((option) => /* @__PURE__ */ jsx(RadioItem, {
1338
- name,
1339
- value: option.value,
1340
- label: option.label,
1341
- checked: value === option.value,
1342
- disabled: rest.disabled,
1343
- onChange: () => {
1344
- if (onChange) onChange(option.value);
1345
- },
1346
- className: "mb-0"
1347
- }, option.value))
1348
- })
1349
- });
1350
- }
1351
- function RadioItem(props) {
1352
- const { name, label, error, ...inputProps } = props;
1353
- const { value } = inputProps;
1354
- const id = `${name}-${value}`;
1355
- return /* @__PURE__ */ jsxs("div", {
1356
- className: "flex items-center gap-2",
1357
- children: [/* @__PURE__ */ jsxs("div", {
1358
- className: "relative w-5 h-5 shrink-0",
1359
- children: [/* @__PURE__ */ jsx("input", {
1360
- ...inputProps,
1361
- id,
1362
- name,
1363
- type: "radio",
1364
- className: `
1365
- peer appearance-none rounded-full border border-login-500 bg-login-500/50
1366
- checked:bg-login checked:border-login
1367
- focus:outline-none focus:ring-1 focus:ring-login/30
1368
- disabled:opacity-40 disabled:cursor-not-allowed
1369
- cursor-pointer transition-all duration-150
1370
- w-5 h-5 absolute inset-0
1371
- ${error ? "border-red-500/70" : ""}
1372
- `
1373
- }), /* @__PURE__ */ jsx("div", { className: `
1374
- absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2
1375
- w-2 h-2 rounded-full bg-white pointer-events-none opacity-0
1376
- peer-checked:opacity-100 transition-opacity duration-200
1377
- ` })]
1378
- }), label && /* @__PURE__ */ jsx(InputLabel, {
1379
- label,
1380
- name,
1381
- disabled: inputProps.disabled,
1382
- className: "select-none cursor-pointer"
1383
- })]
1384
- });
1385
- }
1386
- //#endregion
1387
- //#region src/components/inputs/range.tsx
1388
- function Range(props) {
1389
- const { name, label, error, className, info, description, showValue = true, textSize = "sm", ...inputProps } = props;
1390
- const { min = 0, max = 100, step = 1, value, defaultValue, onChange, ...restInputProps } = inputProps;
1391
- const displayValue = value ?? defaultValue ?? 0;
1392
- return /* @__PURE__ */ jsx(FieldWrapper, {
1393
- label,
1394
- name,
1395
- required: restInputProps.required,
1396
- info,
1397
- description,
1398
- error,
1399
- textSize,
1400
- className,
1401
- children: /* @__PURE__ */ jsxs("div", {
1402
- className: "flex items-center gap-4",
1403
- children: [/* @__PURE__ */ jsx("input", {
1404
- ...restInputProps,
1405
- id: name,
1406
- name,
1407
- type: "range",
1408
- min,
1409
- max,
1410
- step,
1411
- ...onChange ? {
1412
- value,
1413
- onChange
1414
- } : { defaultValue: value ?? defaultValue ?? 0 },
1415
- title: label,
1416
- "aria-invalid": !!error,
1417
- "aria-describedby": error ? `${name}-error` : void 0,
1418
- className: `
1419
- flex-1 h-2 bg-login-500 rounded-lg appearance-none cursor-pointer
1420
- accent-login
1421
- [&::-webkit-slider-thumb]:appearance-none
1422
- [&::-webkit-slider-thumb]:w-4
1423
- [&::-webkit-slider-thumb]:h-4
1424
- [&::-webkit-slider-thumb]:rounded-full
1425
- [&::-webkit-slider-thumb]:bg-login
1426
- [&::-moz-range-thumb]:w-4
1427
- [&::-moz-range-thumb]:h-4
1428
- [&::-moz-range-thumb]:rounded-full
1429
- [&::-moz-range-thumb]:bg-login
1430
- [&::-moz-range-thumb]:border-none
1431
- disabled:opacity-50 disabled:cursor-not-allowed
1432
- ${error ? "accent-red-500" : ""}
1433
- `
1434
- }), showValue && /* @__PURE__ */ jsx("span", {
1435
- className: "text-login-text text-sm font-medium min-w-10 text-right",
1436
- children: displayValue
1437
- })]
1438
- })
1439
- });
1440
- }
1441
- //#endregion
1442
- //#region src/components/logo/logo.tsx
1443
- function Logo({ className }) {
1444
- const corner = "fill-[var(--foreground)] transition-all duration-1000";
1445
- const letter = "fill-none stroke-[var(--color-login)] stroke-[3.5px]";
1446
- return /* @__PURE__ */ jsxs("svg", {
1447
- className: `block w-full max-w-2xl mx-auto ${className || ""}`,
1448
- viewBox: "0 0 147.02299 59.20511",
1449
- children: [
1450
- /* @__PURE__ */ jsx("path", {
1451
- className: corner,
1452
- d: "m 28.77713,58.37738 v 0.76465 H 25.531 v -5.61816 h 0.91309 v 4.85351 z"
1453
- }),
1454
- /* @__PURE__ */ jsx("path", {
1455
- className: corner,
1456
- d: "m 30.47831,59.142 h -0.917 v -5.61813 h 0.917 z"
1457
- }),
1458
- /* @__PURE__ */ jsx("path", {
1459
- className: corner,
1460
- d: "M 36.46268,53.52387 V 59.142 H 35.99881 A 0.36347,0.36347 0 0 1 35.6785,58.98185 L 32.59256,55.018 c 0.0078,0.07617 0.01368,0.15039 0.01758,0.22461 0.0039,0.07422 0.0059,0.14258 0.0059,0.20508 V 59.142 h -0.80371 v -5.61813 h 0.47656 a 0.71321,0.71321 0 0 1 0.09864,0.0059 0.3128,0.3128 0 0 1 0.07617,0.02148 0.22919,0.22919 0 0 1 0.0664,0.04688 0.63781,0.63781 0 0 1 0.06641,0.07812 l 3.08984,3.96779 c -0.0078,-0.08105 -0.01367,-0.16015 -0.01757,-0.23828 -0.0039,-0.07813 -0.0059,-0.15039 -0.0059,-0.21875 v -3.6631 z"
1461
- }),
1462
- /* @__PURE__ */ jsx("path", {
1463
- className: corner,
1464
- d: "m 39.84549,57.1684 a 2.91264,2.91264 0 0 1 -0.11523,0.84765 1.748,1.748 0 0 1 -0.34375,0.64063 1.52483,1.52483 0 0 1 -0.56543,0.40527 2.00691,2.00691 0 0 1 -0.78223,0.14258 3.23707,3.23707 0 0 1 -0.40234,-0.0254 3.44454,3.44454 0 0 1 -0.41309,-0.0801 l 0.04688,-0.5459 a 0.2079,0.2079 0 0 1 0.06055,-0.125 0.19754,0.19754 0 0 1 0.14257,-0.0469 0.74035,0.74035 0 0 1 0.18067,0.0293 1.36468,1.36468 0 0 0 0.71387,-0.041 0.74722,0.74722 0 0 0 0.3125,-0.2207 0.9864,0.9864 0 0 0 0.1914,-0.38574 2.19551,2.19551 0 0 0 0.06445,-0.57227 v -3.667 h 0.90918 z"
1465
- }),
1466
- /* @__PURE__ */ jsx("path", {
1467
- className: corner,
1468
- d: "m 44.6326,58.40473 -0.0039,0.7373 h -3.50391 v -5.61816 h 3.50391 v 0.7373 h -2.58692 v 1.69336 h 2.06739 v 0.71387 h -2.06739 v 1.73633 z"
1469
- }),
1470
- /* @__PURE__ */ jsx("path", {
1471
- className: corner,
1472
- d: "M 46.53592,54.26117 V 56.06 h 2.19629 v 0.7373 h -2.19629 v 2.3447 h -0.917 v -5.61813 h 3.50391 v 0.7373 z"
1473
- }),
1474
- /* @__PURE__ */ jsx("path", {
1475
- className: corner,
1476
- d: "m 55.25956,56.33344 a 3.18179,3.18179 0 0 1 -0.20215,1.15039 2.6634,2.6634 0 0 1 -0.57227,0.90722 2.59685,2.59685 0 0 1 -0.88476,0.59473 3.17156,3.17156 0 0 1 -2.29492,0 2.62415,2.62415 0 0 1 -0.88672,-0.59473 2.65327,2.65327 0 0 1 -0.57422,-0.90722 3.37717,3.37717 0 0 1 0,-2.30176 2.67118,2.67118 0 0 1 0.57422,-0.90918 2.61491,2.61491 0 0 1 0.88672,-0.59668 3.1717,3.1717 0 0 1 2.29492,0 2.58781,2.58781 0 0 1 0.88476,0.59668 2.68144,2.68144 0 0 1 0.57227,0.90918 3.1871,3.1871 0 0 1 0.20215,1.15137 z m -0.93164,0 a 2.706,2.706 0 0 0 -0.13086,-0.87012 1.821,1.821 0 0 0 -0.375,-0.65527 1.63008,1.63008 0 0 0 -0.59082,-0.41407 2.16795,2.16795 0 0 0 -1.55664,0 1.65415,1.65415 0 0 0 -0.59278,0.41407 1.84212,1.84212 0 0 0 -0.3789,0.65527 2.92611,2.92611 0 0 0 0,1.74316 1.83766,1.83766 0 0 0 0.3789,0.6543 1.64222,1.64222 0 0 0 0.59278,0.40918 2.19564,2.19564 0 0 0 1.55664,0 1.61838,1.61838 0 0 0 0.59082,-0.40918 1.81652,1.81652 0 0 0 0.375,-0.6543 2.71589,2.71589 0 0 0 0.13086,-0.87304 z"
1477
- }),
1478
- /* @__PURE__ */ jsx("path", {
1479
- className: corner,
1480
- d: "m 60.534,59.142 h -0.81543 a 0.377,0.377 0 0 1 -0.35156,-0.1875 l -1.31055,-1.8916 a 0.4267,0.4267 0 0 0 -0.14453,-0.14063 0.50286,0.50286 0 0 0 -0.23437,-0.043 H 57.17072 V 59.142 H 56.2576 v -5.61813 h 1.6543 a 3.54427,3.54427 0 0 1 0.9541,0.11328 1.80649,1.80649 0 0 1 0.65723,0.32226 1.25606,1.25606 0 0 1 0.37988,0.501 1.76427,1.76427 0 0 1 0.03516,1.19727 1.50418,1.50418 0 0 1 -0.25293,0.46093 1.61283,1.61283 0 0 1 -0.40821,0.3584 2.04861,2.04861 0 0 1 -0.5498,0.23828 0.92346,0.92346 0 0 1 0.28906,0.28516 z m -2.64551,-2.92578 a 1.763,1.763 0 0 0 0.5459,-0.07617 1.11007,1.11007 0 0 0 0.39063,-0.21289 0.87892,0.87892 0 0 0 0.23437,-0.3252 1.10093,1.10093 0 0 0 0.07715,-0.41992 0.84276,0.84276 0 0 0 -0.30371,-0.70215 1.46527,1.46527 0 0 0 -0.9209,-0.24219 h -0.74121 v 1.97852 z"
1481
- }),
1482
- /* @__PURE__ */ jsx("path", {
1483
- className: corner,
1484
- d: "m 64.72049,58.40473 -0.0039,0.7373 h -3.50391 v -5.61816 h 3.50391 v 0.7373 h -2.58692 v 1.69336 h 2.06739 v 0.71387 h -2.06739 v 1.73633 z"
1485
- }),
1486
- /* @__PURE__ */ jsx("path", {
1487
- className: corner,
1488
- d: "M 70.35721,53.52387 V 59.142 H 69.89335 A 0.36347,0.36347 0 0 1 69.57303,58.98185 L 66.4871,55.018 c 0.0078,0.07617 0.01367,0.15039 0.01757,0.22461 0.0039,0.07422 0.0059,0.14258 0.0059,0.20508 V 59.142 h -0.80371 v -5.61813 h 0.47656 a 0.71321,0.71321 0 0 1 0.09864,0.0059 0.3128,0.3128 0 0 1 0.07617,0.02148 0.22936,0.22936 0 0 1 0.06641,0.04688 0.63869,0.63869 0 0 1 0.0664,0.07812 l 3.08985,3.96777 c -0.008,-0.08105 -0.0137,-0.16015 -0.0176,-0.23828 -0.004,-0.07813 -0.006,-0.15039 -0.006,-0.21875 v -3.66308 z"
1489
- }),
1490
- /* @__PURE__ */ jsx("path", {
1491
- className: corner,
1492
- d: "m 72.6121,59.142 h -0.917 v -5.61813 h 0.917 z"
1493
- }),
1494
- /* @__PURE__ */ jsx("path", {
1495
- className: corner,
1496
- d: "M 78.59794,53.52387 V 59.142 H 78.13358 A 0.36344,0.36344 0 0 1 77.81327,58.98185 L 74.72733,55.018 c 0.008,0.07617 0.0137,0.15039 0.0176,0.22461 0.004,0.07422 0.006,0.14258 0.006,0.20508 V 59.142 h -0.80371 v -5.61813 h 0.47656 a 0.713,0.713 0 0 1 0.0986,0.0059 0.31254,0.31254 0 0 1 0.0762,0.02148 0.22936,0.22936 0 0 1 0.0664,0.04688 0.63869,0.63869 0 0 1 0.0664,0.07812 l 3.08984,3.96777 c -0.008,-0.08105 -0.0137,-0.16015 -0.0176,-0.23828 -0.004,-0.07813 -0.006,-0.15039 -0.006,-0.21875 v -3.66308 z"
1497
- }),
1498
- /* @__PURE__ */ jsx("path", {
1499
- className: corner,
1500
- d: "M 84.53544,56.37641 V 58.6 a 3.24425,3.24425 0 0 1 -1.9502,0.60449 3.419,3.419 0 0 1 -1.23535,-0.21289 2.7275,2.7275 0 0 1 -0.94141,-0.59277 2.59231,2.59231 0 0 1 -0.60156,-0.90723 3.08634,3.08634 0 0 1 -0.21,-1.1582 3.23536,3.23536 0 0 1 0.20215,-1.165 2.5484,2.5484 0 0 1 1.49414,-1.498 3.29189,3.29189 0 0 1 1.20215,-0.209 3.52605,3.52605 0 0 1 0.62988,0.05273 3.11559,3.11559 0 0 1 0.54,0.14649 2.535,2.535 0 0 1 0.84668,0.52246 l -0.26074,0.418 a 0.26545,0.26545 0 0 1 -0.16016,0.12109 0.27377,0.27377 0 0 1 -0.21094,-0.04688 c -0.0752,-0.04492 -0.15527,-0.09082 -0.24023,-0.14062 a 2.01137,2.01137 0 0 0 -0.29,-0.13867 2.127,2.127 0 0 0 -0.37891,-0.10547 2.72656,2.72656 0 0 0 -0.50683,-0.041 2.09434,2.09434 0 0 0 -0.80176,0.14649 1.70173,1.70173 0 0 0 -0.61035,0.418 1.84692,1.84692 0 0 0 -0.39063,0.65722 2.5766,2.5766 0 0 0 -0.13672,0.86231 2.62333,2.62333 0 0 0 0.14453,0.89844 1.88731,1.88731 0 0 0 0.41016,0.67187 1.74772,1.74772 0 0 0 0.6416,0.419 2.55647,2.55647 0 0 0 1.459,0.0703 2.80344,2.80344 0 0 0 0.53222,-0.207 V 57.07074 H 82.928 a 0.19287,0.19287 0 0 1 -0.13964,-0.04883 0.16848,0.16848 0 0 1 -0.0508,-0.12695 v -0.51855 z"
1501
- }),
1502
- /* @__PURE__ */ jsx("path", {
1503
- className: corner,
1504
- d: "m 89.1243,58.40473 -0.004,0.7373 h -3.50391 v -5.61816 h 3.50391 v 0.7373 h -2.58692 v 1.69336 h 2.06739 v 0.71387 h -2.06739 v 1.73633 z"
1505
- }),
1506
- /* @__PURE__ */ jsx("path", {
1507
- className: corner,
1508
- d: "M 94.761,53.52387 V 59.142 H 94.29713 A 0.36347,0.36347 0 0 1 93.97682,58.98185 L 90.8909,55.018 c 0.008,0.07617 0.0137,0.15039 0.0176,0.22461 0.004,0.07422 0.006,0.14258 0.006,0.20508 V 59.142 h -0.80371 v -5.61813 h 0.47656 a 0.71321,0.71321 0 0 1 0.0986,0.0059 0.3128,0.3128 0 0 1 0.0762,0.02148 0.22919,0.22919 0 0 1 0.0664,0.04688 0.63781,0.63781 0 0 1 0.0664,0.07812 l 3.08984,3.96777 c -0.008,-0.08105 -0.0137,-0.16015 -0.0176,-0.23828 -0.004,-0.07813 -0.006,-0.15039 -0.006,-0.21875 v -3.66308 z"
1509
- }),
1510
- /* @__PURE__ */ jsx("path", {
1511
- className: corner,
1512
- d: "M 98.95829,54.26117 V 56.06 h 2.19629 v 0.7373 h -2.19629 v 2.3447 h -0.917 v -5.61813 h 3.5039 v 0.7373 z"
1513
- }),
1514
- /* @__PURE__ */ jsx("path", {
1515
- className: corner,
1516
- d: "m 107.68192,56.33344 a 3.18158,3.18158 0 0 1 -0.20215,1.15039 2.66353,2.66353 0 0 1 -0.57226,0.90722 2.597,2.597 0 0 1 -0.88477,0.59473 3.17156,3.17156 0 0 1 -2.29492,0 2.62415,2.62415 0 0 1 -0.88672,-0.59473 2.65327,2.65327 0 0 1 -0.57422,-0.90722 3.37717,3.37717 0 0 1 0,-2.30176 2.67118,2.67118 0 0 1 0.57422,-0.90918 2.61491,2.61491 0 0 1 0.88672,-0.59668 3.1717,3.1717 0 0 1 2.29492,0 2.588,2.588 0 0 1 0.88477,0.59668 2.68157,2.68157 0 0 1 0.57226,0.90918 3.18689,3.18689 0 0 1 0.20215,1.15137 z m -0.93164,0 a 2.706,2.706 0 0 0 -0.13086,-0.87012 1.82066,1.82066 0 0 0 -0.375,-0.65527 1.63,1.63 0 0 0 -0.59082,-0.41407 2.16795,2.16795 0 0 0 -1.55664,0 1.65411,1.65411 0 0 0 -0.59277,0.41407 1.84214,1.84214 0 0 0 -0.37891,0.65527 2.92632,2.92632 0 0 0 0,1.74316 1.83768,1.83768 0 0 0 0.37891,0.6543 1.64218,1.64218 0 0 0 0.59277,0.40918 2.19564,2.19564 0 0 0 1.55664,0 1.61829,1.61829 0 0 0 0.59082,-0.40918 1.81623,1.81623 0 0 0 0.375,-0.6543 2.71589,2.71589 0 0 0 0.13086,-0.87304 z"
1517
- }),
1518
- /* @__PURE__ */ jsx("path", {
1519
- className: corner,
1520
- d: "m 112.95731,59.142 h -0.81543 a 0.377,0.377 0 0 1 -0.35156,-0.1875 l -1.31055,-1.8916 a 0.4267,0.4267 0 0 0 -0.14453,-0.14063 0.50286,0.50286 0 0 0 -0.23437,-0.043 H 109.594 V 59.142 h -0.91309 v -5.61813 h 1.6543 a 3.54427,3.54427 0 0 1 0.9541,0.11328 1.80649,1.80649 0 0 1 0.65723,0.32226 1.25606,1.25606 0 0 1 0.37988,0.501 1.76427,1.76427 0 0 1 0.0352,1.19727 1.50418,1.50418 0 0 1 -0.25293,0.46093 1.61283,1.61283 0 0 1 -0.40821,0.3584 2.04861,2.04861 0 0 1 -0.5498,0.23828 0.92346,0.92346 0 0 1 0.28906,0.28516 z m -2.64551,-2.92578 a 1.763,1.763 0 0 0 0.5459,-0.07617 1.11007,1.11007 0 0 0 0.39063,-0.21289 0.87892,0.87892 0 0 0 0.23437,-0.3252 1.10093,1.10093 0 0 0 0.0772,-0.41992 0.84276,0.84276 0 0 0 -0.30371,-0.70215 1.46527,1.46527 0 0 0 -0.9209,-0.24219 H 109.594 v 1.97852 z"
1521
- }),
1522
- /* @__PURE__ */ jsx("path", {
1523
- className: corner,
1524
- d: "m 116.4954,59.142 h -0.917 v -5.61813 h 0.917 z"
1525
- }),
1526
- /* @__PURE__ */ jsx("path", {
1527
- className: corner,
1528
- d: "m 121.69559,54.28461 h -1.75195 V 59.142 h -0.9082 v -4.85739 h -1.75586 v -0.76074 h 4.416 z"
1529
- }),
1530
- /* @__PURE__ */ jsx("polyline", {
1531
- className: letter,
1532
- style: { strokeMiterlimit: 10 },
1533
- points: "47.871 98.1 33.189 98.1 33.189 83.418",
1534
- transform: "translate(-31.392,-41.894)"
1535
- }),
1536
- /* @__PURE__ */ jsx("polyline", {
1537
- className: letter,
1538
- style: { strokeMiterlimit: 10 },
1539
- points: "33.142 58.326 33.142 43.644 47.824 43.644",
1540
- transform: "translate(-31.392,-41.894)"
1541
- }),
1542
- /* @__PURE__ */ jsx("polyline", {
1543
- className: letter,
1544
- style: { strokeMiterlimit: 10 },
1545
- points: "161.983 98.122 176.665 98.122 176.665 83.44",
1546
- transform: "translate(-31.392,-41.894)"
1547
- }),
1548
- /* @__PURE__ */ jsx("polyline", {
1549
- className: letter,
1550
- style: { strokeMiterlimit: 10 },
1551
- points: "176.665 58.372 176.665 43.69 161.983 43.69",
1552
- transform: "translate(-31.392,-41.894)"
1553
- }),
1554
- /* @__PURE__ */ jsx("path", {
1555
- className: corner,
1556
- d: "m 30.02449,40.19351 v 4.12842 H 12.4991 V 13.99038 h 4.92871 v 26.20313 z"
1557
- }),
1558
- /* @__PURE__ */ jsx("path", {
1559
- className: corner,
1560
- d: "m 61.53523,29.1564 a 17.15942,17.15942 0 0 1 -1.09473,6.21338 14.35971,14.35971 0 0 1 -3.08593,4.89746 14.091,14.091 0 0 1 -4.78125,3.21191 17.1289,17.1289 0 0 1 -12.38575,0 13.98317,13.98317 0 0 1 -7.88867,-8.10937 18.18161,18.18161 0 0 1 0,-12.42725 14.39119,14.39119 0 0 1 3.09668,-4.90771 14.13157,14.13157 0 0 1 4.792,-3.22315 17.13565,17.13565 0 0 1 12.38575,0 14.02046,14.02046 0 0 1 4.78125,3.22315 14.47032,14.47032 0 0 1 3.08593,4.90771 17.16209,17.16209 0 0 1 1.09472,6.21387 z m -5.03418,0 a 14.62587,14.62587 0 0 0 -0.70508,-4.69727 9.9446,9.9446 0 0 0 -2.02246,-3.53906 8.80545,8.80545 0 0 0 -3.1914,-2.23242 11.719,11.719 0 0 0 -8.4043,0 8.90077,8.90077 0 0 0 -3.20117,2.23242 9.96735,9.96735 0 0 0 -2.043,3.53906 15.81644,15.81644 0 0 0 0,9.415 9.847,9.847 0 0 0 2.043,3.52832 8.85094,8.85094 0 0 0 3.20117,2.21192 11.87213,11.87213 0 0 0 8.4043,0 8.75623,8.75623 0 0 0 3.1914,-2.21192 9.82454,9.82454 0 0 0 2.02249,-3.52828 14.69371,14.69371 0 0 0 0.70505,-4.71777 z"
1561
- }),
1562
- /* @__PURE__ */ jsx("path", {
1563
- className: corner,
1564
- d: "m 91.76082,29.38784 v 12.00635 a 17.5354,17.5354 0 0 1 -10.53125,3.26465 18.41512,18.41512 0 0 1 -6.667,-1.148 14.80254,14.80254 0 0 1 -5.08691,-3.20166 14.0148,14.0148 0 0 1 -3.24316,-4.897 16.691,16.691 0 0 1 -1.1377,-6.25586 17.42935,17.42935 0 0 1 1.09473,-6.2876 13.74023,13.74023 0 0 1 8.06738,-8.08838 17.7222,17.7222 0 0 1 6.48828,-1.127 19.10354,19.10354 0 0 1 3.40137,0.28418 16.85244,16.85244 0 0 1 2.917,0.79 13.68442,13.68442 0 0 1 2.48633,1.22168 13.95372,13.95372 0 0 1 2.085,1.60058 l -1.41113,2.25391 a 1.40229,1.40229 0 0 1 -0.86426,0.65283 1.47784,1.47784 0 0 1 -1.13672,-0.25244 q -0.6123,-0.35816 -1.2959,-0.7583 a 11.33129,11.33129 0 0 0 -1.56933,-0.748 11.53387,11.53387 0 0 0 -2.043,-0.56836 14.78335,14.78335 0 0 0 -2.73828,-0.22119 11.32128,11.32128 0 0 0 -4.32813,0.78955 9.26752,9.26752 0 0 0 -3.29687,2.25391 9.99164,9.99164 0 0 0 -2.10645,3.54931 13.90267,13.90267 0 0 0 -0.7373,4.65528 14.11731,14.11731 0 0 0 0.77929,4.855 10.1425,10.1425 0 0 0 2.21192,3.62305 9.43419,9.43419 0 0 0 3.46484,2.26416 13.81975,13.81975 0 0 0 7.87793,0.3789 15.14816,15.14816 0 0 0 2.875,-1.11621 v -6.02383 h -4.2334 a 1.04883,1.04883 0 0 1 -0.75879,-0.26367 0.90553,0.90553 0 0 1 -0.27343,-0.68457 v -2.80127 z"
1565
- }),
1566
- /* @__PURE__ */ jsx("path", {
1567
- className: corner,
1568
- d: "M 102.546,44.32193 H 97.59581 V 13.99038 h 4.95019 z"
1569
- }),
1570
- /* @__PURE__ */ jsx("path", {
1571
- className: corner,
1572
- d: "m 134.8575,13.99038 v 30.33155 h -2.50684 a 2.14219,2.14219 0 0 1 -0.96875,-0.2002 2.26108,2.26108 0 0 1 -0.75879,-0.66357 L 113.962,22.05777 q 0.063,0.61083 0.0947,1.21093 0.0322,0.60058 0.0322,1.106 v 19.94723 h -4.3398 V 13.99038 h 2.57031 a 3.89092,3.89092 0 0 1 0.53711,0.03174 1.53328,1.53328 0 0 1 0.41016,0.11572 1.18964,1.18964 0 0 1 0.35839,0.25293 4.01792,4.01792 0 0 1 0.3584,0.4209 l 16.68164,21.42188 q -0.063,-0.65259 -0.0947,-1.28467 -0.0308,-0.63208 -0.0312,-1.17969 V 13.99038 Z"
1573
- })
1574
- ]
1575
- });
1576
- }
1577
- //#endregion
1578
- //#region src/components/logo/logoSmall.tsx
1579
- function LogoSmall() {
1580
- const corner = "fill-login";
1581
- const letter = "fill-[var(--foreground)] transition-all duration-1000";
1582
- return /* @__PURE__ */ jsxs("svg", {
1583
- className: "block h-full",
1584
- viewBox: "0 0 100 100",
1585
- fill: "none",
1586
- xmlns: "http://www.w3.org/2000/svg",
1587
- children: [
1588
- /* @__PURE__ */ jsx("path", {
1589
- className: corner,
1590
- d: "M0 0H6.6667V28.3333H0V0Z"
1591
- }),
1592
- /* @__PURE__ */ jsx("path", {
1593
- className: corner,
1594
- d: "M28.3333 0V6.6667H0V0H28.3333Z"
1595
- }),
1596
- /* @__PURE__ */ jsx("path", {
1597
- className: corner,
1598
- d: "M100 0V6.6667H71.6667V0H100Z"
1599
- }),
1600
- /* @__PURE__ */ jsx("path", {
1601
- className: corner,
1602
- d: "M100 28.3333H93.3333V0H100V28.3333Z"
1603
- }),
1604
- /* @__PURE__ */ jsx("path", {
1605
- className: corner,
1606
- d: "M0 100V93.3333H28.3333V100H0Z"
1607
- }),
1608
- /* @__PURE__ */ jsx("path", {
1609
- className: corner,
1610
- d: "M0 71.6667H6.6667V100H0V71.6667Z"
1611
- }),
1612
- /* @__PURE__ */ jsx("path", {
1613
- className: corner,
1614
- d: "M100 100H93.3333V71.6667H100V100Z"
1615
- }),
1616
- /* @__PURE__ */ jsx("path", {
1617
- className: corner,
1618
- d: "M71.6667 100V93.3333H100V100H71.6667Z"
1619
- }),
1620
- /* @__PURE__ */ jsx("path", {
1621
- className: letter,
1622
- d: "M31.6667 18.3333H43.3334V81.6666H31.6667V18.3333Z"
1623
- }),
1624
- /* @__PURE__ */ jsx("path", {
1625
- className: letter,
1626
- d: "M31.6667 70H68.3334V81.6667H31.6667V70Z"
1627
- })
1628
- ]
1629
- });
1630
- }
1631
- //#endregion
1632
- //#region src/components/toggle/theme.tsx
1633
- function ThemeToggle({ className }) {
1634
- const router = useRouter();
1635
- const [theme, setTheme] = useState("dark");
1636
- useEffect(() => {
1637
- const savedTheme = getCookie("theme");
1638
- if (savedTheme) setTheme(savedTheme);
1639
- document.documentElement.classList.remove("dark", "light");
1640
- document.documentElement.classList.add(theme);
1641
- }, [theme]);
1642
- function toggleTheme() {
1643
- const newTheme = theme === "dark" ? "light" : "dark";
1644
- setCookie("theme", newTheme);
1645
- setTheme(newTheme);
1646
- router.refresh();
1647
- }
1648
- return /* @__PURE__ */ jsx("div", {
1649
- className: `grid place-items-center justify-end rounded-md hover:bg-login-300/20 w-fit ${className}`,
1650
- children: /* @__PURE__ */ jsxs("label", {
1651
- className: "cursor-pointer",
1652
- children: [/* @__PURE__ */ jsx("input", {
1653
- type: "checkbox",
1654
- checked: theme === "light",
1655
- onChange: toggleTheme,
1656
- className: "sr-only"
1657
- }), /* @__PURE__ */ jsx(ThemeIcon, { theme })]
1658
- })
1659
- });
1660
- }
1661
- function ThemeIcon({ theme }) {
1662
- const sunrayClass = `fill-white transition-opacity duration-400 ${theme === "light" ? "opacity-0" : "opacity-100"}`;
1663
- return /* @__PURE__ */ jsxs("svg", {
1664
- className: "h-12 p-3",
1665
- viewBox: "0 0 100 100",
1666
- xmlns: "http://www.w3.org/2000/svg",
1667
- children: [
1668
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("mask", {
1669
- id: "theme-toggle_clip-path",
1670
- children: [/* @__PURE__ */ jsx("rect", {
1671
- x: "0",
1672
- y: "0",
1673
- width: "100",
1674
- height: "100",
1675
- fill: "white"
1676
- }), /* @__PURE__ */ jsx("circle", {
1677
- className: `transition-transform duration-400 ${theme === "dark" ? "translate-x-8 -translate-y-4" : ""}`,
1678
- cx: "68",
1679
- cy: "40",
1680
- r: "18"
1681
- })]
1682
- }) }),
1683
- /* @__PURE__ */ jsx("circle", {
1684
- className: `origin-center transition-all duration-400 ${theme === "light" ? "scale-[1.9] fill-black" : "scale-100 fill-white"}`,
1685
- mask: "url(#theme-toggle_clip-path)",
1686
- cx: "50",
1687
- cy: "50",
1688
- r: "23"
1689
- }),
1690
- /* @__PURE__ */ jsx("rect", {
1691
- className: sunrayClass,
1692
- x: "86",
1693
- y: "47",
1694
- width: "14",
1695
- height: "6",
1696
- rx: "3"
1697
- }),
1698
- /* @__PURE__ */ jsx("rect", {
1699
- className: sunrayClass,
1700
- y: "47",
1701
- width: "14",
1702
- height: "6",
1703
- rx: "3"
1704
- }),
1705
- /* @__PURE__ */ jsx("rect", {
1706
- className: sunrayClass,
1707
- x: "47",
1708
- y: "86",
1709
- width: "6",
1710
- height: "14",
1711
- rx: "3"
1712
- }),
1713
- /* @__PURE__ */ jsx("rect", {
1714
- className: sunrayClass,
1715
- x: "75",
1716
- y: "75",
1717
- width: "6",
1718
- height: "14",
1719
- rx: "3",
1720
- transform: "rotate(-45 78 78)"
1721
- }),
1722
- /* @__PURE__ */ jsx("rect", {
1723
- className: sunrayClass,
1724
- x: "84.8995",
1725
- y: "12",
1726
- width: "6",
1727
- height: "14",
1728
- rx: "3",
1729
- transform: "rotate(45 84.8995 12)"
1730
- }),
1731
- /* @__PURE__ */ jsx("rect", {
1732
- className: sunrayClass,
1733
- x: "22.8995",
1734
- y: "74",
1735
- width: "6",
1736
- height: "14",
1737
- rx: "3",
1738
- transform: "rotate(45 22.8995 74)"
1739
- }),
1740
- /* @__PURE__ */ jsx("rect", {
1741
- className: sunrayClass,
1742
- x: "13",
1743
- y: "16.2426",
1744
- width: "6",
1745
- height: "14",
1746
- rx: "3",
1747
- transform: "rotate(-45 13 16.2426)"
1748
- }),
1749
- /* @__PURE__ */ jsx("rect", {
1750
- className: sunrayClass,
1751
- x: "47",
1752
- y: "0",
1753
- width: "6",
1754
- height: "14",
1755
- rx: "3"
1756
- })
1757
- ]
1758
- });
1759
- }
1760
- //#endregion
1761
- //#region src/components/toggle/language.tsx
1762
- function LanguageToggle({ language }) {
1763
- const [lang, setLang] = useState(language || "en");
1764
- const [jump, setJump] = useState(false);
1765
- const router = useRouter();
1766
- useEffect(() => {
1767
- const savedLang = getCookie("lang");
1768
- if (savedLang) setLang(savedLang);
1769
- }, []);
1770
- function handleClick() {
1771
- const newLang = lang === "no" ? "en" : "no";
1772
- setCookie("lang", newLang);
1773
- setLang(newLang);
1774
- language = newLang;
1775
- setJump(true);
1776
- setTimeout(() => setJump(false), 400);
1777
- router.refresh();
1778
- }
1779
- return /* @__PURE__ */ jsxs("button", {
1780
- value: lang,
1781
- onClick: handleClick,
1782
- className: `cursor-pointer p-2 leading-8 text-base w-[4.3rem] text-center rounded
1783
- bg-transparent border-none hover:bg-gray-400/10 flex flex-row items-center justify-center gap-1`,
1784
- children: [/* @__PURE__ */ jsx(Globe, { className: `text-xl leading-8 -mt-0.5 ${jump ? "animate-jump" : ""}` }), " " + lang]
1785
- });
1786
- }
1787
- //#endregion
1788
- //#region src/components/navbar/bubble.tsx
1789
- function Bubble({ bubble }) {
1790
- if (bubble.hide) return null;
1791
- return /* @__PURE__ */ jsxs("a", {
1792
- href: bubble.href,
1793
- className: `absolute top-13 min-w-40 ${bubble.className}`,
1794
- children: [/* @__PURE__ */ jsxs("svg", {
1795
- viewBox: "0 0 24 12",
1796
- className: "absolute -top-3 h-3 w-6",
1797
- "aria-hidden": "true",
1798
- children: [/* @__PURE__ */ jsx("path", {
1799
- d: "M12 0 24 12H0Z",
1800
- fill: bubble.fill,
1801
- stroke: bubble.stroke,
1802
- strokeWidth: "1.5",
1803
- strokeLinejoin: "round"
1804
- }), /* @__PURE__ */ jsx("path", {
1805
- d: "M12 0 24 12H0Z",
1806
- fill: bubble.fill
1807
- })]
1808
- }), /* @__PURE__ */ jsxs("div", {
1809
- className: "flex justify-between",
1810
- children: [/* @__PURE__ */ jsx("span", {
1811
- className: "min-w-40",
1812
- children: bubble.text
1813
- }), /* @__PURE__ */ jsx(X, {
1814
- onClick: bubble.handleHide,
1815
- className: bubble.x
1816
- })]
1817
- })]
1818
- });
1819
- }
1820
- //#endregion
1821
- //#region src/components/navbar/navbar.tsx
1822
- function Navbar({ children, bubble, className, disableLanguageToggle, disableThemeToggle, innerClassName, lang, loginPath, logoutPath, onlyLogo, profilePath, token }) {
1823
- const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
1824
- return /* @__PURE__ */ jsx("div", {
1825
- className: `${isMobileMenuOpen ? "bg-[#181818f0]" : "bg-[#18181899]"} backdrop-blur-xl fixed top-0 z-900 w-full ${className}`,
1826
- children: /* @__PURE__ */ jsxs("div", {
1827
- className: `flex w-full max-w-6xl m-auto p-2 transition duration-500 800px:justify-between 800px:p-4 ${isMobileMenuOpen ? "h-screen bg-login-900/20 800px:h-20" : ""} ${innerClassName}
1828
- `,
1829
- children: [/* @__PURE__ */ jsx("div", {
1830
- className: "block h-12 p-1 800px:p-0",
1831
- children: /* @__PURE__ */ jsx(Link, {
1832
- href: "/",
1833
- onClick: () => setIsMobileMenuOpen(false),
1834
- children: /* @__PURE__ */ jsx(LogoSmall, {})
1835
- })
1836
- }), onlyLogo ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
1837
- /* @__PURE__ */ jsx("nav", {
1838
- className: "hidden 800px:flex 800px:justify-between 800px:items-center 800px:w-fill max-w-200",
1839
- children
1840
- }),
1841
- /* @__PURE__ */ jsxs("nav", {
1842
- className: "flex w-[calc(100vw-8rem)] justify-end h-12 800px:w-fit",
1843
- children: [
1844
- /* @__PURE__ */ jsxs("div", {
1845
- className: "relative grid gap-2",
1846
- children: [!disableThemeToggle && /* @__PURE__ */ jsx(ThemeToggle, {}), bubble?.theme?.condition && /* @__PURE__ */ jsx(Bubble, { bubble: bubble.theme })]
1847
- }),
1848
- /* @__PURE__ */ jsxs("div", {
1849
- className: "relative grid gap-2",
1850
- children: [!disableLanguageToggle && /* @__PURE__ */ jsx(LanguageToggle, { language: lang }), bubble?.lang?.condition && /* @__PURE__ */ jsx(Bubble, { bubble: bubble.lang })]
1851
- }),
1852
- /* @__PURE__ */ jsxs("div", {
1853
- className: "relative grid gap-2",
1854
- children: [loginPath && logoutPath && /* @__PURE__ */ jsx(AuthButton, {
1855
- profilePath,
1856
- token,
1857
- loginPath,
1858
- logoutPath
1859
- }), bubble?.login?.condition && /* @__PURE__ */ jsx(Bubble, { bubble: bubble.login })]
1860
- })
1861
- ]
1862
- }),
1863
- /* @__PURE__ */ jsxs("button", {
1864
- className: "w-12 h-12 relative cursor-pointer bg-none border-none 800px:hidden",
1865
- onClick: () => setIsMobileMenuOpen(!isMobileMenuOpen),
1866
- children: [/* @__PURE__ */ jsx("div", { className: hamburgerStyle(isMobileMenuOpen) }), /* @__PURE__ */ jsx("div", { className: hamburgerStyle(isMobileMenuOpen, true) })]
1867
- }),
1868
- /* @__PURE__ */ jsx("nav", {
1869
- className: `fixed top-16 w-[calc(100%-2rem)] max-w-140 mx-auto left-0 right-0 800px:hidden
1870
- transition-all duration-500 ease-in-out overflow-hidden
1871
- ${isMobileMenuOpen ? "max-h-[calc(100vh-4rem)] opacity-100" : "max-h-0 opacity-0"}`,
1872
- onClick: () => setIsMobileMenuOpen(false),
1873
- children: React.Children.map(children, (child, index) => /* @__PURE__ */ jsx("div", {
1874
- className: `transition-all duration-500 ease-out ${isMobileMenuOpen ? "opacity-100 transform translate-y-0" : "opacity-0 transform -translate-y-4"}`,
1875
- style: { transitionDelay: isMobileMenuOpen ? `${index * 80}ms` : "0ms" },
1876
- children: child
1877
- }, index))
1878
- })
1879
- ] })]
1880
- })
1881
- });
1882
- }
1883
- function AuthButton({ profilePath, logoutPath, loginPath, token }) {
1884
- return /* @__PURE__ */ jsx("div", {
1885
- className: "rounded-[0.3rem] hover:bg-login-300/20 h-12 w-12",
1886
- children: token ? /* @__PURE__ */ jsxs(Fragment, { children: [logoutPath && /* @__PURE__ */ jsx(Link, {
1887
- href: logoutPath,
1888
- prefetch: false,
1889
- onClick: (e) => {
1890
- e.preventDefault();
1891
- window.location.href = logoutPath;
1892
- },
1893
- className: "grid items-center justify-center h-full w-full",
1894
- children: /* @__PURE__ */ jsx(LogOut, { size: 24 })
1895
- }), profilePath && /* @__PURE__ */ jsx(Link, {
1896
- href: profilePath,
1897
- className: "grid items-center justify-center h-full w-full",
1898
- children: /* @__PURE__ */ jsx(User, { size: 24 })
1899
- })] }) : /* @__PURE__ */ jsx(Link, {
1900
- href: loginPath,
1901
- className: "grid items-center justify-center h-full w-full",
1902
- children: /* @__PURE__ */ jsx(User, { size: 24 })
1903
- })
1904
- });
1905
- }
1906
- function hamburgerStyle(isOpen, isSecond) {
1907
- return `bg-login-50 h-0.5 absolute w-8 transition-all duration-[400ms] left-2 ${isOpen ? `top-6 ${isSecond ? "rotate-45" : "-rotate-45"}` : isSecond ? "top-7" : "top-4"}`;
1908
- }
1909
- //#endregion
1910
- //#region src/components/navbar/navbarItem.tsx
1911
- const commonStyling = "list-none flex no-underline items-center gap-2 whitespace-nowrap cursor-pointer";
1912
- function NavItem({ href, children, external = false, target, rel, title, icon }) {
1913
- const linkProps = {
1914
- href,
1915
- target,
1916
- rel,
1917
- title
1918
- };
1919
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Link, {
1920
- ...linkProps,
1921
- className: "hidden 800px:flex",
1922
- children: /* @__PURE__ */ jsxs("li", {
1923
- className: `${commonStyling} text-base leading-4 p-3 font-bold transition-colors link-corner-hover
1924
- group-[.dropdown]:p-2.5 group-[.dropdown]:pr-3 group-[.dropdown]:pl-1`,
1925
- children: [
1926
- icon,
1927
- children,
1928
- external && /* @__PURE__ */ jsx(ArrowUpRight, { className: "w-6 h-6 stroke-login" })
1929
- ]
1930
- })
1931
- }), /* @__PURE__ */ jsx(Link, {
1932
- ...linkProps,
1933
- className: "800px:hidden",
1934
- children: /* @__PURE__ */ jsxs("li", {
1935
- className: `${commonStyling} text-2xl leading-6 overflow-hidden w-auto pl-4 rounded-[0.3rem] transition-all
1936
- duration-600 opacity-100 h-16 py-5 group-[.dropdown]:p-0 group-[.dropdown]:text-lg group-[.dropdown]:h-auto
1937
- group-[.dropdown]:py-2.5 group-[.dropdown]:pl-4`,
1938
- children: [children, external && /* @__PURE__ */ jsx(ArrowUpRight, { className: "w-6 h-6 stroke-login" })]
1939
- })
1940
- })] });
1941
- }
1942
- //#endregion
1943
- //#region src/components/navbar/navbarDropdown.tsx
1944
- function NavDropdown({ children, title, className }) {
1945
- const [isMobileDropdownOpen, setIsMobileDropdownOpen] = useState(false);
1946
- const [isDesktopOpen, setIsDesktopOpen] = useState(false);
1947
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
1948
- className: "relative hidden 800px:block",
1949
- children: /* @__PURE__ */ jsxs("div", {
1950
- className: "outline-none",
1951
- tabIndex: 0,
1952
- ref: useRef(null),
1953
- onMouseEnter: () => setIsDesktopOpen(true),
1954
- onMouseLeave: () => setIsDesktopOpen(false),
1955
- onFocus: () => setIsDesktopOpen(true),
1956
- onBlur: () => setIsDesktopOpen(false),
1957
- children: [/* @__PURE__ */ jsxs("div", {
1958
- className: `list-none no-underline text-base leading-4 p-3 font-bold cursor-pointer flex flex-row items-center
1959
- transition-colors`,
1960
- children: [title, /* @__PURE__ */ jsx(ChevronDown, { className: "w-6 h-6 stroke-login ml-1 text-2xl transition-transform duration-300 ease-in-out" })]
1961
- }), /* @__PURE__ */ jsx("div", {
1962
- className: `absolute pt-2 -ml-4 transition-all duration-200 ease-in-out z-10 ${isDesktopOpen ? "opacity-100 pointer-events-auto translate-y-0" : "opacity-0 pointer-events-none -translate-y-4"}`,
1963
- children: /* @__PURE__ */ jsx("ul", {
1964
- className: `p-3 px-6 pb-4 rounded-[0.4rem] shadow-[0_0.1rem_0.5rem_rgba(3,3,3,0.5)] bg-login-700/98 ${className || ""}`,
1965
- onClick: () => setIsDesktopOpen(false),
1966
- children: React.Children.map(children, (child, index) => /* @__PURE__ */ jsx("div", {
1967
- onClick: () => setIsDesktopOpen(false),
1968
- className: "group dropdown",
1969
- children: child
1970
- }, index))
1971
- })
1972
- })]
1973
- })
1974
- }), /* @__PURE__ */ jsxs("div", {
1975
- className: "block 800px:hidden!",
1976
- children: [/* @__PURE__ */ jsx("button", {
1977
- className: "bg-none border-none cursor-pointer w-full text-left",
1978
- onClick: (e) => {
1979
- e.stopPropagation();
1980
- setIsMobileDropdownOpen(!isMobileDropdownOpen);
1981
- },
1982
- children: /* @__PURE__ */ jsxs("li", {
1983
- className: `list-none no-underline text-2xl leading-6 overflow-hidden
1984
- w-full pl-4 pr-4 rounded-[0.3rem] transition-all duration-600
1985
- flex items-center gap-2 opacity-100 min-h-16 py-5 `,
1986
- children: [/* @__PURE__ */ jsx("span", { children: title }), /* @__PURE__ */ jsx(ChevronDown, { className: `w-6 h-6 transition-transform duration-400 shrink-0
1987
- ${isMobileDropdownOpen ? "rotate-180" : ""}` })]
1988
- })
1989
- }), /* @__PURE__ */ jsx("div", {
1990
- className: `list-none no-underline text-xl px-6 ${isMobileDropdownOpen ? "pb-4" : ""}`,
1991
- children: React.Children.map(children, (child, index) => /* @__PURE__ */ jsx("div", {
1992
- className: `leading-6 transition-all duration-500 group dropdown
1993
- ${isMobileDropdownOpen ? "h-11 opacity-100" : "h-0 opacity-0"}
1994
- `,
1995
- children: child
1996
- }, index))
1997
- })]
1998
- })] });
1999
- }
2000
- //#endregion
2001
- //#region src/components/version/version.tsx
2002
- function VersionTag({ version, url, className }) {
2003
- if (!version) return;
2004
- const style = `w-fit bg-login-700 text-login-100 border border-login-500/40 text-xs font-mono px-2 py-0.5 rounded ${className || ""}`;
2005
- if (url) return /* @__PURE__ */ jsxs(Link, {
2006
- className: style,
2007
- target: "_blank",
2008
- href: url,
2009
- children: ["v", version]
2010
- });
2011
- return /* @__PURE__ */ jsxs("div", {
2012
- className: style,
2013
- children: ["v", version]
2014
- });
2015
- }
2016
- //#endregion
2017
- //#region src/components/footer/footer.tsx
2018
- function t(s, lang) {
2019
- return typeof s === "string" ? s : s[lang];
2020
- }
2021
- function Footer({ logo, sponsor, columns, socialLinks, copyright, version, lang = "no", className }) {
2022
- const year = (/* @__PURE__ */ new Date()).getFullYear();
2023
- const hasRight = columns && columns.length > 0 || socialLinks && socialLinks.length > 0;
2024
- return /* @__PURE__ */ jsx("div", {
2025
- className: `mt-24 bg-login-950 md:mt-40 ${className || ""}`,
2026
- children: /* @__PURE__ */ jsxs("div", {
2027
- className: `
2028
- mx-auto w-full px-4 pt-16 pb-24 md:max-w-304 md:px-12 md:pt-20 md:pb-4
2029
- ${hasRight ? "md:grid md:grid-cols-[18rem_1fr] md:gap-x-12" : ""}
2030
- `,
2031
- children: [
2032
- /* @__PURE__ */ jsxs("div", {
2033
- className: "mx-auto grid w-full max-w-60 gap-16 md:row-span-2 md:max-w-72 md:gap-20",
2034
- children: [/* @__PURE__ */ jsx("div", {
2035
- className: "block w-full",
2036
- children: logo
2037
- }), sponsor && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
2038
- className: "block w-full",
2039
- children: sponsor.node
2040
- }), sponsor.label && /* @__PURE__ */ jsx("p", {
2041
- className: "pt-8 text-center text-login-100",
2042
- children: t(sponsor.label, lang)
2043
- })] })]
2044
- }),
2045
- columns && columns.length > 0 && /* @__PURE__ */ jsx("div", {
2046
- className: `
2047
- mt-12 grid w-full max-w-60 gap-8
2048
- sm:max-w-88 sm:justify-items-end sm:justify-self-end
2049
- md:col-start-2 md:row-start-1 md:mt-0 md:max-w-136 md:gap-0 md:justify-self-end
2050
- ${columns.length > 1 ? "sm:grid-cols-2" : ""}
2051
- `,
2052
- children: columns.map((col, i) => /* @__PURE__ */ jsxs("div", {
2053
- className: "sm:justify-self-center md:justify-self-end",
2054
- children: [/* @__PURE__ */ jsx("h4", {
2055
- className: "pb-2 text-sm font-medium tracking-widest text-login-100",
2056
- children: t(col.heading, lang)
2057
- }), col.items.map((item, j) => item.href ? item.href.startsWith("/") ? /* @__PURE__ */ jsx(Link, {
2058
- className: "link--underscore-hover block text-login-100",
2059
- href: item.href,
2060
- children: t(item.label, lang)
2061
- }, j) : /* @__PURE__ */ jsx("a", {
2062
- className: "link--underscore-hover block text-login-100",
2063
- href: item.href,
2064
- children: t(item.label, lang)
2065
- }, j) : /* @__PURE__ */ jsx("p", {
2066
- className: "text-login-100",
2067
- children: t(item.label, lang)
2068
- }, j))]
2069
- }, i))
2070
- }),
2071
- socialLinks && socialLinks.length > 0 && /* @__PURE__ */ jsx("div", {
2072
- className: "md:col-start-2 md:row-start-2 md:justify-self-end",
2073
- children: /* @__PURE__ */ jsx("div", {
2074
- className: "mx-auto mt-20 mb-12 flex w-fit flex-wrap justify-center gap-6",
2075
- children: socialLinks.map((link, i) => /* @__PURE__ */ jsx("a", {
2076
- className: `block size-8 text-login-100 transition-all duration-200 group
2077
- ${link.hoverClass ?? "hover:text-login-50"}`,
2078
- title: link.title,
2079
- href: link.href,
2080
- target: "_blank",
2081
- rel: "noreferrer",
2082
- children: link.icon
2083
- }, i))
2084
- })
2085
- }),
2086
- /* @__PURE__ */ jsxs("div", {
2087
- className: "mt-16 flex flex-col items-start gap-4 md:col-span-2 md:row-start-3 md:mt-24 md:grid\n md:grid-cols-[auto_min-content] md:items-end md:gap-8",
2088
- children: [/* @__PURE__ */ jsxs("p", {
2089
- className: "text-xs wrap-break-word text-login-100",
2090
- children: [
2091
- lang === "no" ? "Opphavsrett" : "Copyright",
2092
- " © ",
2093
- year,
2094
- " ",
2095
- t(copyright, lang)
2096
- ]
2097
- }), version && /* @__PURE__ */ jsx(VersionTag, {
2098
- version: version.tag,
2099
- url: version.href
2100
- })]
2101
- })
2102
- ]
2103
- })
2104
- });
2105
- }
2106
- //#endregion
2107
- //#region src/components/footer/loginContent.tsx
2108
- const INSTAGRAM_PATH = "M512 960Q408 960 375.0 959.5Q342 959 301 957Q260 955 230.5 949.0Q201 943 177 933Q151 923 129.0 909.0Q107 895 86 874Q65 853 51.0 831.0Q37 809 27 783Q17 759 11.0 729.5Q5 700 3 659Q1 618 0.5 585.0Q0 552 0 448Q0 344 0.5 311.0Q1 278 3 237Q5 196 11.0 166.5Q17 137 27 113Q37 87 51.0 65.0Q65 43 86 22Q107 1 129.0 -13.0Q151 -27 177 -37Q201 -47 230.5 -53.0Q260 -59 301 -61Q342 -63 375.0 -63.5Q408 -64 512 -64Q616 -64 649.0 -63.5Q682 -63 723 -61Q764 -59 793.5 -53.0Q823 -47 847 -37Q873 -27 895.0 -13.0Q917 1 938 22Q959 43 973.0 65.0Q987 87 997 113Q1007 137 1013.0 166.5Q1019 196 1021 237Q1023 278 1023.5 311.0Q1024 344 1024 448Q1024 552 1023.5 585.0Q1023 618 1021 659Q1019 700 1013.0 729.5Q1007 759 997 783Q987 809 973.0 831.0Q959 853 938 874Q917 895 895.0 909.0Q873 923 847 933Q823 943 793.5 949.0Q764 955 723 957Q682 959 649.0 959.5Q616 960 512 960ZM512 868Q614 868 646.0 867.5Q678 867 719 865Q756 863 778.0 857.5Q800 852 814 847Q832 840 845.5 831.0Q859 822 873 809Q886 795 895.0 781.5Q904 768 911 750Q916 736 921.5 714.0Q927 692 929 655Q931 614 931.5 582.5Q932 551 932 448Q932 345 931.0 313.5Q930 282 929 241Q927 204 921.5 182.0Q916 160 911 146Q903 128 894.5 114.5Q886 101 872 87Q859 74 845.0 65.0Q831 56 813 49Q800 44 777.5 38.5Q755 33 718 31Q677 29 645.0 28.5Q613 28 511 28Q408 28 376.0 29.0Q344 30 303 31Q266 33 243.5 38.5Q221 44 208 49Q190 57 176.5 65.5Q163 74 149 88Q136 101 126.5 115.0Q117 129 111 147Q105 160 100.0 182.5Q95 205 93 242Q91 282 90.5 314.0Q90 346 90 449Q90 551 90.5 583.0Q91 615 93 656Q95 693 100.0 715.5Q105 738 111 751Q117 770 126.5 783.5Q136 797 149 810Q163 824 176.5 833.0Q190 842 208 849Q221 854 243.0 859.5Q265 865 303 867Q344 868 375.5 868.5Q407 869 510 869ZM512 711Q458 711 410 690Q362 670 326.0 634.0Q290 598 270 550Q249 502 249 448Q249 394 270 346Q290 298 326.0 262.0Q362 226 410 206Q458 185 512 185Q566 185 614 206Q662 226 698.0 262.0Q734 298 754 346Q775 394 775 448Q775 502 754 550Q734 598 698.0 634.0Q662 670 614 690Q566 711 512 711ZM512 277Q441 277 391.0 327.0Q341 377 341 448Q341 519 391.0 569.0Q441 619 512 619Q583 619 633.0 569.0Q683 519 683 448Q683 377 633.0 327.0Q583 277 512 277ZM847 721Q847 696 829.0 678.0Q811 660 785 660Q760 660 742.0 678.0Q724 696 724 721Q724 747 742.0 765.0Q760 783 785 783Q811 783 829.0 765.0Q847 747 847 721Z";
2109
- function InstagramIcon({ size = 24 }) {
2110
- return /* @__PURE__ */ jsxs("span", {
2111
- className: "relative block",
2112
- style: {
2113
- width: size,
2114
- height: size
2115
- },
2116
- children: [/* @__PURE__ */ jsx("svg", {
2117
- xmlns: "http://www.w3.org/2000/svg",
2118
- viewBox: "0 0 1024 1024",
2119
- width: size,
2120
- height: size,
2121
- "aria-hidden": "true",
2122
- className: "absolute inset-0 transition-opacity duration-200 opacity-100 group-hover:opacity-0",
2123
- children: /* @__PURE__ */ jsx("g", {
2124
- transform: "translate(0 960) scale(1 -1)",
2125
- children: /* @__PURE__ */ jsx("path", {
2126
- fill: "currentColor",
2127
- d: INSTAGRAM_PATH
2128
- })
2129
- })
2130
- }), /* @__PURE__ */ jsxs("svg", {
2131
- xmlns: "http://www.w3.org/2000/svg",
2132
- viewBox: "0 0 1024 1024",
2133
- width: size,
2134
- height: size,
2135
- "aria-hidden": "true",
2136
- className: "absolute inset-0 transition-opacity duration-200 opacity-0 group-hover:opacity-100",
2137
- children: [/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", {
2138
- id: "ig-grad",
2139
- x1: "0%",
2140
- y1: "100%",
2141
- x2: "100%",
2142
- y2: "0%",
2143
- children: [
2144
- /* @__PURE__ */ jsx("stop", {
2145
- offset: "0%",
2146
- stopColor: "#fff695"
2147
- }),
2148
- /* @__PURE__ */ jsx("stop", {
2149
- offset: "45%",
2150
- stopColor: "#ff5445"
2151
- }),
2152
- /* @__PURE__ */ jsx("stop", {
2153
- offset: "60%",
2154
- stopColor: "#ff37c0"
2155
- }),
2156
- /* @__PURE__ */ jsx("stop", {
2157
- offset: "90%",
2158
- stopColor: "#3d6dff"
2159
- })
2160
- ]
2161
- }) }), /* @__PURE__ */ jsx("g", {
2162
- transform: "translate(0 960) scale(1 -1)",
2163
- children: /* @__PURE__ */ jsx("path", {
2164
- fill: "url(#ig-grad)",
2165
- d: INSTAGRAM_PATH
2166
- })
2167
- })]
2168
- })]
2169
- });
2170
- }
2171
- const loginAddress = {
2172
- heading: {
2173
- no: "Adresse",
2174
- en: "Address"
2175
- },
2176
- items: [
2177
- { label: "Teknologivegen 22" },
2178
- { label: {
2179
- no: "Bygg A, rom 155",
2180
- en: "Building A, room 155"
2181
- } },
2182
- { label: "2815 GJØVIK" }
2183
- ]
2184
- };
2185
- const loginEmail = (email) => ({
2186
- heading: {
2187
- no: "E-post",
2188
- en: "Email"
2189
- },
2190
- items: [{
2191
- label: email,
2192
- href: `mailto:${email}`
2193
- }]
2194
- });
2195
- const loginCopyright = {
2196
- no: "Login - Linjeforeningen for IT, NO 811 940 372",
2197
- en: "Login - Association for IT, NO 811 940 372"
2198
- };
2199
- const loginSponsor = { label: {
2200
- no: "Hovedsamarbeidspartner",
2201
- en: "Main partner"
2202
- } };
2203
- const loginSocialLinks = [
2204
- {
2205
- title: "Discord",
2206
- href: "https://discord.gg/login-ntnu",
2207
- icon: /* @__PURE__ */ jsx(Discord, { size: 24 }),
2208
- hoverClass: "hover:text-[#6571fd]"
2209
- },
2210
- {
2211
- title: "Instagram",
2212
- href: "https://www.instagram.com/login_linjeforening/",
2213
- icon: /* @__PURE__ */ jsx(InstagramIcon, { size: 24 })
2214
- },
2215
- {
2216
- title: "Facebook",
2217
- href: "https://facebook.com/LogNTNU",
2218
- icon: /* @__PURE__ */ jsx(Facebook, { size: 24 }),
2219
- hoverClass: "hover:text-[#2c87ff]"
2220
- },
2221
- {
2222
- title: "LinkedIn",
2223
- href: "https://www.linkedin.com/company/linjeforeningen-login/about",
2224
- icon: /* @__PURE__ */ jsx(Linkedin, { size: 24 }),
2225
- hoverClass: "hover:text-[#1a7bdd]"
2226
- },
2227
- {
2228
- title: "GitHub",
2229
- href: "https://github.com/login-linjeforeningen-for-it",
2230
- icon: /* @__PURE__ */ jsx(Github, { size: 24 }),
2231
- hoverClass: "hover:text-white"
2232
- },
2233
- {
2234
- title: "Wiki",
2235
- href: "https://outline.login.no/s/doc",
2236
- icon: /* @__PURE__ */ jsx(Wikijs, { size: 24 }),
2237
- hoverClass: "hover:text-login-50"
2238
- }
2239
- ];
2240
- //#endregion
2241
- //#region src/components/container/page.tsx
2242
- function PageContainer({ title, children, className, innerClassName }) {
2243
- return /* @__PURE__ */ jsx("div", {
2244
- className: `w-full page-container ${className}`,
2245
- children: /* @__PURE__ */ jsxs("div", {
2246
- className: `flex flex-col col-start-3 ${innerClassName}`,
2247
- children: [/* @__PURE__ */ jsx("h1", {
2248
- className: "heading",
2249
- children: title
2250
- }), children]
2251
- })
2252
- });
2253
- }
2254
- //#endregion
2255
- //#region src/components/container/highlight.tsx
2256
- function Highlight({ children, className }) {
2257
- return /* @__PURE__ */ jsx("div", {
2258
- className: `highlighted-section ${className ?? ""}`,
2259
- children
2260
- });
2261
- }
2262
- //#endregion
2263
- //#region src/components/container/leftBarPanel.tsx
2264
- function LeftBarPanel({ color, children, className = "" }) {
2265
- return /* @__PURE__ */ jsx("div", {
2266
- className: `bg-login-500/50 border border-login-500/30 border-l-2 rounded-sm ${color} ${className}`,
2267
- children
2268
- });
2269
- }
2270
- //#endregion
2271
- //#region src/components/container/card.tsx
2272
- function Card({ children, className = "" }) {
2273
- return /* @__PURE__ */ jsx("section", {
2274
- className: `rounded-xl border border-login-500/30 bg-login-500/50 ${className}`,
2275
- children
2276
- });
2277
- }
2278
- //#endregion
2279
- //#region src/components/container/iconBubble.tsx
2280
- const tones = {
2281
- amber: "bg-amber-500/10 text-amber-400",
2282
- blue: "bg-sky-500/10 text-sky-400",
2283
- emerald: "bg-emerald-500/10 text-emerald-400",
2284
- rose: "bg-rose-500/10 text-rose-400",
2285
- slate: "bg-login-600 text-login-100",
2286
- violet: "bg-violet-500/10 text-violet-400",
2287
- orange: "bg-login/10 text-login"
2288
- };
2289
- function IconBubble({ icon: Icon, tone = "slate", size = "md" }) {
2290
- const sizeClass = size === "sm" ? "h-7 w-7" : size === "lg" ? "h-11 w-11" : "h-9 w-9";
2291
- const iconSize = size === "sm" ? "h-3.5 w-3.5" : size === "lg" ? "h-5 w-5" : "h-4 w-4";
2292
- return /* @__PURE__ */ jsx("div", {
2293
- className: `flex shrink-0 items-center justify-center rounded-lg ${sizeClass} ${tones[tone]}`,
2294
- children: /* @__PURE__ */ jsx(Icon, { className: iconSize })
2295
- });
2296
- }
2297
- //#endregion
2298
- //#region src/components/container/statCard.tsx
2299
- function StatCard({ label, value, icon, tone = "slate" }) {
2300
- return /* @__PURE__ */ jsxs(Card, {
2301
- className: "p-4",
2302
- children: [/* @__PURE__ */ jsxs("div", {
2303
- className: "mb-3 flex items-center gap-3",
2304
- children: [/* @__PURE__ */ jsx(IconBubble, {
2305
- icon,
2306
- tone
2307
- }), /* @__PURE__ */ jsx("span", {
2308
- className: "text-sm font-medium text-login-200",
2309
- children: label
2310
- })]
2311
- }), /* @__PURE__ */ jsx("div", {
2312
- className: "truncate text-lg font-semibold text-login-50",
2313
- title: value,
2314
- children: value
2315
- })]
2316
- });
2317
- }
2318
- //#endregion
2319
- //#region src/components/container/tabs.tsx
2320
- function Tabs({ tabs, defaultTab, activeTab: controlledTab, onTabChange, children, className = "" }) {
2321
- const [internalTab, setInternalTab] = useState(defaultTab ?? tabs[0]?.id ?? "");
2322
- const activeTab = controlledTab ?? internalTab;
2323
- function handleTabChange(id) {
2324
- if (!controlledTab) setInternalTab(id);
2325
- onTabChange?.(id);
2326
- }
2327
- return /* @__PURE__ */ jsxs("div", {
2328
- className,
2329
- children: [/* @__PURE__ */ jsx("div", {
2330
- className: "flex gap-1 rounded-md bg-login-500/50 border border-login-500/40 p-1 w-fit",
2331
- children: tabs.map((tab) => /* @__PURE__ */ jsx("button", {
2332
- type: "button",
2333
- onClick: () => handleTabChange(tab.id),
2334
- className: `
2335
- px-3 py-1.5 rounded text-sm font-medium transition-all duration-150 cursor-pointer select-none
2336
- ${activeTab === tab.id ? "bg-login text-white shadow-sm" : "text-login-200 hover:text-login-50 hover:bg-login-600"}
2337
- `,
2338
- children: tab.label
2339
- }, tab.id))
2340
- }), /* @__PURE__ */ jsx("div", {
2341
- className: "mt-3",
2342
- children
2343
- })]
2344
- });
2345
- }
2346
- function TabPanel({ id, activeTab, children }) {
2347
- if (activeTab !== id) return null;
2348
- return /* @__PURE__ */ jsx("div", { children });
2349
- }
2350
- //#endregion
2351
- //#region src/components/container/accordion.tsx
2352
- const GroupContext = createContext(false);
2353
- function AccordionGroup({ children, className = "" }) {
2354
- return /* @__PURE__ */ jsx(GroupContext.Provider, {
2355
- value: true,
2356
- children: /* @__PURE__ */ jsx("div", {
2357
- className: `rounded-lg border border-login-500/40 overflow-hidden divide-y divide-login-500/25 ${className}`,
2358
- children
2359
- })
2360
- });
2361
- }
2362
- function Accordion({ title, children, defaultOpen = false, className = "" }) {
2363
- const [open, setOpen] = useState(defaultOpen);
2364
- return /* @__PURE__ */ jsxs("div", {
2365
- className: useContext(GroupContext) ? className : `rounded-lg border border-login-500/40 overflow-hidden ${className}`,
2366
- children: [/* @__PURE__ */ jsxs("button", {
2367
- type: "button",
2368
- onClick: () => setOpen((o) => !o),
2369
- className: "\n flex w-full cursor-pointer items-center justify-between\n bg-login-800 px-4 py-3 text-left select-none\n transition-colors duration-150 hover:bg-login-700\n ",
2370
- children: [/* @__PURE__ */ jsx("div", {
2371
- className: "text-sm font-medium text-login-50",
2372
- children: title
2373
- }), /* @__PURE__ */ jsx(ChevronDown, {
2374
- size: 16,
2375
- className: `shrink-0 text-login-300 transition-transform duration-200 ${open ? "rotate-180" : ""}`
2376
- })]
2377
- }), /* @__PURE__ */ jsx("div", {
2378
- className: `overflow-hidden bg-login-900 transition-all duration-200 ${open ? "max-h-[9999px]" : "max-h-0"}`,
2379
- children: /* @__PURE__ */ jsx("div", {
2380
- className: "px-4 py-3 text-sm text-login-100",
2381
- children
2382
- })
2383
- })]
2384
- });
2385
- }
2386
- //#endregion
2387
- //#region src/components/container/pulseDot.tsx
2388
- const variantColor = {
2389
- online: "bg-green-500",
2390
- offline: "bg-red-500",
2391
- warning: "bg-login",
2392
- unknown: "bg-login-400"
2393
- };
2394
- const sizeClass = {
2395
- sm: "w-1.5 h-1.5",
2396
- md: "w-2 h-2",
2397
- lg: "w-3 h-3"
2398
- };
2399
- function PulseDot({ variant = "online", size = "md" }) {
2400
- const color = variantColor[variant];
2401
- const dotSize = sizeClass[size];
2402
- return /* @__PURE__ */ jsxs("div", {
2403
- className: `relative grid place-items-center ${dotSize}`,
2404
- children: [/* @__PURE__ */ jsx("span", { className: `absolute inline-flex h-full w-full rounded-full ${color} opacity-50 animate-ping` }), /* @__PURE__ */ jsx("span", { className: `relative inline-flex rounded-full ${dotSize} ${color}` })]
2405
- });
2406
- }
2407
- //#endregion
2408
- //#region src/components/login/loginPage.tsx
2409
- function LoginPage({ title, description, redirectPath, version, btg, handleSubmit, guestRedirectPath, guestText }) {
2410
- return /* @__PURE__ */ jsx("main", {
2411
- className: "w-full h-full flex items-center justify-center bg-login-800 p-8",
2412
- children: /* @__PURE__ */ jsxs("div", {
2413
- className: "flex flex-col justify-center items-center bg-login-600 px-4 py-12 rounded-xl w-full max-w-md gap-4 md:gap-6",
2414
- children: [
2415
- /* @__PURE__ */ jsx("div", {
2416
- className: "relative aspect-3/1 w-full",
2417
- children: /* @__PURE__ */ jsx(Logo, { className: "object-contain px-6 sm:px-12" })
2418
- }),
2419
- /* @__PURE__ */ jsxs("h1", {
2420
- className: "text-3xl font-extrabold text-login text-center tracking-tight",
2421
- children: [
2422
- title,
2423
- " ",
2424
- btg ? " - Break the Glass" : ""
2425
- ]
2426
- }),
2427
- description && /* @__PURE__ */ jsx("p", {
2428
- className: "text-center font-medium text-lg mb-2 max-w-xs",
2429
- children: description
2430
- }),
2431
- btg ? /* @__PURE__ */ jsxs("form", {
2432
- className: "w-full flex flex-col gap-3 max-w-xs",
2433
- onSubmit: (e) => {
2434
- e.preventDefault();
2435
- handleSubmit?.(new FormData(e.currentTarget));
2436
- e.currentTarget.reset();
2437
- },
2438
- children: [
2439
- /* @__PURE__ */ jsx("input", {
2440
- type: "text",
2441
- name: "name",
2442
- placeholder: "Name",
2443
- className: "py-2 px-3 rounded bg-login-900 font-medium focus:outline-none",
2444
- required: true
2445
- }),
2446
- /* @__PURE__ */ jsx("input", {
2447
- type: "password",
2448
- name: "token",
2449
- placeholder: "Token",
2450
- className: "py-2 px-3 rounded bg-login-900 font-medium focus:outline-none",
2451
- required: true
2452
- }),
2453
- /* @__PURE__ */ jsx("button", {
2454
- type: "submit",
2455
- className: "py-2 px-4 rounded-xl bg-login font-bold text-lg hover:bg-login/80 transition-all duration-200 mt-2",
2456
- children: "Login"
2457
- })
2458
- ]
2459
- }) : /* @__PURE__ */ jsxs(Link, {
2460
- href: redirectPath,
2461
- className: `
2462
- flex items-center justify-center gap-2 w-full
2463
- max-w-xs py-3 px-6 rounded-xl bg-login font-bold
2464
- text-lg hover:bg-login/80 transition-all
2465
- duration-200 mb-2 mt-2 cursor-pointer
2466
- `,
2467
- children: ["Login", /* @__PURE__ */ jsx(LogIn, { className: "w-6 h-6" })]
2468
- }),
2469
- guestRedirectPath && /* @__PURE__ */ jsx(Link, {
2470
- href: guestRedirectPath,
2471
- className: "text-sm font-semibold cursor-pointer opacity-50",
2472
- children: guestText || "Continue as guest"
2473
- }),
2474
- /* @__PURE__ */ jsxs("span", {
2475
- className: "text-sm mt-2",
2476
- children: ["v", version]
2477
- })
2478
- ]
2479
- })
2480
- });
2481
- }
2482
- //#endregion
2483
- //#region src/components/toast/toastItem.tsx
2484
- function ToastItem({ toast, index, expanded, onRemove, onHeight, offset, frontHeight }) {
2485
- const [mounted, setMounted] = useState(false);
2486
- const ref = useRef(null);
2487
- useEffect(() => {
2488
- requestAnimationFrame(() => setMounted(true));
2489
- }, []);
2490
- useLayoutEffect(() => {
2491
- if (ref.current) onHeight(toast.id, ref.current.offsetHeight);
2492
- }, [
2493
- toast.message,
2494
- onHeight,
2495
- toast.id,
2496
- expanded
2497
- ]);
2498
- const isVisible = mounted && !toast.exiting;
2499
- const isFront = index === 0;
2500
- const collapsedOffset = index * 10 + (index > 0 ? frontHeight - 60 : 0);
2501
- return /* @__PURE__ */ jsx("li", {
2502
- ref,
2503
- className: "absolute bottom-0 right-0 w-full transition-all duration-300 ease-out pointer-events-auto",
2504
- style: {
2505
- transform: isVisible ? `translateY(${expanded ? -offset : -collapsedOffset}px) scale(${expanded ? 1 : 1 - index * .05})` : "translateY(20px) scale(0.9)",
2506
- opacity: isVisible ? 1 : 0,
2507
- zIndex: toast.id
2508
- },
2509
- children: /* @__PURE__ */ jsxs("div", {
2510
- className: "flex items-center space-x-4 rounded-lg p-4 shadow-lg border-2 border-login-400 bg-login-700",
2511
- children: [
2512
- /* @__PURE__ */ jsx("div", {
2513
- className: "shrink-0",
2514
- children: Icon(toast.type)
2515
- }),
2516
- /* @__PURE__ */ jsx("p", {
2517
- className: `flex-1 text-sm font-semibold text-login-800 dark:text-login-100 min-w-0
2518
- ${!expanded && !isFront ? "truncate" : ""}`,
2519
- children: toast.message
2520
- }),
2521
- /* @__PURE__ */ jsx("button", {
2522
- onClick: onRemove,
2523
- className: "hover:text-login-200 text-login-400",
2524
- children: /* @__PURE__ */ jsx(X, { className: "h-5 w-5" })
2525
- })
2526
- ]
2527
- })
2528
- });
2529
- }
2530
- function Icon(type) {
2531
- switch (type) {
2532
- case "info": return /* @__PURE__ */ jsx(Info, { className: "h-6 w-6 text-blue-500" });
2533
- case "success": return /* @__PURE__ */ jsx(CheckCircle, { className: "h-6 w-6 text-green-500" });
2534
- case "warning": return /* @__PURE__ */ jsx(AlertTriangle, { className: "h-6 w-6 text-yellow-500" });
2535
- case "error": return /* @__PURE__ */ jsx(AlertCircle, { className: "h-6 w-6 text-red-500" });
2536
- }
2537
- }
2538
- //#endregion
2539
- //#region src/components/toast/toaster.tsx
2540
- const listeners = /* @__PURE__ */ new Set();
2541
- let idCounter = 0;
2542
- function toast(message, type, duration = 4e3) {
2543
- const id = ++idCounter;
2544
- listeners.forEach((listener) => listener({
2545
- id,
2546
- message,
2547
- type,
2548
- expiresAt: Date.now() + duration
2549
- }));
2550
- }
2551
- toast.info = (message, duration) => toast(message, "info", duration);
2552
- toast.success = (message, duration) => toast(message, "success", duration);
2553
- toast.warning = (message, duration) => toast(message, "warning", duration);
2554
- toast.error = (message, duration) => toast(message, "error", duration);
2555
- function Toaster() {
2556
- const [toasts, setToasts] = useState([]);
2557
- const [expanded, setExpanded] = useState(false);
2558
- const [heights, setHeights] = useState({});
2559
- useEffect(() => {
2560
- function addToast(toast) {
2561
- setToasts((prev) => [toast, ...prev]);
2562
- }
2563
- listeners.add(addToast);
2564
- return () => {
2565
- listeners.delete(addToast);
2566
- };
2567
- }, []);
2568
- useEffect(() => {
2569
- const now = Date.now();
2570
- setToasts((prev) => prev.map((toast) => {
2571
- if (expanded) return {
2572
- ...toast,
2573
- pausedAt: toast.pausedAt || now
2574
- };
2575
- if (!toast.pausedAt) return toast;
2576
- return {
2577
- ...toast,
2578
- expiresAt: toast.expiresAt + (now - toast.pausedAt),
2579
- pausedAt: void 0
2580
- };
2581
- }));
2582
- }, [expanded]);
2583
- function removeToast(id) {
2584
- setToasts((prev) => prev.map((toast) => toast.id === id ? {
2585
- ...toast,
2586
- exiting: true
2587
- } : toast));
2588
- setTimeout(() => {
2589
- setToasts((prev) => prev.filter((toast) => toast.id !== id));
2590
- }, 300);
2591
- }
2592
- useEffect(() => {
2593
- const timer = setInterval(() => {
2594
- if (expanded) return;
2595
- const now = Date.now();
2596
- setToasts((prev) => {
2597
- const toastsToExit = prev.filter((toast) => !toast.exiting && !toast.pausedAt && toast.expiresAt <= now);
2598
- if (toastsToExit.length === 0) return prev;
2599
- toastsToExit.forEach((toast) => {
2600
- setTimeout(() => {
2601
- setToasts((current) => current.filter((item) => item.id !== toast.id));
2602
- }, 300);
2603
- });
2604
- return prev.map((toast) => toastsToExit.find((exitToast) => exitToast.id === toast.id) ? {
2605
- ...toast,
2606
- exiting: true
2607
- } : toast);
2608
- });
2609
- }, 100);
2610
- return () => clearInterval(timer);
2611
- }, [expanded]);
2612
- function onHeight(id, height) {
2613
- setHeights((prev) => {
2614
- if (prev[id] === height) return prev;
2615
- return {
2616
- ...prev,
2617
- [id]: height
2618
- };
2619
- });
2620
- }
2621
- const visibleToasts = toasts.slice(0, expanded ? 10 : 3);
2622
- const frontHeight = heights[visibleToasts[0]?.id] || 60;
2623
- const offsets = useMemo(() => {
2624
- let currentOffset = 0;
2625
- return visibleToasts.map((toast) => {
2626
- const height = heights[toast.id] || 60;
2627
- const offset = currentOffset;
2628
- currentOffset += height + 16;
2629
- return offset;
2630
- });
2631
- }, [visibleToasts, heights]);
2632
- const totalHeight = offsets.length > 0 ? offsets[offsets.length - 1] + (heights[visibleToasts[visibleToasts.length - 1]?.id] || 60) : 0;
2633
- return /* @__PURE__ */ jsx("ul", {
2634
- className: `fixed bottom-4 right-4 z-9999 w-full max-w-sm flex flex-col items-end transition-all duration-300 ease-out
2635
- ${expanded ? "pointer-events-auto" : "pointer-events-none"}`,
2636
- style: { height: expanded ? totalHeight + "px" : "auto" },
2637
- onMouseEnter: () => setExpanded(true),
2638
- onMouseLeave: () => setExpanded(false),
2639
- children: visibleToasts.map((toast, index) => /* @__PURE__ */ jsx(ToastItem, {
2640
- toast,
2641
- index,
2642
- expanded,
2643
- onRemove: () => removeToast(toast.id),
2644
- onHeight,
2645
- offset: offsets[index],
2646
- frontHeight
2647
- }, toast.id))
2648
- });
2649
- }
2650
- //#endregion
2651
- //#region src/components/buttons/button.tsx
2652
- const variants$1 = {
2653
- primary: "bg-login text-white hover:brightness-110",
2654
- secondary: "bg-login-500 text-login-50 hover:bg-login-400",
2655
- warning: "bg-yellow-500 text-black hover:brightness-110",
2656
- danger: "bg-red-600 text-white hover:brightness-110",
2657
- success: "bg-green-600 text-white hover:brightness-110",
2658
- info: "bg-blue-600 text-white hover:brightness-110"
2659
- };
2660
- const base = "cursor-pointer rounded-md h-9 flex items-center justify-center gap-2 select-none text-sm font-medium transition-all duration-150";
2661
- const withText = "px-4 w-fit";
2662
- const iconOnly = "w-9";
2663
- const disabledCls = "opacity-40 cursor-not-allowed pointer-events-none";
2664
- const iconWrap = (icon) => icon ? /* @__PURE__ */ jsx("span", {
2665
- className: "[&>svg]:w-4 [&>svg]:h-4 flex items-center",
2666
- children: icon
2667
- }) : null;
2668
- function Button({ text, className, icon, path, variant = "primary", type, onClick, disabled }) {
2669
- const color = variants$1[variant];
2670
- const sizing = icon && !text ? iconOnly : withText;
2671
- const cls = `${base} ${sizing} ${color} ${disabled ? disabledCls : ""} ${className || ""}`;
2672
- if (!path) return /* @__PURE__ */ jsxs("button", {
2673
- type: type || "button",
2674
- disabled,
2675
- onClick,
2676
- "aria-label": text,
2677
- className: cls,
2678
- children: [iconWrap(icon), text]
2679
- });
2680
- if (disabled) return /* @__PURE__ */ jsxs("div", {
2681
- className: cls,
2682
- children: [iconWrap(icon), text]
2683
- });
2684
- return /* @__PURE__ */ jsxs(Link, {
2685
- href: path,
2686
- className: `${base} ${sizing} ${color} ${className || ""}`,
2687
- children: [iconWrap(icon), text]
2688
- });
2689
- }
2690
- //#endregion
2691
- //#region src/components/alert/alert.tsx
2692
- const styles = {
2693
- warning: {
2694
- color: "border-l-red-500",
2695
- iconClass: "w-4 h-4 shrink-0 stroke-red-400 mr-3 mt-0.5",
2696
- Icon: CircleAlert
2697
- },
2698
- info: {
2699
- color: "border-l-blue-500",
2700
- iconClass: "w-4 h-4 shrink-0 stroke-blue-400 mr-3 mt-0.5",
2701
- Icon: Info
2702
- }
2703
- };
2704
- function Alert({ children, variant = "warning", className = "" }) {
2705
- const { color, iconClass, Icon } = styles[variant] ?? styles.warning;
2706
- return /* @__PURE__ */ jsxs(LeftBarPanel, {
2707
- color,
2708
- className: `flex items-start px-4 py-3 text-sm text-login-100 ${className}`,
2709
- children: [/* @__PURE__ */ jsx(Icon, { className: iconClass }), /* @__PURE__ */ jsx("div", {
2710
- className: "leading-relaxed",
2711
- children
2712
- })]
2713
- });
2714
- }
2715
- //#endregion
2716
- //#region src/components/table/constants.ts
2717
- const HIGHLIGHT = {
2718
- green: "bg-green-500/15 text-green-400 ring-1 ring-green-500/25",
2719
- yellow: "bg-yellow-500/15 text-yellow-400 ring-1 ring-yellow-500/25",
2720
- red: "bg-red-500/15 text-red-400 ring-1 ring-red-500/25",
2721
- blue: "bg-blue-500/15 text-blue-400 ring-1 ring-blue-500/25",
2722
- gray: "bg-gray-500/15 text-gray-400 ring-1 ring-gray-500/25",
2723
- orange: "bg-orange-500/15 text-orange-400 ring-1 ring-orange-500/25",
2724
- purple: "bg-purple-500/15 text-purple-400 ring-1 ring-purple-500/25"
2725
- };
2726
- const DENSITY_TH = {
2727
- compact: "px-4 py-2",
2728
- comfortable: "px-6 py-3",
2729
- spacious: "px-8 py-4"
2730
- };
2731
- const DENSITY_TD = {
2732
- compact: "px-4 py-1.5",
2733
- comfortable: "px-6 py-3.5",
2734
- spacious: "px-8 py-5"
2735
- };
2736
- const VARIANT_CONTAINER = {
2737
- original: "bg-login-500/50 rounded-lg border border-login-600 shadow",
2738
- modern: "bg-transparent"
2739
- };
2740
- const VARIANT_THEAD = {
2741
- original: "bg-login-700",
2742
- modern: "bg-transparent"
2743
- };
2744
- const VARIANT_HEAD_BG = {
2745
- original: "bg-login-700",
2746
- modern: ""
2747
- };
2748
- const VARIANT_HEAD_BORDER = {
2749
- original: "border-b border-login-600",
2750
- modern: "border-b border-login-500/40"
2751
- };
2752
- const VARIANT_ROW_BORDER = {
2753
- original: "border-b border-login-600",
2754
- modern: "border-b border-login-600/15"
2755
- };
2756
- const VARIANT_THEAD_TH = {
2757
- original: "text-login-200",
2758
- modern: "text-login-300"
2759
- };
2760
- const VARIANT_TBODY = {
2761
- original: "bg-login-500/50 divide-login-600",
2762
- modern: "divide-login-600/15"
2763
- };
2764
- const VARIANT_ROW_HOVER = {
2765
- original: "hover:bg-login-600/30",
2766
- modern: "hover:bg-login-700/50"
2767
- };
2768
- const VARIANT_ROW_STRIPED = {
2769
- original: "even:bg-login-600/40",
2770
- modern: "even:bg-login-800/40"
2771
- };
2772
- //#endregion
2773
- //#region src/components/table/header.tsx
2774
- function formatLabel(key, label) {
2775
- if (label) return label;
2776
- if (key.length <= 2) return key.toUpperCase();
2777
- return key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replaceAll("_", " ").replaceAll("-", " ").split(/\s+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
2778
- }
2779
- function Header({ columns, sort, onSort, hasMenu, hasSelect, hasExpand, allSelected, someSelected, onSelectAll, variant, density }) {
2780
- function handleSort(key) {
2781
- onSort({
2782
- column: key,
2783
- order: sort?.column === key && sort?.order === "asc" ? "desc" : "asc"
2784
- });
2785
- }
2786
- return /* @__PURE__ */ jsx("thead", {
2787
- className: VARIANT_THEAD[variant],
2788
- children: /* @__PURE__ */ jsxs("tr", { children: [
2789
- hasSelect && /* @__PURE__ */ jsx("th", {
2790
- className: `sticky top-0 z-10 ${VARIANT_HEAD_BG[variant]} ${VARIANT_HEAD_BORDER[variant]}`,
2791
- style: {
2792
- width: "3rem",
2793
- minWidth: "3rem"
2794
- },
2795
- children: /* @__PURE__ */ jsx("div", {
2796
- className: "flex items-center justify-center",
2797
- children: /* @__PURE__ */ jsxs("button", {
2798
- type: "button",
2799
- "aria-label": allSelected ? "Deselect all" : "Select all",
2800
- onClick: onSelectAll,
2801
- className: `
2802
- h-4 w-4 rounded border flex items-center justify-center transition-colors cursor-pointer
2803
- ${allSelected || someSelected ? "bg-login border-login text-white" : "border-login-400 bg-transparent hover:border-login-200"}
2804
- `,
2805
- children: [someSelected && !allSelected && /* @__PURE__ */ jsx("span", { className: "block h-0.5 w-2 bg-white rounded-full" }), allSelected && /* @__PURE__ */ jsx("svg", {
2806
- className: "h-3 w-3",
2807
- viewBox: "0 0 12 12",
2808
- fill: "none",
2809
- children: /* @__PURE__ */ jsx("path", {
2810
- d: "M2 6l3 3 5-5",
2811
- stroke: "currentColor",
2812
- strokeWidth: "1.5",
2813
- strokeLinecap: "round",
2814
- strokeLinejoin: "round"
2815
- })
2816
- })]
2817
- })
2818
- })
2819
- }),
2820
- columns.map((col) => {
2821
- const sortable = col.sortable !== false;
2822
- const isActive = sort?.column === col.key;
2823
- const ariaSort = isActive ? sort.order === "asc" ? "ascending" : "descending" : "none";
2824
- const alignClass = col.align === "right" ? "justify-end" : col.align === "center" ? "justify-center" : "";
2825
- return /* @__PURE__ */ jsx("th", {
2826
- "aria-sort": sortable ? ariaSort : void 0,
2827
- style: col.width ? { width: col.width } : void 0,
2828
- className: `
2829
- sticky top-0 z-10 ${VARIANT_HEAD_BG[variant]} ${VARIANT_HEAD_BORDER[variant]}
2830
- text-xs font-medium uppercase tracking-wider
2831
- ${DENSITY_TH[density]} ${VARIANT_THEAD_TH[variant]}
2832
- `,
2833
- children: sortable ? /* @__PURE__ */ jsxs("button", {
2834
- type: "button",
2835
- className: `group inline-flex items-center gap-1.5 w-full cursor-pointer ${alignClass}`,
2836
- onClick: () => handleSort(col.key),
2837
- children: [/* @__PURE__ */ jsx("span", {
2838
- className: "whitespace-nowrap",
2839
- children: formatLabel(col.key, col.label)
2840
- }), /* @__PURE__ */ jsx("span", {
2841
- className: "shrink-0 text-current",
2842
- children: isActive ? sort.order === "asc" ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(ChevronsUpDown, { className: "h-3.5 w-3.5 opacity-0 group-hover:opacity-35 transition-opacity" })
2843
- })]
2844
- }) : /* @__PURE__ */ jsx("span", {
2845
- className: `flex w-full whitespace-nowrap ${alignClass}`,
2846
- children: formatLabel(col.key, col.label)
2847
- })
2848
- }, col.key);
2849
- }),
2850
- hasExpand && /* @__PURE__ */ jsx("th", {
2851
- className: `sticky top-0 z-10 ${VARIANT_HEAD_BG[variant]} ${VARIANT_HEAD_BORDER[variant]}`,
2852
- style: {
2853
- width: "2.5rem",
2854
- minWidth: "2.5rem"
2855
- },
2856
- children: /* @__PURE__ */ jsx("span", {
2857
- className: `
2858
- flex items-center justify-center
2859
- text-xs font-medium tracking-wider uppercase opacity-50
2860
- ${VARIANT_THEAD_TH[variant]}
2861
- `,
2862
- children: "+"
2863
- })
2864
- }),
2865
- hasMenu && /* @__PURE__ */ jsx("th", {
2866
- "aria-hidden": "true",
2867
- className: `sticky top-0 z-10 ${VARIANT_HEAD_BG[variant]} ${VARIANT_HEAD_BORDER[variant]}`,
2868
- style: {
2869
- width: "3.5rem",
2870
- minWidth: "3.5rem"
2871
- }
2872
- })
2873
- ] })
2874
- });
2875
- }
2876
- //#endregion
2877
- //#region src/components/table/format.ts
2878
- const nullableTimeKeys = /* @__PURE__ */ new Set([
2879
- "date",
2880
- "last_sent",
2881
- "sent_at",
2882
- "time"
2883
- ]);
2884
- const RX_DATETIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/;
2885
- const RX_DATE = /^\d{4}-\d{2}-\d{2}$/;
2886
- const RX_TIME = /^\d{2}:\d{2}(:\d{2})?$/;
2887
- function formatValue(key, value) {
2888
- if (value === null || value === void 0) return nullableTimeKeys.has(key) ? "Never" : "-";
2889
- if (typeof value === "boolean") return value ? "Yes" : "No";
2890
- if (typeof value === "number") {
2891
- if (key.includes("capacity") && value === 0) return "Unlimited";
2892
- return value;
2893
- }
2894
- if (typeof value === "string") {
2895
- if (RX_DATETIME.test(value)) return new Date(value).toLocaleString("nb-NO", {
2896
- timeZone: "Europe/Oslo",
2897
- year: "numeric",
2898
- month: "2-digit",
2899
- day: "2-digit",
2900
- hour: "2-digit",
2901
- minute: "2-digit"
2902
- });
2903
- if (RX_DATE.test(value)) return new Date(value).toLocaleDateString("nb-NO", { timeZone: "Europe/Oslo" });
2904
- if (RX_TIME.test(value)) return (/* @__PURE__ */ new Date(`1970-01-01T${value}`)).toLocaleTimeString("nb-NO", {
2905
- timeZone: "Europe/Oslo",
2906
- hour: "2-digit",
2907
- minute: "2-digit"
2908
- });
2909
- return value;
2910
- }
2911
- if (Array.isArray(value)) return value.join(", ");
2912
- return String(value);
2913
- }
2914
- //#endregion
2915
- //#region src/components/table/utils.ts
2916
- function resolveId(row, idKey, columns) {
2917
- if (idKey && row[idKey] !== void 0) return String(row[idKey]);
2918
- if (row["id"] !== void 0) return String(row["id"]);
2919
- const firstKey = columns[0]?.key ?? Object.keys(row)[0];
2920
- return String(row[firstKey] ?? "");
2921
- }
2922
- //#endregion
2923
- //#region src/components/table/menu.tsx
2924
- const MenuCtx = createContext({});
2925
- function Menu({ ref, children, anchor, onClose }) {
2926
- useEffect(() => {
2927
- function handleKey(e) {
2928
- if (e.key === "Escape") onClose?.();
2929
- }
2930
- window.addEventListener("keydown", handleKey);
2931
- return () => window.removeEventListener("keydown", handleKey);
2932
- }, [onClose]);
2933
- return createPortal(/* @__PURE__ */ jsx("div", {
2934
- ref,
2935
- role: "menu",
2936
- "aria-orientation": "vertical",
2937
- style: {
2938
- top: anchor.top,
2939
- right: anchor.right
2940
- },
2941
- className: "fixed z-[9999] w-44 overflow-hidden rounded-lg border border-login-500/60 bg-login-600 shadow-xl shadow-black/40",
2942
- children: /* @__PURE__ */ jsx(MenuCtx.Provider, {
2943
- value: { onClose },
2944
- children
2945
- })
2946
- }), document.body);
2947
- }
2948
- function MenuButton({ icon, text, hotKey, onClick, className = "" }) {
2949
- const { onClose } = useContext(MenuCtx);
2950
- useEffect(() => {
2951
- if (!hotKey) return;
2952
- function handleKey(e) {
2953
- const tag = e.target.tagName;
2954
- if (tag === "INPUT" || tag === "TEXTAREA") return;
2955
- if (e.key.toLowerCase() === hotKey.toLowerCase()) {
2956
- e.preventDefault();
2957
- onClick();
2958
- onClose?.();
2959
- }
2960
- }
2961
- window.addEventListener("keydown", handleKey);
2962
- return () => window.removeEventListener("keydown", handleKey);
2963
- }, [
2964
- hotKey,
2965
- onClick,
2966
- onClose
2967
- ]);
2968
- return /* @__PURE__ */ jsxs("button", {
2969
- role: "menuitem",
2970
- onClick: () => {
2971
- onClick();
2972
- onClose?.();
2973
- },
2974
- className: `
2975
- flex w-full items-center justify-between px-3 py-2 text-sm
2976
- text-login-75 transition-colors duration-100
2977
- hover:bg-login-500 focus:bg-login-500 focus:outline-none
2978
- first:rounded-t-lg last:rounded-b-lg
2979
- ${className}
2980
- `,
2981
- children: [/* @__PURE__ */ jsxs("span", {
2982
- className: "flex items-center gap-2",
2983
- children: [/* @__PURE__ */ jsx("span", {
2984
- className: "h-4 w-4 shrink-0 flex items-center justify-center",
2985
- children: icon
2986
- }), text]
2987
- }), hotKey && /* @__PURE__ */ jsx("kbd", {
2988
- className: "font-mono text-xs opacity-40",
2989
- children: hotKey
2990
- })]
2991
- });
2992
- }
2993
- //#endregion
2994
- //#region src/components/table/body.tsx
2995
- function useClickOutside(ref, cb, enabled) {
2996
- useEffect(() => {
2997
- if (!enabled) return;
2998
- function handler(e) {
2999
- if (ref.current && !ref.current.contains(e.target)) cb();
3000
- }
3001
- document.addEventListener("mousedown", handler);
3002
- return () => document.removeEventListener("mousedown", handler);
3003
- }, [
3004
- ref,
3005
- cb,
3006
- enabled
3007
- ]);
3008
- }
3009
- function resolveRedirectUrl(redirectPath, row, id) {
3010
- if (!redirectPath) return null;
3011
- const cfg = typeof redirectPath === "string" ? {
3012
- path: redirectPath,
3013
- key: void 0
3014
- } : redirectPath;
3015
- if (!cfg.path) return null;
3016
- const rid = cfg.key ? String(row[cfg.key] ?? id) : id;
3017
- return cfg.path.includes("?") ? `${cfg.path}${rid}` : `${cfg.path}/${rid}`;
3018
- }
3019
- function Cell({ col, row, density, variant }) {
3020
- const value = row[col.key];
3021
- const shouldTruncate = col.truncate === true;
3022
- const align = col.align ?? "left";
3023
- const wrapperAlign = align === "right" ? "text-right" : align === "center" ? "text-center" : "";
3024
- let content;
3025
- if (col.render) content = col.render(value, row);
3026
- else if (col.highlight) {
3027
- const colorName = col.highlight[String(value)] ?? col.highlight["default"];
3028
- const formatted = String(formatValue(col.key, value));
3029
- if (colorName) content = /* @__PURE__ */ jsx("span", {
3030
- className: `inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${HIGHLIGHT[colorName]}`,
3031
- children: formatted
3032
- });
3033
- else content = /* @__PURE__ */ jsx("span", {
3034
- className: shouldTruncate ? "block truncate" : "whitespace-nowrap",
3035
- children: formatted
3036
- });
3037
- } else {
3038
- const formatted = formatValue(col.key, value);
3039
- content = /* @__PURE__ */ jsx("span", {
3040
- className: shouldTruncate ? "block truncate" : "whitespace-nowrap",
3041
- children: formatted === null || formatted === void 0 ? "-" : String(formatted)
3042
- });
3043
- }
3044
- return /* @__PURE__ */ jsx("td", {
3045
- style: col.width ? {
3046
- width: col.width,
3047
- maxWidth: col.width
3048
- } : void 0,
3049
- className: `
3050
- align-middle text-sm text-login-75 ${wrapperAlign}
3051
- ${DENSITY_TD[density]} ${VARIANT_ROW_BORDER[variant]}
3052
- `,
3053
- children: content
3054
- });
3055
- }
3056
- function Body({ data, columns, idKey, variant, density, striped, redirectPath, onRowClick, renderExpandedRow, selectable, selectedIds, onSelectionChange, menuItems }) {
3057
- const router = useRouter();
3058
- const [openMenuId, setOpenMenuId] = useState(null);
3059
- const [anchor, setAnchor] = useState(null);
3060
- const [expandedId, setExpandedId] = useState(null);
3061
- const menuRef = useRef(null);
3062
- const menuWasOpenOnMouseDown = useRef(false);
3063
- const closeMenu = useCallback(() => setOpenMenuId(null), []);
3064
- useClickOutside(menuRef, closeMenu, openMenuId !== null);
3065
- useEffect(() => {
3066
- if (openMenuId === null) return;
3067
- document.addEventListener("scroll", closeMenu, true);
3068
- return () => document.removeEventListener("scroll", closeMenu, true);
3069
- }, [closeMenu, openMenuId]);
3070
- function openMenu(id, coords) {
3071
- setAnchor(coords);
3072
- setOpenMenuId(id);
3073
- }
3074
- const selectedSet = useMemo(() => new Set(selectedIds), [selectedIds]);
3075
- function toggleSelect(id) {
3076
- onSelectionChange(selectedSet.has(id) ? selectedIds.filter((s) => s !== id) : [...selectedIds, id]);
3077
- }
3078
- const hasMenu = Boolean(menuItems);
3079
- const hasExpand = Boolean(renderExpandedRow);
3080
- return /* @__PURE__ */ jsx("tbody", {
3081
- className: VARIANT_TBODY[variant],
3082
- children: data.map((row, rowIdx) => {
3083
- const id = resolveId(row, idKey, columns);
3084
- const url = resolveRedirectUrl(redirectPath, row, id);
3085
- const isClickable = Boolean(url || onRowClick || hasExpand);
3086
- const isMenuOpen = openMenuId === id;
3087
- const isExpanded = expandedId === id;
3088
- const isSelected = selectable && selectedSet.has(id);
3089
- const expandedContent = renderExpandedRow?.(row);
3090
- const rowClass = [
3091
- "transition-colors duration-100",
3092
- isClickable ? "cursor-pointer" : "",
3093
- VARIANT_ROW_HOVER[variant],
3094
- striped ? VARIANT_ROW_STRIPED[variant] : "",
3095
- isSelected ? "bg-login/5" : ""
3096
- ].filter(Boolean).join(" ");
3097
- return /* @__PURE__ */ jsxs(React.Fragment, { children: [/* @__PURE__ */ jsxs("tr", {
3098
- className: rowClass,
3099
- onMouseEnter: () => {
3100
- if (url) router.prefetch(url);
3101
- },
3102
- onMouseDown: () => {
3103
- menuWasOpenOnMouseDown.current = openMenuId !== null;
3104
- },
3105
- onClick: () => {
3106
- if (menuWasOpenOnMouseDown.current) {
3107
- menuWasOpenOnMouseDown.current = false;
3108
- return;
3109
- }
3110
- if (hasExpand) {
3111
- setExpandedId(isExpanded ? null : id);
3112
- return;
3113
- }
3114
- if (onRowClick) {
3115
- onRowClick(row, id);
3116
- return;
3117
- }
3118
- if (url) router.push(url);
3119
- },
3120
- onContextMenu: (e) => {
3121
- if (!hasMenu) return;
3122
- e.preventDefault();
3123
- openMenu(id, {
3124
- top: e.clientY,
3125
- right: window.innerWidth - e.clientX
3126
- });
3127
- },
3128
- children: [
3129
- selectable && /* @__PURE__ */ jsx("td", {
3130
- className: `align-middle ${VARIANT_ROW_BORDER[variant]}`,
3131
- style: {
3132
- width: "3rem",
3133
- minWidth: "3rem"
3134
- },
3135
- children: /* @__PURE__ */ jsx("div", {
3136
- className: "flex items-center justify-center",
3137
- children: /* @__PURE__ */ jsx("button", {
3138
- type: "button",
3139
- "aria-label": isSelected ? "Deselect row" : "Select row",
3140
- "aria-checked": isSelected,
3141
- role: "checkbox",
3142
- onClick: (e) => {
3143
- e.stopPropagation();
3144
- toggleSelect(id);
3145
- },
3146
- className: `
3147
- h-4 w-4 rounded border flex items-center justify-center transition-colors cursor-pointer
3148
- ${isSelected ? "bg-login border-login text-white" : "border-login-400 bg-transparent hover:border-login-100"}
3149
- `,
3150
- children: isSelected && /* @__PURE__ */ jsx("svg", {
3151
- className: "h-3 w-3",
3152
- viewBox: "0 0 12 12",
3153
- fill: "none",
3154
- children: /* @__PURE__ */ jsx("path", {
3155
- d: "M2 6l3 3 5-5",
3156
- stroke: "currentColor",
3157
- strokeWidth: "1.5",
3158
- strokeLinecap: "round",
3159
- strokeLinejoin: "round"
3160
- })
3161
- })
3162
- })
3163
- })
3164
- }),
3165
- columns.map((col) => /* @__PURE__ */ jsx(Cell, {
3166
- col,
3167
- row,
3168
- density,
3169
- variant
3170
- }, col.key)),
3171
- hasExpand && /* @__PURE__ */ jsx("td", {
3172
- className: `align-middle ${VARIANT_ROW_BORDER[variant]}`,
3173
- style: {
3174
- width: "2.5rem",
3175
- minWidth: "2.5rem"
3176
- },
3177
- children: /* @__PURE__ */ jsx("div", {
3178
- className: "flex items-center justify-center",
3179
- children: /* @__PURE__ */ jsx(ChevronDown, { className: `
3180
- h-4 w-4 transition-transform duration-200
3181
- ${isExpanded ? "rotate-180 text-login" : "text-login-400"}
3182
- ` })
3183
- })
3184
- }),
3185
- hasMenu && /* @__PURE__ */ jsx("td", {
3186
- className: `align-middle pr-3 ${VARIANT_ROW_BORDER[variant]}`,
3187
- style: {
3188
- width: "3.5rem",
3189
- minWidth: "3.5rem"
3190
- },
3191
- children: /* @__PURE__ */ jsxs("div", {
3192
- className: "relative flex items-center justify-end",
3193
- children: [/* @__PURE__ */ jsx("button", {
3194
- type: "button",
3195
- "aria-label": "Row actions",
3196
- "aria-expanded": isMenuOpen,
3197
- "aria-haspopup": "menu",
3198
- onMouseDown: (e) => e.nativeEvent.stopImmediatePropagation(),
3199
- onClick: (e) => {
3200
- e.stopPropagation();
3201
- if (isMenuOpen) setOpenMenuId(null);
3202
- else {
3203
- const rect = e.currentTarget.getBoundingClientRect();
3204
- openMenu(id, {
3205
- top: rect.bottom + 4,
3206
- right: window.innerWidth - rect.right
3207
- });
3208
- }
3209
- },
3210
- className: `
3211
- p-1.5 rounded flex items-center justify-center transition-colors
3212
- ${isMenuOpen ? "bg-login-500 text-login-75" : "text-login-300 hover:bg-login-500/60 hover:text-login-75"}
3213
- `,
3214
- children: /* @__PURE__ */ jsx(EllipsisVertical, { className: "h-4 w-4" })
3215
- }), isMenuOpen && anchor && /* @__PURE__ */ jsx(Menu, {
3216
- ref: menuRef,
3217
- anchor,
3218
- onClose: closeMenu,
3219
- children: menuItems(row, id)
3220
- })]
3221
- })
3222
- })
3223
- ]
3224
- }), hasExpand && isExpanded && /* @__PURE__ */ jsx("tr", {
3225
- className: "bg-login-700/25",
3226
- children: /* @__PURE__ */ jsx("td", {
3227
- colSpan: 999,
3228
- className: "px-6 py-4 border-b border-login-600/20",
3229
- onClick: (e) => e.stopPropagation(),
3230
- children: expandedContent
3231
- })
3232
- })] }, id + rowIdx);
3233
- })
3234
- });
3235
- }
3236
- //#endregion
3237
- //#region src/components/table/skeleton.tsx
3238
- function Skeleton({ columns, rows, variant, density, hasMenu, hasSelect }) {
3239
- return /* @__PURE__ */ jsx("tbody", {
3240
- className: VARIANT_TBODY[variant],
3241
- children: Array.from({ length: rows }).map((_, rowIdx) => /* @__PURE__ */ jsxs("tr", { children: [
3242
- hasSelect && /* @__PURE__ */ jsx("td", {
3243
- className: `align-middle ${VARIANT_ROW_BORDER[variant]}`,
3244
- style: {
3245
- width: "3rem",
3246
- minWidth: "3rem"
3247
- },
3248
- children: /* @__PURE__ */ jsx("span", { className: "block h-4 w-4 mx-auto rounded animate-shimmer" })
3249
- }),
3250
- columns.map((col, colIdx) => /* @__PURE__ */ jsx("td", {
3251
- style: col.width ? { width: col.width } : void 0,
3252
- className: `align-middle ${DENSITY_TD[density]} ${VARIANT_ROW_BORDER[variant]}`,
3253
- children: /* @__PURE__ */ jsx("span", {
3254
- className: "block h-4 rounded animate-shimmer",
3255
- style: {
3256
- width: colIdx === 0 ? `${8 + (rowIdx * 17 + colIdx * 31) % 5}rem` : `${5 + (rowIdx * 13 + colIdx * 23) % 5}rem`,
3257
- animationDelay: `${(rowIdx * columns.length + colIdx) * 40}ms`
3258
- }
3259
- })
3260
- }, col.key)),
3261
- hasMenu && /* @__PURE__ */ jsx("td", {
3262
- className: `align-middle pr-3 ${VARIANT_ROW_BORDER[variant]}`,
3263
- style: {
3264
- width: "3.5rem",
3265
- minWidth: "3.5rem"
3266
- },
3267
- children: /* @__PURE__ */ jsx("span", { className: "block h-5 w-5 ml-auto rounded animate-shimmer" })
3268
- })
3269
- ] }, rowIdx))
3270
- });
3271
- }
3272
- //#endregion
3273
- //#region src/components/table/empty.tsx
3274
- function Empty({ emptyState }) {
3275
- if (emptyState) return /* @__PURE__ */ jsx("tbody", { children: /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
3276
- colSpan: 999,
3277
- children: /* @__PURE__ */ jsx("div", {
3278
- className: "flex items-center justify-center min-h-[160px] py-8 px-6",
3279
- children: emptyState
3280
- })
3281
- }) }) });
3282
- return /* @__PURE__ */ jsx("tbody", { children: /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
3283
- colSpan: 999,
3284
- children: /* @__PURE__ */ jsxs("div", {
3285
- className: "flex flex-col items-center justify-center gap-3 min-h-[160px] py-8 text-login-300",
3286
- children: [/* @__PURE__ */ jsx(TableIcon, { className: "h-10 w-10 opacity-30" }), /* @__PURE__ */ jsx("span", {
3287
- className: "text-sm",
3288
- children: "No data found"
3289
- })]
3290
- })
3291
- }) }) });
3292
- }
3293
- //#endregion
3294
- //#region src/components/table/pagination.tsx
3295
- function computeTotalPages(totalRows, pageSize) {
3296
- return Math.max(1, pageSize > 0 ? Math.ceil(totalRows / pageSize) : 1);
3297
- }
3298
- function pageRange(current, total) {
3299
- const delta = 2;
3300
- const left = Math.max(1, current - delta);
3301
- const right = Math.min(total, current + delta);
3302
- const pages = [];
3303
- if (left > 1) {
3304
- pages.push(1);
3305
- if (left > 2) pages.push("…");
3306
- }
3307
- for (let i = left; i <= right; i++) pages.push(i);
3308
- if (right < total) {
3309
- if (right < total - 1) pages.push("…");
3310
- pages.push(total);
3311
- }
3312
- return pages;
3313
- }
3314
- function PaginationShell({ page, totalPages, totalRows, pageSize, onPageChange, variant }) {
3315
- const start = totalRows === 0 ? 0 : (page - 1) * pageSize + 1;
3316
- const end = Math.min(page * pageSize, totalRows);
3317
- const pages = pageRange(page, totalPages);
3318
- const btnBase = `
3319
- flex items-center justify-center rounded-md border text-sm transition-colors duration-100
3320
- disabled:opacity-35 disabled:cursor-not-allowed
3321
- `;
3322
- const btnStyle = variant === "original" ? "border-login-500/50 bg-login-700 hover:bg-login-600 text-login-100" : "border-login-500/40 bg-transparent hover:bg-login-700/60 text-login-100";
3323
- const pageActive = variant === "original" ? "border-login bg-login/10 text-login" : "border-login text-login bg-transparent";
3324
- const pageInactive = variant === "original" ? "border-login-500/50 bg-login-700 text-login-100 hover:bg-login-600" : "border-transparent bg-transparent text-login-200 hover:text-login-75 hover:bg-login-700/60";
3325
- return /* @__PURE__ */ jsxs("div", {
3326
- className: "flex items-center justify-between w-full gap-4 flex-wrap",
3327
- children: [/* @__PURE__ */ jsx("span", {
3328
- className: "text-xs text-login-300 tabular-nums",
3329
- children: totalRows === 0 ? "No results" : `${start}-${end} of ${totalRows}`
3330
- }), /* @__PURE__ */ jsxs("nav", {
3331
- className: "flex items-center gap-1.5",
3332
- "aria-label": "Pagination",
3333
- children: [
3334
- /* @__PURE__ */ jsx("button", {
3335
- type: "button",
3336
- "aria-label": "Previous page",
3337
- disabled: page <= 1,
3338
- onClick: () => onPageChange(page - 1),
3339
- className: `${btnBase} ${btnStyle} h-8 w-8`,
3340
- children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
3341
- }),
3342
- pages.map((p, i) => p === "…" ? /* @__PURE__ */ jsx("span", {
3343
- className: "w-8 text-center text-sm text-login-400 select-none",
3344
- children: "…"
3345
- }, `ellipsis-${i}`) : /* @__PURE__ */ jsx("button", {
3346
- type: "button",
3347
- "aria-current": p === page ? "page" : void 0,
3348
- onClick: () => onPageChange(p),
3349
- className: `${btnBase} h-8 min-w-8 px-2 tabular-nums ${p === page ? pageActive : pageInactive}`,
3350
- children: p
3351
- }, p)),
3352
- /* @__PURE__ */ jsx("button", {
3353
- type: "button",
3354
- "aria-label": "Next page",
3355
- disabled: page >= totalPages,
3356
- onClick: () => onPageChange(page + 1),
3357
- className: `${btnBase} ${btnStyle} h-8 w-8`,
3358
- children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
3359
- })
3360
- ]
3361
- })]
3362
- });
3363
- }
3364
- function PaginationLocalState({ totalRows, pageSize, variant = "original" }) {
3365
- const [page, setPage] = useState(1);
3366
- return /* @__PURE__ */ jsx(PaginationShell, {
3367
- page,
3368
- totalPages: computeTotalPages(totalRows, pageSize),
3369
- totalRows,
3370
- pageSize,
3371
- onPageChange: setPage,
3372
- variant
3373
- });
3374
- }
3375
- function PaginationURLState({ totalRows, pageSize, variant = "original" }) {
3376
- const router = useRouter();
3377
- const pathname = usePathname();
3378
- const searchParams = useSearchParams();
3379
- const page = Math.max(1, parseInt(searchParams.get("page") ?? "1", 10) || 1);
3380
- function onPageChange(p) {
3381
- const params = new URLSearchParams(searchParams.toString());
3382
- params.set("page", String(p));
3383
- router.replace(`${pathname}?${params.toString()}`);
3384
- }
3385
- return /* @__PURE__ */ jsx(PaginationShell, {
3386
- page,
3387
- totalPages: computeTotalPages(totalRows, pageSize),
3388
- totalRows,
3389
- pageSize,
3390
- onPageChange,
3391
- variant
3392
- });
3393
- }
3394
- function Pagination(props) {
3395
- const { totalRows, pageSize, variant = "original", urlState, page, onPageChange } = props;
3396
- if (urlState) return /* @__PURE__ */ jsx(Suspense, {
3397
- fallback: /* @__PURE__ */ jsx(PaginationShell, {
3398
- page: 1,
3399
- totalPages: computeTotalPages(totalRows, pageSize),
3400
- totalRows,
3401
- pageSize,
3402
- onPageChange: () => {},
3403
- variant
3404
- }),
3405
- children: /* @__PURE__ */ jsx(PaginationURLState, { ...props })
3406
- });
3407
- if (page !== void 0 && onPageChange !== void 0) return /* @__PURE__ */ jsx(PaginationShell, {
3408
- page,
3409
- totalPages: computeTotalPages(totalRows, pageSize),
3410
- totalRows,
3411
- pageSize,
3412
- onPageChange,
3413
- variant
3414
- });
3415
- return /* @__PURE__ */ jsx(PaginationLocalState, { ...props });
3416
- }
3417
- //#endregion
3418
- //#region src/components/table/table.tsx
3419
- function TableShell({ data, columns, idKey, variant, density, striped, loading, loadingRows, emptyState, redirectPath, onRowClick, renderExpandedRow, selectable, selectedIds, onSelectionChange, sort, onSort, page, onPageChange, totalRows, pageSize, hidePagination, menuItems, className }) {
3420
- const allIds = data.map((row) => resolveId(row, idKey, columns));
3421
- const allIdsSet = useMemo(() => new Set(allIds), [allIds]);
3422
- const allSelected = allIds.length > 0 && allIds.every((id) => selectedIds.includes(id));
3423
- const someSelected = !allSelected && allIds.some((id) => selectedIds.includes(id));
3424
- function handleSelectAll() {
3425
- if (allSelected) onSelectionChange(selectedIds.filter((id) => !allIdsSet.has(id)));
3426
- else onSelectionChange([.../* @__PURE__ */ new Set([...selectedIds, ...allIds])]);
3427
- }
3428
- const isEmpty = !loading && data.length === 0;
3429
- const showPagination = !hidePagination && pageSize > 0 && totalRows > 0;
3430
- const hasMenu = Boolean(menuItems);
3431
- const hasSelect = Boolean(selectable);
3432
- const hasExpand = Boolean(renderExpandedRow);
3433
- const paginationPad = variant === "original" ? "px-4 pb-4 pt-3" : "pt-4";
3434
- return /* @__PURE__ */ jsxs("div", {
3435
- className: [
3436
- "flex flex-col min-h-0 w-full",
3437
- VARIANT_CONTAINER[variant],
3438
- className
3439
- ].filter(Boolean).join(" "),
3440
- children: [/* @__PURE__ */ jsx("div", {
3441
- className: "flex-1 min-h-0 overflow-auto",
3442
- children: /* @__PURE__ */ jsxs("table", {
3443
- className: "min-w-full table-auto border-separate border-spacing-0",
3444
- children: [/* @__PURE__ */ jsx(Header, {
3445
- columns,
3446
- sort,
3447
- onSort,
3448
- hasMenu,
3449
- hasSelect,
3450
- hasExpand,
3451
- allSelected,
3452
- someSelected,
3453
- onSelectAll: handleSelectAll,
3454
- variant,
3455
- density
3456
- }), loading ? /* @__PURE__ */ jsx(Skeleton, {
3457
- columns,
3458
- rows: loadingRows,
3459
- variant,
3460
- density,
3461
- hasMenu,
3462
- hasSelect
3463
- }) : isEmpty ? /* @__PURE__ */ jsx(Empty, { emptyState }) : /* @__PURE__ */ jsx(Body, {
3464
- data,
3465
- columns,
3466
- idKey,
3467
- variant,
3468
- density,
3469
- striped,
3470
- redirectPath,
3471
- onRowClick,
3472
- renderExpandedRow,
3473
- selectable,
3474
- selectedIds,
3475
- onSelectionChange,
3476
- menuItems
3477
- })]
3478
- })
3479
- }), showPagination && /* @__PURE__ */ jsx("div", {
3480
- className: paginationPad,
3481
- children: /* @__PURE__ */ jsx(Pagination, {
3482
- page,
3483
- totalRows,
3484
- pageSize,
3485
- onPageChange,
3486
- variant
3487
- })
3488
- })]
3489
- });
3490
- }
3491
- function useInternalSelection(props) {
3492
- const [internal, setInternal] = useState([]);
3493
- return {
3494
- selectedIds: props.selectedIds ?? internal,
3495
- onSelectionChange: props.onSelectionChange ?? setInternal
3496
- };
3497
- }
3498
- function applyDefaults(props) {
3499
- return {
3500
- variant: props.variant ?? "original",
3501
- density: props.density ?? "comfortable",
3502
- selectable: props.selectable ?? false,
3503
- loading: props.loading ?? false,
3504
- loadingRows: props.loadingRows ?? props.pageSize ?? 5,
3505
- striped: props.striped ?? false,
3506
- hidePagination: props.hidePagination ?? false,
3507
- pageSize: props.pageSize ?? 0
3508
- };
3509
- }
3510
- function TableLocalState(props) {
3511
- const defaults = applyDefaults(props);
3512
- const selection = useInternalSelection(props);
3513
- const [sort, setSort] = useState(void 0);
3514
- const [page, setPage] = useState(1);
3515
- const ps = defaults.pageSize;
3516
- const allRows = props.data.length;
3517
- const sorted = useMemo(() => {
3518
- if (!sort) return props.data;
3519
- return [...props.data].sort((a, b) => {
3520
- const av = a[sort.column];
3521
- const bv = b[sort.column];
3522
- const cmp = String(av ?? "").localeCompare(String(bv ?? ""), void 0, {
3523
- numeric: true,
3524
- sensitivity: "base"
3525
- });
3526
- return sort.order === "asc" ? cmp : -cmp;
3527
- });
3528
- }, [props.data, sort]);
3529
- const displayData = ps > 0 ? sorted.slice((page - 1) * ps, page * ps) : sorted;
3530
- function handleSort(newSort) {
3531
- setSort(newSort);
3532
- setPage(1);
3533
- }
3534
- return /* @__PURE__ */ jsx(TableShell, {
3535
- ...props,
3536
- ...defaults,
3537
- ...selection,
3538
- data: displayData,
3539
- sort,
3540
- onSort: handleSort,
3541
- page,
3542
- onPageChange: setPage,
3543
- totalRows: ps > 0 ? allRows : props.totalRows ?? allRows
3544
- });
3545
- }
3546
- function TableURLState(props) {
3547
- const defaults = applyDefaults(props);
3548
- const selection = useInternalSelection(props);
3549
- const router = useRouter();
3550
- const pathname = usePathname();
3551
- const searchParams = useSearchParams();
3552
- const urlColumn = searchParams.get("column") ?? "";
3553
- const urlOrder = searchParams.get("order") ?? "asc";
3554
- const urlPage = Math.max(1, parseInt(searchParams.get("page") ?? "1", 10) || 1);
3555
- const sort = urlColumn ? {
3556
- column: urlColumn,
3557
- order: urlOrder
3558
- } : void 0;
3559
- function handleSort(newSort) {
3560
- const p = new URLSearchParams(searchParams.toString());
3561
- p.set("column", newSort.column);
3562
- p.set("order", newSort.order);
3563
- p.set("page", "1");
3564
- router.replace(`${pathname}?${p.toString()}`);
3565
- }
3566
- function handlePageChange(newPage) {
3567
- const p = new URLSearchParams(searchParams.toString());
3568
- p.set("page", String(newPage));
3569
- router.replace(`${pathname}?${p.toString()}`);
3570
- }
3571
- return /* @__PURE__ */ jsx(TableShell, {
3572
- ...props,
3573
- ...defaults,
3574
- ...selection,
3575
- sort,
3576
- onSort: handleSort,
3577
- page: urlPage,
3578
- onPageChange: handlePageChange,
3579
- totalRows: props.totalRows ?? props.data.length
3580
- });
3581
- }
3582
- function TableControlled(props) {
3583
- const defaults = applyDefaults(props);
3584
- const selection = useInternalSelection(props);
3585
- return /* @__PURE__ */ jsx(TableShell, {
3586
- ...props,
3587
- ...defaults,
3588
- ...selection,
3589
- sort: props.sort,
3590
- onSort: props.onSort,
3591
- page: props.page ?? 1,
3592
- onPageChange: props.onPageChange ?? (() => {}),
3593
- totalRows: props.totalRows ?? props.data.length
3594
- });
3595
- }
3596
- function Table(props) {
3597
- if (props.sort !== void 0 || props.onSort !== void 0) return /* @__PURE__ */ jsx(TableControlled, { ...props });
3598
- if (props.urlState) {
3599
- const defaults = applyDefaults(props);
3600
- return /* @__PURE__ */ jsx(Suspense, {
3601
- fallback: /* @__PURE__ */ jsx(TableShell, {
3602
- ...props,
3603
- ...defaults,
3604
- selectedIds: props.selectedIds ?? [],
3605
- onSelectionChange: props.onSelectionChange ?? (() => {}),
3606
- sort: void 0,
3607
- onSort: () => {},
3608
- page: 1,
3609
- onPageChange: () => {},
3610
- totalRows: props.totalRows ?? props.data.length
3611
- }),
3612
- children: /* @__PURE__ */ jsx(TableURLState, { ...props })
3613
- });
3614
- }
3615
- return /* @__PURE__ */ jsx(TableLocalState, { ...props });
3616
- }
3617
- //#endregion
3618
- //#region src/components/confirm/confirmPopup.tsx
3619
- function ConfirmPopup({ isOpen, header, description, confirmText = "Confirm", cancelText = "Cancel", onConfirm, onCancel, variant = "default" }) {
3620
- if (!isOpen) return null;
3621
- return /* @__PURE__ */ jsxs("div", {
3622
- role: "dialog",
3623
- "aria-modal": "true",
3624
- "aria-labelledby": "confirm-popup-header",
3625
- className: "fixed inset-0 z-50 flex items-center justify-center",
3626
- onClick: onCancel,
3627
- children: [/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/50 backdrop-blur-sm" }), /* @__PURE__ */ jsxs("div", {
3628
- className: "\n relative z-10 w-full max-w-md mx-4\n bg-login-800 border border-login-500/50 rounded-xl\n shadow-2xl p-6 flex flex-col gap-4\n ",
3629
- onClick: (e) => e.stopPropagation(),
3630
- children: [
3631
- /* @__PURE__ */ jsxs("div", {
3632
- className: "flex items-start gap-3",
3633
- children: [variant !== "default" && /* @__PURE__ */ jsx(TriangleAlert, { className: `w-5 h-5 shrink-0 mt-0.5 ${variant === "danger" ? "stroke-red-400" : "stroke-yellow-400"}` }), /* @__PURE__ */ jsx("h2", {
3634
- id: "confirm-popup-header",
3635
- className: "text-login-50 text-base font-semibold leading-snug",
3636
- children: header
3637
- })]
3638
- }),
3639
- description && /* @__PURE__ */ jsx("p", {
3640
- className: "text-login-200 text-sm leading-relaxed",
3641
- children: description
3642
- }),
3643
- /* @__PURE__ */ jsxs("div", {
3644
- className: "flex justify-end gap-2 mt-1",
3645
- children: [/* @__PURE__ */ jsx("button", {
3646
- type: "button",
3647
- onClick: onCancel,
3648
- className: "\n cursor-pointer px-4 py-1.5 rounded-md text-sm font-medium\n bg-login-600 hover:bg-login-500 text-login-100\n transition-colors duration-150 select-none\n ",
3649
- children: cancelText
3650
- }), /* @__PURE__ */ jsx("button", {
3651
- type: "button",
3652
- onClick: onConfirm,
3653
- className: `
3654
- cursor-pointer px-4 py-1.5 rounded-md text-sm font-medium
3655
- transition-all duration-150 select-none
3656
- ${variant === "danger" ? "bg-red-600 hover:brightness-110 text-white" : variant === "warning" ? "bg-yellow-500 hover:brightness-110 text-black" : "bg-login hover:brightness-110 text-white"}
3657
- `,
3658
- children: confirmText
3659
- })]
3660
- })
3661
- ]
3662
- })]
3663
- });
3664
- }
3665
- //#endregion
3666
- //#region src/components/vulnerability/constants.ts
3667
- const severityLabel = {
3668
- critical: "Critical",
3669
- high: "High",
3670
- medium: "Medium",
3671
- low: "Low",
3672
- unknown: "Unknown"
3673
- };
3674
- const severityClasses = {
3675
- critical: "border-l-red-500",
3676
- high: "border-l-orange-500",
3677
- medium: "border-l-amber-500",
3678
- low: "border-l-green-500",
3679
- unknown: "border-l-login-400"
3680
- };
3681
- //#endregion
3682
- //#region src/components/vulnerability/severityPill.tsx
3683
- function SeverityPill({ severity, count, compact = false }) {
3684
- if (count === 0) return null;
3685
- return /* @__PURE__ */ jsxs(LeftBarPanel, {
3686
- color: severityClasses[severity],
3687
- className: `flex items-center gap-2.5 ${compact ? "px-2.5 py-1.5" : "px-3 py-2"}`,
3688
- children: [/* @__PURE__ */ jsx("span", {
3689
- className: `${compact ? "text-sm" : "text-base"} font-bold text-login-50`,
3690
- children: count
3691
- }), /* @__PURE__ */ jsx("span", {
3692
- className: "text-[10px] font-semibold uppercase tracking-[0.15em] text-login-300",
3693
- children: severityLabel[severity]
3694
- })]
3695
- });
3696
- }
3697
- //#endregion
3698
- //#region src/components/inputs/toggle.tsx
3699
- function Toggle({ value, onChange, left, right }) {
3700
- const active = "bg-login text-white shadow-sm";
3701
- const idle = "text-login-200 hover:text-login-50 hover:bg-login-500/50";
3702
- const base = "flex items-center justify-center rounded-md px-3 h-7 transition-all duration-150 gap-1.5 text-sm";
3703
- function renderContent(opt) {
3704
- return /* @__PURE__ */ jsxs(Fragment, { children: [opt.icon, opt.text && /* @__PURE__ */ jsx("span", { children: opt.text })] });
3705
- }
3706
- const isLeftActive = value === left.value;
3707
- const isRightActive = value === right.value;
3708
- return /* @__PURE__ */ jsxs("div", {
3709
- className: "flex items-center w-fit bg-login-500/50 border border-login-500 rounded-lg p-1 gap-0.5",
3710
- children: [/* @__PURE__ */ jsx("button", {
3711
- type: "button",
3712
- onClick: () => onChange(left.value),
3713
- "aria-label": left.label ?? left.text,
3714
- "aria-pressed": isLeftActive,
3715
- className: `${base} ${isLeftActive ? active : idle}`,
3716
- children: renderContent(left)
3717
- }), /* @__PURE__ */ jsx("button", {
3718
- type: "button",
3719
- onClick: () => onChange(right.value),
3720
- "aria-label": right.label ?? right.text,
3721
- "aria-pressed": isRightActive,
3722
- className: `${base} ${isRightActive ? active : idle}`,
3723
- children: renderContent(right)
3724
- })]
3725
- });
3726
- }
3727
- //#endregion
3728
- //#region src/components/inputs/fileInput.tsx
3729
- function FileInput({ name, label, accept, multiple = false, onChange, className = "" }) {
3730
- const [files, setFiles] = useState([]);
3731
- const [dragging, setDragging] = useState(false);
3732
- const inputRef = useRef(null);
3733
- function handleFiles(incoming) {
3734
- if (!incoming) return;
3735
- const arr = multiple ? Array.from(incoming) : [incoming[0]];
3736
- setFiles(arr);
3737
- onChange(arr);
3738
- }
3739
- function removeFile(index) {
3740
- const next = files.filter((_, i) => i !== index);
3741
- setFiles(next);
3742
- onChange(next);
3743
- if (inputRef.current) inputRef.current.value = "";
3744
- }
3745
- function onDrop(e) {
3746
- e.preventDefault();
3747
- setDragging(false);
3748
- handleFiles(e.dataTransfer.files);
3749
- }
3750
- return /* @__PURE__ */ jsxs("div", {
3751
- className: `flex flex-col gap-2 ${className}`,
3752
- children: [
3753
- label && /* @__PURE__ */ jsx("label", {
3754
- className: "text-sm font-medium text-login-200",
3755
- children: label
3756
- }),
3757
- /* @__PURE__ */ jsxs("div", {
3758
- role: "button",
3759
- tabIndex: 0,
3760
- onClick: () => inputRef.current?.click(),
3761
- onKeyDown: (e) => {
3762
- if (e.key === "Enter" || e.key === " ") inputRef.current?.click();
3763
- },
3764
- onDragOver: (e) => {
3765
- e.preventDefault();
3766
- setDragging(true);
3767
- },
3768
- onDragLeave: () => setDragging(false),
3769
- onDrop,
3770
- className: `
3771
- flex cursor-pointer flex-col items-center justify-center gap-2 rounded-xl border-2 border-dashed p-6
3772
- transition-all duration-150
3773
- ${dragging ? "scale-[1.01] border-login bg-login/5" : "border-login-500/50 bg-login-800/30 hover:border-login/50 hover:bg-login/5"}
3774
- `,
3775
- children: [
3776
- /* @__PURE__ */ jsx("input", {
3777
- ref: inputRef,
3778
- type: "file",
3779
- name,
3780
- accept,
3781
- multiple,
3782
- className: "hidden",
3783
- onChange: (e) => handleFiles(e.target.files)
3784
- }),
3785
- /* @__PURE__ */ jsx(UploadCloud, { className: "h-7 w-7 text-login-400" }),
3786
- /* @__PURE__ */ jsxs("div", {
3787
- className: "text-center",
3788
- children: [/* @__PURE__ */ jsxs("p", {
3789
- className: "text-sm text-login-200",
3790
- children: ["Drop files here or ", /* @__PURE__ */ jsx("span", {
3791
- className: "text-login",
3792
- children: "browse"
3793
- })]
3794
- }), accept && /* @__PURE__ */ jsx("p", {
3795
- className: "mt-0.5 text-xs text-login-400",
3796
- children: accept
3797
- })]
3798
- })
3799
- ]
3800
- }),
3801
- files.length > 0 && /* @__PURE__ */ jsx("ul", {
3802
- className: "flex flex-col gap-1.5",
3803
- children: files.map((file, i) => /* @__PURE__ */ jsxs("li", {
3804
- className: "\n flex items-center gap-2 rounded-lg\n border border-login-500/25 bg-login-800/50 px-3 py-2 text-sm\n ",
3805
- children: [
3806
- /* @__PURE__ */ jsx(FileIcon, { className: "h-4 w-4 shrink-0 text-login-400" }),
3807
- /* @__PURE__ */ jsx("span", {
3808
- className: "flex-1 truncate text-login-200",
3809
- children: file.name
3810
- }),
3811
- /* @__PURE__ */ jsxs("span", {
3812
- className: "shrink-0 text-xs text-login-400",
3813
- children: [(file.size / 1024).toFixed(1), " KB"]
3814
- }),
3815
- /* @__PURE__ */ jsx("button", {
3816
- type: "button",
3817
- onClick: (e) => {
3818
- e.stopPropagation();
3819
- removeFile(i);
3820
- },
3821
- className: "cursor-pointer text-login-400 transition-colors hover:text-red-400",
3822
- children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
3823
- })
3824
- ]
3825
- }, i))
3826
- })
3827
- ]
3828
- });
3829
- }
3830
- //#endregion
3831
- //#region src/components/container/glassCard.tsx
3832
- function GlassCard({ children, className = "" }) {
3833
- return /* @__PURE__ */ jsx("div", {
3834
- className: `rounded-xl border border-login-500/20 bg-login-800/60 backdrop-blur-sm ${className}`,
3835
- children
3836
- });
3837
- }
3838
- //#endregion
3839
- //#region src/components/container/expandableCard.tsx
3840
- function ExpandableCard({ icon, iconTone = "orange", title, subtitle, pulse, trailing, isExpanded, onToggle, children }) {
3841
- return /* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsxs("div", {
3842
- role: "button",
3843
- tabIndex: 0,
3844
- onClick: onToggle,
3845
- onKeyDown: (e) => {
3846
- if (e.key === "Enter" || e.key === " ") {
3847
- e.preventDefault();
3848
- onToggle();
3849
- }
3850
- },
3851
- "aria-expanded": isExpanded,
3852
- className: "group flex cursor-pointer select-none items-center gap-4 px-5 py-4",
3853
- children: [
3854
- /* @__PURE__ */ jsx(IconBubble, {
3855
- icon,
3856
- tone: iconTone,
3857
- size: "sm"
3858
- }),
3859
- /* @__PURE__ */ jsxs("div", {
3860
- className: "min-w-0 flex-1",
3861
- children: [/* @__PURE__ */ jsxs("div", {
3862
- className: "flex flex-wrap items-center gap-3",
3863
- children: [/* @__PURE__ */ jsx("span", {
3864
- className: "font-semibold text-login-50 transition group-hover:text-login",
3865
- children: title
3866
- }), pulse && /* @__PURE__ */ jsxs("span", {
3867
- className: "flex items-center gap-2 text-xs text-login-300",
3868
- children: [/* @__PURE__ */ jsx("span", {
3869
- className: "flex h-3 w-3 shrink-0 items-center justify-center",
3870
- children: /* @__PURE__ */ jsx(PulseDot, {
3871
- variant: pulse.variant,
3872
- size: "sm"
3873
- })
3874
- }), pulse.label]
3875
- })]
3876
- }), subtitle && /* @__PURE__ */ jsx("div", {
3877
- className: "mt-0.5 text-xs text-login-300",
3878
- children: subtitle
3879
- })]
3880
- }),
3881
- trailing && /* @__PURE__ */ jsx("div", {
3882
- className: "flex shrink-0 items-center gap-3",
3883
- onClick: (e) => e.stopPropagation(),
3884
- children: trailing
3885
- }),
3886
- /* @__PURE__ */ jsx(Button, {
3887
- variant: "secondary",
3888
- icon: /* @__PURE__ */ jsx(ChevronDown, { className: `h-4 w-4 transition-transform duration-200 ${isExpanded ? "rotate-180" : ""}` }),
3889
- onClick: (e) => {
3890
- e.stopPropagation();
3891
- onToggle();
3892
- }
3893
- })
3894
- ]
3895
- }), isExpanded && children && /* @__PURE__ */ jsx("div", {
3896
- className: "border-t border-white/5 px-5 pb-5 pt-4",
3897
- children
3898
- })] });
3899
- }
3900
- //#endregion
3901
- //#region src/components/modal/modal.tsx
3902
- const sizes$2 = {
3903
- sm: "max-w-sm",
3904
- md: "max-w-md",
3905
- lg: "max-w-lg"
3906
- };
3907
- function Modal({ isOpen, onClose, title, children, footer, size = "md" }) {
3908
- useEffect(() => {
3909
- if (!isOpen) return;
3910
- const handler = (e) => {
3911
- if (e.key === "Escape") onClose();
3912
- };
3913
- document.addEventListener("keydown", handler);
3914
- return () => document.removeEventListener("keydown", handler);
3915
- }, [isOpen, onClose]);
3916
- if (!isOpen) return null;
3917
- return /* @__PURE__ */ jsxs("div", {
3918
- role: "dialog",
3919
- "aria-modal": "true",
3920
- className: "fixed inset-0 z-50 flex items-center justify-center",
3921
- onClick: onClose,
3922
- children: [/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/50 backdrop-blur-sm" }), /* @__PURE__ */ jsxs("div", {
3923
- className: `
3924
- relative z-10 mx-4 w-full ${sizes$2[size]}
3925
- flex flex-col rounded-xl border border-login-500/50
3926
- bg-login-800 shadow-2xl
3927
- `,
3928
- onClick: (e) => e.stopPropagation(),
3929
- children: [
3930
- title && /* @__PURE__ */ jsxs("div", {
3931
- className: "flex items-center justify-between px-6 pt-5 pb-4 border-b border-login-500/25",
3932
- children: [/* @__PURE__ */ jsx("h2", {
3933
- className: "text-login-50 text-base font-semibold leading-snug",
3934
- children: title
3935
- }), /* @__PURE__ */ jsx("button", {
3936
- type: "button",
3937
- onClick: onClose,
3938
- className: "\n cursor-pointer rounded-md p-1.5\n text-login-400 hover:text-login-100 hover:bg-login-600\n transition-colors\n ",
3939
- children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
3940
- })]
3941
- }),
3942
- /* @__PURE__ */ jsx("div", {
3943
- className: "p-6",
3944
- children
3945
- }),
3946
- footer && /* @__PURE__ */ jsx("div", {
3947
- className: "px-6 pb-5 pt-4 border-t border-login-500/25",
3948
- children: footer
3949
- })
3950
- ]
3951
- })]
3952
- });
3953
- }
3954
- //#endregion
3955
- //#region src/components/sidebar/sidebar.tsx
3956
- const ITEM_HEIGHT = 48;
3957
- const GAP = 4;
3958
- const SUB_STRIDE = 40;
3959
- function Sidebar({ items, header, bottomAction, mobile = false, initialExpanded = true, onExpandedChange, className = "" }) {
3960
- const [expanded, setExpanded] = useState(initialExpanded);
3961
- const pathname = usePathname();
3962
- const searchParams = useSearchParams();
3963
- const fullPath = pathname + (searchParams.toString() ? `?${searchParams.toString()}` : "");
3964
- function toggleExpanded() {
3965
- const next = !expanded;
3966
- setExpanded(next);
3967
- onExpandedChange?.(next);
3968
- }
3969
- function isSubActive(sub) {
3970
- return sub.path.includes("?") ? fullPath.startsWith(sub.path) : pathname === sub.path;
3971
- }
3972
- function isItemActive(item) {
3973
- return pathname === item.path || !!item.items?.some((sub) => sub.path.includes("?") ? fullPath.startsWith(sub.path) : pathname === sub.path || pathname.startsWith(sub.path + "/"));
3974
- }
3975
- const activeIndex = items.findIndex(isItemActive);
3976
- const activeOffset = items.slice(0, Math.max(activeIndex, 0)).reduce((acc, item) => acc + ITEM_HEIGHT + (item.items ? GAP : 0) + GAP, 0);
3977
- return /* @__PURE__ */ jsxs("aside", {
3978
- className: `
3979
- flex flex-col border-r border-login-100/10 bg-login-900
3980
- transition-all duration-300 ease-in-out
3981
- ${mobile ? "w-full" : `h-full ${expanded ? "w-64" : "w-20"}`}
3982
- ${className}
3983
- `,
3984
- children: [
3985
- !mobile && /* @__PURE__ */ jsxs("div", {
3986
- className: `relative mb-2 p-4 transition-all duration-300 ${expanded ? "h-16" : "h-20"}`,
3987
- children: [header && /* @__PURE__ */ jsx("div", {
3988
- className: `
3989
- absolute top-4 flex items-center transition-all duration-300
3990
- ${expanded ? "left-4 gap-3" : "left-1/2 -translate-x-1/2 gap-0"}
3991
- `,
3992
- children: typeof header === "function" ? header(expanded) : header
3993
- }), /* @__PURE__ */ jsx("button", {
3994
- onClick: toggleExpanded,
3995
- className: `
3996
- absolute cursor-pointer rounded-lg p-1.5
3997
- text-login-200 transition-all duration-300 hover:bg-login-800
3998
- ${expanded ? "right-4 top-4" : "left-1/2 top-12 -translate-x-1/2"}
3999
- `,
4000
- children: expanded ? /* @__PURE__ */ jsx(ChevronLeft, { size: 20 }) : /* @__PURE__ */ jsx(ChevronRight, { size: 20 })
4001
- })]
4002
- }),
4003
- mobile && /* @__PURE__ */ jsx("div", { className: "h-4" }),
4004
- /* @__PURE__ */ jsxs("div", {
4005
- className: "relative flex flex-1 flex-col gap-1 overflow-x-hidden overflow-y-auto px-3 [scrollbar-width:none]",
4006
- children: [activeIndex >= 0 && /* @__PURE__ */ jsx("span", {
4007
- "aria-hidden": true,
4008
- className: "absolute left-3 right-3 top-0 h-12 rounded-lg bg-login-800 transition-transform duration-300 ease-in-out",
4009
- style: { transform: `translateY(${activeOffset}px)` }
4010
- }), items.map((item, index) => {
4011
- const isActive = isItemActive(item);
4012
- const Icon = item.icon;
4013
- const activeSubIndex = item.items ? item.items.findIndex(isSubActive) : -1;
4014
- return /* @__PURE__ */ jsxs("div", {
4015
- className: "flex flex-col gap-1",
4016
- children: [/* @__PURE__ */ jsxs(Link, {
4017
- href: item.path,
4018
- title: !expanded ? item.name : void 0,
4019
- className: `
4020
- group relative z-10 flex items-center
4021
- overflow-hidden rounded-lg p-3 transition-all duration-200
4022
- ${isActive ? "text-login" : "text-login-200 hover:bg-login-800/50 hover:text-login-100"}
4023
- `,
4024
- children: [
4025
- /* @__PURE__ */ jsx("div", {
4026
- className: `
4027
- flex min-w-6 w-6 items-center justify-center transition-all duration-300
4028
- ${expanded ? "" : "translate-x-1"}
4029
- ${isActive ? "[&>svg]:stroke-login" : "group-hover:[&>svg]:stroke-login-100"}
4030
- `,
4031
- children: /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5" })
4032
- }),
4033
- /* @__PURE__ */ jsx("span", {
4034
- className: `
4035
- whitespace-nowrap overflow-hidden transition-all duration-300
4036
- ${expanded ? "ml-3 max-w-48 opacity-100" : "ml-0 max-w-0 opacity-0"}
4037
- `,
4038
- children: item.name
4039
- }),
4040
- item.status && /* @__PURE__ */ jsx("div", {
4041
- className: `
4042
- flex items-center justify-center
4043
- ${expanded ? "ml-auto" : "absolute right-1 top-1 scale-75"}
4044
- `,
4045
- children: item.status
4046
- })
4047
- ]
4048
- }), item.items && /* @__PURE__ */ jsxs("div", {
4049
- className: `
4050
- relative ml-6 flex flex-col gap-1 overflow-hidden
4051
- border-l border-login-800 pl-2
4052
- transition-all duration-300 ease-in-out
4053
- ${expanded && isActive ? "max-h-96 opacity-100" : "max-h-0 opacity-0"}
4054
- `,
4055
- children: [activeSubIndex >= 0 && /* @__PURE__ */ jsx("span", {
4056
- "aria-hidden": true,
4057
- className: "\n absolute left-2 right-0 top-0 h-9 rounded-lg\n bg-login-800/50 transition-transform duration-300 ease-in-out\n ",
4058
- style: { transform: `translateY(${activeSubIndex * SUB_STRIDE}px)` }
4059
- }), item.items.map((sub, subIndex) => {
4060
- const subActive = isSubActive(sub);
4061
- return /* @__PURE__ */ jsx(Link, {
4062
- href: sub.path,
4063
- className: `
4064
- relative z-10 rounded-lg p-2 text-sm
4065
- transition-all duration-200
4066
- ${subActive ? "text-login" : "text-login-300 hover:bg-login-800/30 hover:text-login-100"}
4067
- `,
4068
- children: sub.name
4069
- }, `${index}-${subIndex}`);
4070
- })]
4071
- })]
4072
- }, index);
4073
- })]
4074
- }),
4075
- bottomAction && /* @__PURE__ */ jsx("div", {
4076
- className: "border-t border-login-100/10 p-3",
4077
- children: bottomAction(expanded)
4078
- })
4079
- ]
4080
- });
4081
- }
4082
- //#endregion
4083
- //#region src/components/badge/badge.tsx
4084
- const variants = {
4085
- default: "bg-login-600 text-login-100",
4086
- success: "bg-emerald-500/15 text-emerald-400",
4087
- warning: "bg-yellow-500/15 text-yellow-400",
4088
- danger: "bg-red-500/15 text-red-400",
4089
- info: "bg-sky-500/15 text-sky-400",
4090
- amber: "bg-amber-500/15 text-amber-400",
4091
- violet: "bg-violet-500/15 text-violet-400",
4092
- blue: "bg-blue-500/15 text-blue-400",
4093
- emerald: "bg-emerald-500/15 text-emerald-400",
4094
- orange: "bg-login/15 text-login"
4095
- };
4096
- const sizes$1 = {
4097
- sm: "px-2 py-0.5 text-xs",
4098
- md: "px-2.5 py-1 text-sm"
4099
- };
4100
- function Badge({ text, variant = "default", size = "sm", className = "" }) {
4101
- return /* @__PURE__ */ jsx("span", {
4102
- className: `inline-flex items-center rounded-full font-medium ${variants[variant]} ${sizes$1[size]} ${className}`,
4103
- children: text
4104
- });
4105
- }
4106
- //#endregion
4107
- //#region src/components/empty/emptyState.tsx
4108
- function EmptyState({ icon: Icon, title, description, action, className = "" }) {
4109
- return /* @__PURE__ */ jsxs("div", {
4110
- className: `flex flex-col items-center justify-center gap-3 py-12 text-center ${className}`,
4111
- children: [
4112
- Icon && /* @__PURE__ */ jsx("div", {
4113
- className: "mb-1 rounded-xl bg-login-600/30 p-3 text-login-400",
4114
- children: /* @__PURE__ */ jsx(Icon, { className: "h-7 w-7" })
4115
- }),
4116
- /* @__PURE__ */ jsx("p", {
4117
- className: "text-sm font-semibold text-login-100",
4118
- children: title
4119
- }),
4120
- description && /* @__PURE__ */ jsx("p", {
4121
- className: "max-w-xs text-xs leading-relaxed text-login-400",
4122
- children: description
4123
- }),
4124
- action && /* @__PURE__ */ jsx("div", {
4125
- className: "mt-2",
4126
- children: action
4127
- })
4128
- ]
4129
- });
4130
- }
4131
- //#endregion
4132
- //#region src/components/spinner/spinner.tsx
4133
- const sizes = {
4134
- sm: "w-4 h-4 border-2",
4135
- md: "w-6 h-6 border-2",
4136
- lg: "w-9 h-9 border-[3px]"
4137
- };
4138
- function Spinner({ size = "md", className = "" }) {
4139
- return /* @__PURE__ */ jsx("div", {
4140
- role: "status",
4141
- "aria-label": "Loading",
4142
- className: `rounded-full border-login-500 border-t-login animate-spin ${sizes[size]} ${className}`
4143
- });
4144
- }
4145
- //#endregion
4146
- //#region src/components/code/code.tsx
4147
- function Code({ children, className = "" }) {
4148
- return /* @__PURE__ */ jsx("code", {
4149
- className: `font-mono text-xs bg-login-700 text-login px-1.5 py-0.5 rounded ${className}`,
4150
- children
4151
- });
4152
- }
4153
- function CodeBlock({ code, language, className = "" }) {
4154
- const [copied, setCopied] = useState(false);
4155
- function copy() {
4156
- navigator.clipboard.writeText(code);
4157
- setCopied(true);
4158
- setTimeout(() => setCopied(false), 2e3);
4159
- }
4160
- return /* @__PURE__ */ jsxs("div", {
4161
- className: `relative group rounded-xl border border-login-500/30 bg-login-900 overflow-hidden ${className}`,
4162
- children: [/* @__PURE__ */ jsxs("div", {
4163
- className: "flex items-center justify-between px-4 py-2 border-b border-login-500/20 bg-login-800",
4164
- children: [/* @__PURE__ */ jsx("span", {
4165
- className: "text-xs font-mono text-login-400",
4166
- children: language ?? ""
4167
- }), /* @__PURE__ */ jsxs("button", {
4168
- type: "button",
4169
- onClick: copy,
4170
- className: "flex cursor-pointer items-center gap-1.5 text-xs text-login-400 hover:text-login-100 transition-colors",
4171
- children: [copied ? /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5 stroke-emerald-400" }) : /* @__PURE__ */ jsx(Copy, { className: "w-3.5 h-3.5" }), copied ? "Copied" : "Copy"]
4172
- })]
4173
- }), /* @__PURE__ */ jsx("pre", {
4174
- className: "overflow-x-auto p-4 text-xs font-mono leading-relaxed text-login-100",
4175
- children: /* @__PURE__ */ jsx("code", { children: code })
4176
- })]
4177
- });
4178
- }
4179
- //#endregion
1
+ import MarkdownRender from "../../components/markdownrender/markdownRender.js";
2
+ import Input from "../../components/inputs/input.js";
3
+ import SearchInput from "../../components/inputs/searchInput.js";
4
+ import Textarea from "../../components/inputs/textarea.js";
5
+ import Checkbox from "../../components/inputs/checkbox.js";
6
+ import Select from "../../components/inputs/select.js";
7
+ import TagInput from "../../components/inputs/tagInput.js";
8
+ import MultiSelect from "../../components/inputs/multiSelect.js";
9
+ import Switch from "../../components/inputs/switch.js";
10
+ import Radio from "../../components/inputs/radio.js";
11
+ import Range from "../../components/inputs/range.js";
12
+ import Logo from "../../components/logo/logo.js";
13
+ import LogoSmall from "../../components/logo/logoSmall.js";
14
+ import ThemeToggle from "../../components/toggle/theme.js";
15
+ import LanguageToggle from "../../components/toggle/language.js";
16
+ import Navbar from "../../components/navbar/navbar.js";
17
+ import NavItem from "../../components/navbar/navbarItem.js";
18
+ import NavDropdown from "../../components/navbar/navbarDropdown.js";
19
+ import VersionTag from "../../components/version/version.js";
20
+ import Footer from "../../components/footer/footer.js";
21
+ import { loginAddress, loginCopyright, loginEmail, loginSocialLinks, loginSponsor } from "../../components/footer/loginContent.js";
22
+ import PageContainer from "../../components/container/page.js";
23
+ import Highlight from "../../components/container/highlight.js";
24
+ import LeftBarPanel from "../../components/container/leftBarPanel.js";
25
+ import Card from "../../components/container/card.js";
26
+ import IconBubble from "../../components/container/iconBubble.js";
27
+ import StatCard from "../../components/container/statCard.js";
28
+ import { TabPanel, Tabs } from "../../components/container/tabs.js";
29
+ import Accordion, { AccordionGroup } from "../../components/container/accordion.js";
30
+ import PulseDot from "../../components/container/pulseDot.js";
31
+ import LoginPage from "../../components/login/loginPage.js";
32
+ import Toaster, { toast } from "../../components/toast/toaster.js";
33
+ import Button from "../../components/buttons/button.js";
34
+ import Alert from "../../components/alert/alert.js";
35
+ import { MenuButton } from "../../components/table/menu.js";
36
+ import Pagination from "../../components/table/pagination.js";
37
+ import { Table } from "../../components/table/table.js";
38
+ import ConfirmPopup from "../../components/confirm/confirmPopup.js";
39
+ import SeverityPill from "../../components/vulnerability/severityPill.js";
40
+ import Toggle from "../../components/inputs/toggle.js";
41
+ import FileInput from "../../components/inputs/fileInput.js";
42
+ import GlassCard from "../../components/container/glassCard.js";
43
+ import ExpandableCard from "../../components/container/expandableCard.js";
44
+ import Modal from "../../components/modal/modal.js";
45
+ import Sidebar from "../../components/sidebar/sidebar.js";
46
+ import Badge from "../../components/badge/badge.js";
47
+ import EmptyState from "../../components/empty/emptyState.js";
48
+ import Spinner from "../../components/spinner/spinner.js";
49
+ import { Code, CodeBlock } from "../../components/code/code.js";
4180
50
  export { Accordion, AccordionGroup, Alert, Badge, Button, Card, Checkbox, Code, CodeBlock, ConfirmPopup, EmptyState, ExpandableCard, FileInput, Footer, GlassCard, Highlight, IconBubble, Input, LanguageToggle, LeftBarPanel, LoginPage, Logo, LogoSmall, MarkdownRender, MenuButton, Modal, MultiSelect, NavDropdown, NavItem, Navbar, PageContainer, Pagination, PulseDot, Radio, Range, SearchInput, Select, SeverityPill, Sidebar, Spinner, StatCard, Switch, TabPanel, Table, Tabs, TagInput, Textarea, ThemeToggle, Toaster, Toggle, VersionTag, loginAddress, loginCopyright, loginEmail, loginSocialLinks, loginSponsor, toast };