@otmc/ui 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +636 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +130 -2
- package/dist/index.d.ts +130 -2
- package/dist/index.js +659 -4
- package/dist/index.js.map +1 -1
- package/package.json +63 -60
package/dist/index.cjs
CHANGED
|
@@ -20,17 +20,47 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
|
|
23
|
+
DEFAULT_AUTHOR: () => DEFAULT_AUTHOR,
|
|
24
|
+
DEFAULT_AUTHOR_HREF: () => DEFAULT_AUTHOR_HREF,
|
|
25
|
+
DEFAULT_COPYRIGHT: () => DEFAULT_COPYRIGHT,
|
|
26
|
+
DEFAULT_LICENSE: () => DEFAULT_LICENSE,
|
|
27
|
+
DEFAULT_LOCATION: () => DEFAULT_LOCATION,
|
|
28
|
+
DEFAULT_VERSION_TYPE: () => DEFAULT_VERSION_TYPE,
|
|
29
|
+
Footer: () => Footer,
|
|
30
|
+
InformationContent: () => InformationContent,
|
|
31
|
+
InformationModal: () => InformationModal,
|
|
32
|
+
NotFound: () => NotFound,
|
|
33
|
+
ThemeMenu: () => ThemeMenu,
|
|
34
|
+
ThemeProvider: () => ThemeProvider,
|
|
35
|
+
UNKNOWN: () => UNKNOWN,
|
|
36
|
+
calculateRemainingTime: () => calculateRemainingTime,
|
|
37
|
+
copyToClipboard: () => copyToClipboard,
|
|
38
|
+
formatAbsolute: () => formatAbsolute,
|
|
39
|
+
formatAbsoluteAndRelativeTime: () => formatAbsoluteAndRelativeTime,
|
|
40
|
+
formatHumanDate: () => formatHumanDate,
|
|
41
|
+
formatRelativeTime: () => formatRelativeTime,
|
|
42
|
+
normalizeDate: () => normalizeDate,
|
|
43
|
+
pad: () => pad,
|
|
44
|
+
resolveColorScheme: () => resolveColorScheme,
|
|
45
|
+
useTheme: () => useTheme
|
|
24
46
|
});
|
|
25
47
|
module.exports = __toCommonJS(index_exports);
|
|
26
48
|
|
|
27
49
|
// src/branding/Footer.tsx
|
|
28
50
|
var import_core = require("@mantine/core");
|
|
29
51
|
var import_icons_react = require("@tabler/icons-react");
|
|
30
|
-
|
|
31
|
-
|
|
52
|
+
|
|
53
|
+
// src/utils/constants.ts
|
|
32
54
|
var DEFAULT_AUTHOR = "Nguyen Van Trung, OTMC Contributors.";
|
|
33
|
-
var DEFAULT_AUTHOR_HREF = "https://github.com";
|
|
55
|
+
var DEFAULT_AUTHOR_HREF = "https://github.com/otmc-sw";
|
|
56
|
+
var DEFAULT_COPYRIGHT = "OTMC Softwares. All rights reserved.";
|
|
57
|
+
var DEFAULT_LICENSE = "OTMC License.";
|
|
58
|
+
var DEFAULT_LOCATION = "An Nhon, Gia Lai, Viet Nam.";
|
|
59
|
+
var DEFAULT_VERSION_TYPE = "Internal";
|
|
60
|
+
var UNKNOWN = "Unknown";
|
|
61
|
+
|
|
62
|
+
// src/branding/Footer.tsx
|
|
63
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
34
64
|
var DEFAULT_SOCIAL_LINKS = [
|
|
35
65
|
{
|
|
36
66
|
label: "Facebook",
|
|
@@ -111,8 +141,609 @@ function Footer({
|
|
|
111
141
|
) }, link.href)) })
|
|
112
142
|
] });
|
|
113
143
|
}
|
|
144
|
+
|
|
145
|
+
// src/components/ThemeMenu.tsx
|
|
146
|
+
var import_core3 = require("@mantine/core");
|
|
147
|
+
var import_lucide_react = require("lucide-react");
|
|
148
|
+
|
|
149
|
+
// src/contexts/ThemeProvider.tsx
|
|
150
|
+
var import_react = require("react");
|
|
151
|
+
var import_core2 = require("@mantine/core");
|
|
152
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
153
|
+
var ThemeContext = (0, import_react.createContext)(null);
|
|
154
|
+
var useTheme = () => {
|
|
155
|
+
const ctx = (0, import_react.useContext)(ThemeContext);
|
|
156
|
+
if (!ctx) {
|
|
157
|
+
throw new Error("useTheme must be used inside ThemeProvider");
|
|
158
|
+
}
|
|
159
|
+
return ctx;
|
|
160
|
+
};
|
|
161
|
+
var resolveColorScheme = (colorScheme) => {
|
|
162
|
+
if (colorScheme === "auto") {
|
|
163
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
164
|
+
}
|
|
165
|
+
return colorScheme;
|
|
166
|
+
};
|
|
167
|
+
var resolveTimeBasedTheme = (settings) => {
|
|
168
|
+
const now = /* @__PURE__ */ new Date();
|
|
169
|
+
const minutes = now.getHours() * 60 + now.getMinutes();
|
|
170
|
+
const [lh, lm] = settings.lightStartTime.split(":").map(Number);
|
|
171
|
+
const [dh, dm] = settings.darkStartTime.split(":").map(Number);
|
|
172
|
+
const light = lh * 60 + lm;
|
|
173
|
+
const dark = dh * 60 + dm;
|
|
174
|
+
return light < dark ? minutes >= light && minutes < dark ? "light" : "dark" : minutes >= light || minutes < dark ? "light" : "dark";
|
|
175
|
+
};
|
|
176
|
+
var resolveAutoScheme = () => window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
177
|
+
var ThemeProvider = ({
|
|
178
|
+
children,
|
|
179
|
+
defaultTheme = "auto",
|
|
180
|
+
defaultTimeBasedSettings = {
|
|
181
|
+
lightStartTime: "07:00",
|
|
182
|
+
darkStartTime: "19:00"
|
|
183
|
+
},
|
|
184
|
+
storagePrefix = ""
|
|
185
|
+
}) => {
|
|
186
|
+
const themeStorageKey = `${storagePrefix}theme`;
|
|
187
|
+
const timeStorageKey = `${storagePrefix}time-theme`;
|
|
188
|
+
const { colorScheme, setColorScheme } = (0, import_core2.useMantineColorScheme)();
|
|
189
|
+
const [theme, setThemeState] = (0, import_react.useState)(
|
|
190
|
+
() => localStorage.getItem(themeStorageKey) ?? defaultTheme
|
|
191
|
+
);
|
|
192
|
+
const [timeBasedSettings, setTimeBasedSettings] = (0, import_react.useState)(
|
|
193
|
+
() => JSON.parse(localStorage.getItem(timeStorageKey) || "null") ?? defaultTimeBasedSettings
|
|
194
|
+
);
|
|
195
|
+
const handleSetTimeBasedSettings = (settings) => {
|
|
196
|
+
setTimeBasedSettings(settings);
|
|
197
|
+
localStorage.setItem(timeStorageKey, JSON.stringify(settings));
|
|
198
|
+
if (theme === "time-based") {
|
|
199
|
+
applyTheme("time-based");
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
const applyTheme = (mode) => {
|
|
203
|
+
let scheme;
|
|
204
|
+
switch (mode) {
|
|
205
|
+
case "light":
|
|
206
|
+
case "dark":
|
|
207
|
+
case "auto":
|
|
208
|
+
scheme = mode;
|
|
209
|
+
break;
|
|
210
|
+
case "time-based":
|
|
211
|
+
scheme = resolveTimeBasedTheme(timeBasedSettings);
|
|
212
|
+
break;
|
|
213
|
+
default:
|
|
214
|
+
scheme = "auto";
|
|
215
|
+
}
|
|
216
|
+
setColorScheme(scheme);
|
|
217
|
+
};
|
|
218
|
+
(0, import_react.useEffect)(() => {
|
|
219
|
+
applyTheme(theme);
|
|
220
|
+
}, [theme, timeBasedSettings]);
|
|
221
|
+
const setTheme = (mode) => {
|
|
222
|
+
setThemeState(mode);
|
|
223
|
+
localStorage.setItem(themeStorageKey, mode);
|
|
224
|
+
applyTheme(mode);
|
|
225
|
+
};
|
|
226
|
+
const toggleTheme = () => {
|
|
227
|
+
setTheme(colorScheme === "dark" ? "light" : "dark");
|
|
228
|
+
};
|
|
229
|
+
const currentTheme = theme === "time-based" ? resolveTimeBasedTheme(timeBasedSettings) : colorScheme === "auto" ? resolveAutoScheme() : colorScheme;
|
|
230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
231
|
+
ThemeContext.Provider,
|
|
232
|
+
{
|
|
233
|
+
value: {
|
|
234
|
+
theme,
|
|
235
|
+
currentTheme,
|
|
236
|
+
setTheme,
|
|
237
|
+
toggleTheme,
|
|
238
|
+
timeBasedSettings,
|
|
239
|
+
setTimeBasedSettings: handleSetTimeBasedSettings
|
|
240
|
+
},
|
|
241
|
+
children
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// src/components/ThemeMenu.tsx
|
|
247
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
248
|
+
var DEFAULT_LABELS = {
|
|
249
|
+
tooltip: "Ch\u1EBF \u0111\u1ED9 giao di\u1EC7n",
|
|
250
|
+
title: "Ch\u1EBF \u0111\u1ED9 giao di\u1EC7n",
|
|
251
|
+
light: "S\xE1ng",
|
|
252
|
+
dark: "T\u1ED1i",
|
|
253
|
+
auto: "Theo h\u1EC7 th\u1ED1ng",
|
|
254
|
+
timeBased: "Theo th\u1EDDi gian"
|
|
255
|
+
};
|
|
256
|
+
var MODE_ICONS = {
|
|
257
|
+
light: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Sun, { size: 16 }),
|
|
258
|
+
dark: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Moon, { size: 16 }),
|
|
259
|
+
auto: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Monitor, { size: 16 }),
|
|
260
|
+
"time-based": /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Clock, { size: 16 })
|
|
261
|
+
};
|
|
262
|
+
function ThemeMenu({
|
|
263
|
+
modes = ["light", "dark", "auto", "time-based"],
|
|
264
|
+
labels = {},
|
|
265
|
+
iconSize = 20,
|
|
266
|
+
size = "lg",
|
|
267
|
+
menuProps = {}
|
|
268
|
+
}) {
|
|
269
|
+
const { theme, currentTheme, setTheme } = useTheme();
|
|
270
|
+
const text = { ...DEFAULT_LABELS, ...labels };
|
|
271
|
+
const isDark = currentTheme === "dark";
|
|
272
|
+
const activeColor = isDark ? "yellow.8" : "blue.8";
|
|
273
|
+
const triggerIcon = theme === "light" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Sun, { size: iconSize, strokeWidth: 2 }) : theme === "dark" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Moon, { size: iconSize, strokeWidth: 2 }) : theme === "auto" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Monitor, { size: iconSize, strokeWidth: 2 }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Clock, { size: iconSize, strokeWidth: 2 });
|
|
274
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_core3.Menu, { shadow: "md", width: 200, position: "bottom-end", ...menuProps, children: [
|
|
275
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core3.Menu.Target, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core3.Tooltip, { label: text.tooltip, position: "bottom", withArrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
276
|
+
import_core3.ActionIcon,
|
|
277
|
+
{
|
|
278
|
+
variant: "subtle",
|
|
279
|
+
color: activeColor,
|
|
280
|
+
size,
|
|
281
|
+
radius: "lg",
|
|
282
|
+
style: {
|
|
283
|
+
boxShadow: isDark ? "0 0 15px rgba(250, 176, 5, 0.2)" : "0 0 15px rgba(34, 139, 230, 0.2)"
|
|
284
|
+
},
|
|
285
|
+
children: triggerIcon
|
|
286
|
+
}
|
|
287
|
+
) }) }),
|
|
288
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_core3.Menu.Dropdown, { style: { borderRadius: "11px" }, children: [
|
|
289
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core3.Menu.Label, { children: text.title }),
|
|
290
|
+
modes.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
291
|
+
import_core3.Menu.Item,
|
|
292
|
+
{
|
|
293
|
+
leftSection: MODE_ICONS[mode],
|
|
294
|
+
onClick: () => setTheme(mode),
|
|
295
|
+
color: theme === mode ? activeColor : void 0,
|
|
296
|
+
fw: theme === mode ? 700 : 400,
|
|
297
|
+
children: text[mode === "time-based" ? "timeBased" : mode]
|
|
298
|
+
},
|
|
299
|
+
mode
|
|
300
|
+
))
|
|
301
|
+
] })
|
|
302
|
+
] });
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// src/modals/Information.tsx
|
|
306
|
+
var import_react2 = require("react");
|
|
307
|
+
var import_core4 = require("@mantine/core");
|
|
308
|
+
var import_icons_react2 = require("@tabler/icons-react");
|
|
309
|
+
|
|
310
|
+
// src/utils/commonUtils.ts
|
|
311
|
+
var copyToClipboard = async (text) => {
|
|
312
|
+
try {
|
|
313
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
314
|
+
await navigator.clipboard.writeText(text);
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
const textarea = document.createElement("textarea");
|
|
318
|
+
textarea.value = text;
|
|
319
|
+
textarea.style.position = "fixed";
|
|
320
|
+
textarea.style.left = "-9999px";
|
|
321
|
+
textarea.style.top = "-9999px";
|
|
322
|
+
textarea.style.opacity = "0";
|
|
323
|
+
document.body.appendChild(textarea);
|
|
324
|
+
textarea.focus();
|
|
325
|
+
textarea.select();
|
|
326
|
+
const success = document.execCommand("copy");
|
|
327
|
+
document.body.removeChild(textarea);
|
|
328
|
+
return success;
|
|
329
|
+
} catch (err) {
|
|
330
|
+
console.error("Failed to copy to clipboard:", err);
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// src/utils/timeUtils.ts
|
|
336
|
+
function normalizeDate(dateInput) {
|
|
337
|
+
if (dateInput instanceof Date) {
|
|
338
|
+
return isNaN(dateInput.getTime()) ? null : dateInput;
|
|
339
|
+
}
|
|
340
|
+
if (typeof dateInput === "string") {
|
|
341
|
+
const date = new Date(dateInput);
|
|
342
|
+
return isNaN(date.getTime()) ? null : date;
|
|
343
|
+
}
|
|
344
|
+
if (typeof dateInput === "number") {
|
|
345
|
+
const timestamp = dateInput < 1e12 ? dateInput * 1e3 : dateInput;
|
|
346
|
+
const date = new Date(timestamp);
|
|
347
|
+
return isNaN(date.getTime()) ? null : date;
|
|
348
|
+
}
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
function pad(n, width = 2) {
|
|
352
|
+
return String(n).padStart(width, "0");
|
|
353
|
+
}
|
|
354
|
+
function formatAbsolute(date) {
|
|
355
|
+
const tz = -date.getTimezoneOffset();
|
|
356
|
+
const sign = tz >= 0 ? "+" : "-";
|
|
357
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())} ${sign}${pad(Math.floor(Math.abs(tz) / 60))}:${pad(Math.abs(tz) % 60)}`;
|
|
358
|
+
}
|
|
359
|
+
function formatRelativeTime(date) {
|
|
360
|
+
const normalizedDate = normalizeDate(date);
|
|
361
|
+
if (!normalizedDate) return "Invalid date";
|
|
362
|
+
const now = Date.now();
|
|
363
|
+
const diffMs = now - normalizedDate.getTime();
|
|
364
|
+
const diffSeconds = Math.floor(diffMs / 1e3);
|
|
365
|
+
if (diffSeconds < 0) {
|
|
366
|
+
return "Just now";
|
|
367
|
+
}
|
|
368
|
+
if (diffSeconds < 60) {
|
|
369
|
+
return "Just now";
|
|
370
|
+
}
|
|
371
|
+
const minute = 60;
|
|
372
|
+
const hour = minute * 60;
|
|
373
|
+
const day = hour * 24;
|
|
374
|
+
const week = day * 7;
|
|
375
|
+
const month = day * 30;
|
|
376
|
+
const year = day * 365;
|
|
377
|
+
if (diffSeconds < hour) {
|
|
378
|
+
const mins = Math.floor(diffSeconds / minute);
|
|
379
|
+
return `${mins} min${mins !== 1 ? "s" : ""} ago`;
|
|
380
|
+
} else if (diffSeconds < day) {
|
|
381
|
+
const hours = Math.floor(diffSeconds / hour);
|
|
382
|
+
return `${hours} hour${hours !== 1 ? "s" : ""} ago`;
|
|
383
|
+
} else if (diffSeconds < week) {
|
|
384
|
+
const days = Math.floor(diffSeconds / day);
|
|
385
|
+
return `${days} day${days !== 1 ? "s" : ""} ago`;
|
|
386
|
+
} else if (diffSeconds < month) {
|
|
387
|
+
const weeks = Math.floor(diffSeconds / week);
|
|
388
|
+
return `${weeks} week${weeks !== 1 ? "s" : ""} ago`;
|
|
389
|
+
} else if (diffSeconds < year) {
|
|
390
|
+
const months = Math.floor(diffSeconds / month);
|
|
391
|
+
return `${months} month${months !== 1 ? "s" : ""} ago`;
|
|
392
|
+
} else {
|
|
393
|
+
const years = Math.floor(diffSeconds / year);
|
|
394
|
+
return `${years} year${years !== 1 ? "s" : ""} ago`;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function formatAbsoluteAndRelativeTime(date) {
|
|
398
|
+
const normalizedDate = normalizeDate(date);
|
|
399
|
+
if (!normalizedDate) return "Invalid date";
|
|
400
|
+
const absoluteTime = formatAbsolute(normalizedDate);
|
|
401
|
+
const relativeTime = formatRelativeTime(normalizedDate);
|
|
402
|
+
return `${absoluteTime} (${relativeTime})`;
|
|
403
|
+
}
|
|
404
|
+
function calculateRemainingTime(targetDate) {
|
|
405
|
+
if (!targetDate) return "Not set";
|
|
406
|
+
const normalizedDate = normalizeDate(targetDate);
|
|
407
|
+
if (!normalizedDate) return "Invalid date";
|
|
408
|
+
const now = /* @__PURE__ */ new Date();
|
|
409
|
+
const diffMs = normalizedDate.getTime() - now.getTime();
|
|
410
|
+
if (diffMs < 0) {
|
|
411
|
+
const daysOverdue = Math.floor(Math.abs(diffMs) / (1e3 * 60 * 60 * 24));
|
|
412
|
+
return `Overdue ${daysOverdue}d`;
|
|
413
|
+
}
|
|
414
|
+
const days = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
415
|
+
const hours = Math.floor(diffMs % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
|
|
416
|
+
if (days > 0) {
|
|
417
|
+
return `${days}d ${hours}h`;
|
|
418
|
+
} else if (hours > 0) {
|
|
419
|
+
return `${hours}h`;
|
|
420
|
+
} else {
|
|
421
|
+
return "< 1h";
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
var MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
425
|
+
function formatHumanDate(date, options) {
|
|
426
|
+
const normalizedDate = normalizeDate(date);
|
|
427
|
+
if (!normalizedDate) return "Invalid date";
|
|
428
|
+
const month = MONTH_NAMES[normalizedDate.getMonth()];
|
|
429
|
+
const day = normalizedDate.getDate();
|
|
430
|
+
const year = normalizedDate.getFullYear();
|
|
431
|
+
if (!options?.showTime) {
|
|
432
|
+
return `${month} ${day}, ${year}`;
|
|
433
|
+
}
|
|
434
|
+
const hours = normalizedDate.getHours();
|
|
435
|
+
const minutes = normalizedDate.getMinutes();
|
|
436
|
+
const seconds = normalizedDate.getSeconds();
|
|
437
|
+
const ampm = hours >= 12 ? "PM" : "AM";
|
|
438
|
+
const hours12 = hours % 12 || 12;
|
|
439
|
+
let timeStr = `${hours12}:${pad(minutes)}`;
|
|
440
|
+
if (options.showSeconds) {
|
|
441
|
+
timeStr += `:${pad(seconds)}`;
|
|
442
|
+
}
|
|
443
|
+
timeStr += ` ${ampm}`;
|
|
444
|
+
return `${month} ${day}, ${year} ${timeStr}`;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// src/modals/Information.tsx
|
|
448
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
449
|
+
var DEFAULT_TITLE = /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core4.Group, { gap: "xs", wrap: "nowrap", children: [
|
|
450
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons_react2.IconCpu, { size: 20 }),
|
|
451
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "System Information" })
|
|
452
|
+
] });
|
|
453
|
+
function InformationContent({ info }) {
|
|
454
|
+
const colorScheme = (0, import_core4.useComputedColorScheme)();
|
|
455
|
+
const author = info.author ?? DEFAULT_AUTHOR;
|
|
456
|
+
const versionType = info.versionType ?? DEFAULT_VERSION_TYPE;
|
|
457
|
+
const cards = [
|
|
458
|
+
{
|
|
459
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons_react2.IconUser, { size: 18 }),
|
|
460
|
+
label: "Author",
|
|
461
|
+
value: author,
|
|
462
|
+
color: "blue"
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons_react2.IconLicense, { size: 18 }),
|
|
466
|
+
label: "License",
|
|
467
|
+
value: info.license ?? DEFAULT_LICENSE,
|
|
468
|
+
color: "orange"
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons_react2.IconMapPin, { size: 18 }),
|
|
472
|
+
label: "Location",
|
|
473
|
+
value: info.location ?? DEFAULT_LOCATION,
|
|
474
|
+
color: "teal"
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons_react2.IconTag, { size: 18 }),
|
|
478
|
+
label: "Version Type",
|
|
479
|
+
value: versionType,
|
|
480
|
+
color: "red"
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons_react2.IconCalendar, { size: 18 }),
|
|
484
|
+
label: "Build Time",
|
|
485
|
+
value: info.buildTime !== void 0 ? formatAbsoluteAndRelativeTime(info.buildTime) : UNKNOWN,
|
|
486
|
+
color: "green"
|
|
487
|
+
},
|
|
488
|
+
...info.metadata ?? []
|
|
489
|
+
];
|
|
490
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core4.Stack, { gap: "lg", children: [
|
|
491
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core4.Stack, { gap: "xs", align: "center", children: [
|
|
492
|
+
info.logo,
|
|
493
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core4.Stack, { gap: 2, align: "center", children: [
|
|
494
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core4.Title, { order: 2, children: info.name }),
|
|
495
|
+
info.tagline && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core4.Text, { size: "sm", c: "dimmed", w: 600, ta: "center", children: info.tagline })
|
|
496
|
+
] }),
|
|
497
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core4.Group, { gap: "xs", children: [
|
|
498
|
+
info.version && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
499
|
+
import_core4.Badge,
|
|
500
|
+
{
|
|
501
|
+
size: "lg",
|
|
502
|
+
color: "blue",
|
|
503
|
+
variant: "outline",
|
|
504
|
+
mt: "sm",
|
|
505
|
+
tt: "none",
|
|
506
|
+
fw: 600,
|
|
507
|
+
children: [
|
|
508
|
+
"\u2728 v",
|
|
509
|
+
info.version
|
|
510
|
+
]
|
|
511
|
+
}
|
|
512
|
+
),
|
|
513
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
514
|
+
import_core4.Badge,
|
|
515
|
+
{
|
|
516
|
+
size: "lg",
|
|
517
|
+
color: "teal",
|
|
518
|
+
variant: "light",
|
|
519
|
+
mt: "sm",
|
|
520
|
+
tt: "none",
|
|
521
|
+
fw: 600,
|
|
522
|
+
children: [
|
|
523
|
+
"\u{1F9E9} ",
|
|
524
|
+
versionType
|
|
525
|
+
]
|
|
526
|
+
}
|
|
527
|
+
)
|
|
528
|
+
] })
|
|
529
|
+
] }),
|
|
530
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core4.Divider, { label: "System Information", labelPosition: "center" }),
|
|
531
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core4.SimpleGrid, { cols: { base: 1, sm: 2 }, children: [
|
|
532
|
+
cards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
533
|
+
InfoCard,
|
|
534
|
+
{
|
|
535
|
+
icon: card.icon ?? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons_react2.IconAward, { size: 18 }),
|
|
536
|
+
label: card.label,
|
|
537
|
+
value: card.value,
|
|
538
|
+
color: card.color ?? "gray"
|
|
539
|
+
},
|
|
540
|
+
card.label
|
|
541
|
+
)),
|
|
542
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
543
|
+
import_core4.Paper,
|
|
544
|
+
{
|
|
545
|
+
withBorder: true,
|
|
546
|
+
p: "sm",
|
|
547
|
+
radius: "18px",
|
|
548
|
+
bg: colorScheme === "dark" ? "gray.9" : "gray.0",
|
|
549
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core4.Group, { justify: "space-between", wrap: "nowrap", children: [
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core4.Group, { gap: "sm", flex: 1, children: [
|
|
551
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core4.ThemeIcon, { variant: "light", color: "yellow", size: "lg", radius: "14px", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons_react2.IconHash, { size: 18 }) }),
|
|
552
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core4.Stack, { gap: 2, children: [
|
|
553
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core4.Text, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: "Build ID" }),
|
|
554
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core4.Text, { size: "sm", fw: 500, truncate: true, children: info.buildId ?? UNKNOWN })
|
|
555
|
+
] })
|
|
556
|
+
] }),
|
|
557
|
+
info.buildId && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CopyBuildIdButton, { buildId: info.buildId })
|
|
558
|
+
] })
|
|
559
|
+
}
|
|
560
|
+
)
|
|
561
|
+
] }),
|
|
562
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
563
|
+
Footer,
|
|
564
|
+
{
|
|
565
|
+
copyright: info.copyright,
|
|
566
|
+
author,
|
|
567
|
+
authorHref: info.authorHref,
|
|
568
|
+
socialLinks: info.socialLinks
|
|
569
|
+
}
|
|
570
|
+
)
|
|
571
|
+
] });
|
|
572
|
+
}
|
|
573
|
+
function InformationModal({
|
|
574
|
+
opened,
|
|
575
|
+
onClose,
|
|
576
|
+
info,
|
|
577
|
+
title = DEFAULT_TITLE
|
|
578
|
+
}) {
|
|
579
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
580
|
+
import_core4.Modal,
|
|
581
|
+
{
|
|
582
|
+
opened,
|
|
583
|
+
onClose,
|
|
584
|
+
withCloseButton: true,
|
|
585
|
+
centered: true,
|
|
586
|
+
radius: "lg",
|
|
587
|
+
size: "60%",
|
|
588
|
+
styles: {
|
|
589
|
+
content: {
|
|
590
|
+
maxHeight: "90vh",
|
|
591
|
+
height: "90vh"
|
|
592
|
+
},
|
|
593
|
+
body: {
|
|
594
|
+
flex: 1,
|
|
595
|
+
overflow: "auto"
|
|
596
|
+
}
|
|
597
|
+
},
|
|
598
|
+
title,
|
|
599
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(InformationContent, { info })
|
|
600
|
+
}
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
function CopyBuildIdButton({ buildId }) {
|
|
604
|
+
const [copied, setCopied] = (0, import_react2.useState)(false);
|
|
605
|
+
const handleCopy = async () => {
|
|
606
|
+
const success = await copyToClipboard(buildId);
|
|
607
|
+
if (success) {
|
|
608
|
+
setCopied(true);
|
|
609
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core4.Tooltip, { label: copied ? "Copied!" : "Copy ID", withArrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
613
|
+
import_core4.ActionIcon,
|
|
614
|
+
{
|
|
615
|
+
variant: "subtle",
|
|
616
|
+
color: copied ? "teal" : "gray",
|
|
617
|
+
onClick: handleCopy,
|
|
618
|
+
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons_react2.IconCheck, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons_react2.IconCopy, { size: 16 })
|
|
619
|
+
}
|
|
620
|
+
) });
|
|
621
|
+
}
|
|
622
|
+
function InfoCard({
|
|
623
|
+
icon,
|
|
624
|
+
label,
|
|
625
|
+
value,
|
|
626
|
+
color
|
|
627
|
+
}) {
|
|
628
|
+
const colorScheme = (0, import_core4.useComputedColorScheme)();
|
|
629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core4.Paper, { withBorder: true, p: "md", radius: "18px", h: "100%", bg: colorScheme === "dark" ? "gray.9" : "gray.0", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core4.Group, { gap: "sm", align: "flex-start", children: [
|
|
630
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core4.ThemeIcon, { color, variant: "light", size: "lg", radius: "14px", children: icon }),
|
|
631
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core4.Stack, { gap: 2, flex: 1, children: [
|
|
632
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core4.Text, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: label }),
|
|
633
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core4.Text, { size: "sm", fw: 500, lineClamp: 1, children: value })
|
|
634
|
+
] })
|
|
635
|
+
] }) });
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// src/pages/NotFound.tsx
|
|
639
|
+
var import_core5 = require("@mantine/core");
|
|
640
|
+
var import_icons_react3 = require("@tabler/icons-react");
|
|
641
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
642
|
+
function NotFound({
|
|
643
|
+
path,
|
|
644
|
+
onSearchClick,
|
|
645
|
+
onHomeClick
|
|
646
|
+
}) {
|
|
647
|
+
const currentPath = path || (typeof window !== "undefined" ? window.location.pathname : "/404");
|
|
648
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
649
|
+
import_core5.Box,
|
|
650
|
+
{
|
|
651
|
+
style: {
|
|
652
|
+
minHeight: "100vh",
|
|
653
|
+
display: "flex",
|
|
654
|
+
alignItems: "center",
|
|
655
|
+
background: "radial-gradient(circle at top left, rgba(34, 139, 230, 0.15), transparent 45%), radial-gradient(circle at bottom right, rgba(34, 211, 238, 0.12), transparent 45%), var(--mantine-color-body)"
|
|
656
|
+
},
|
|
657
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_core5.Container, { size: "xl", py: 80, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_core5.Paper, { radius: "xl", p: 48, withBorder: true, style: { borderColor: "var(--mantine-color-default-border)", textAlign: "center" }, children: [
|
|
658
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
659
|
+
import_core5.Box,
|
|
660
|
+
{
|
|
661
|
+
mx: "auto",
|
|
662
|
+
mb: "xl",
|
|
663
|
+
w: 96,
|
|
664
|
+
h: 96,
|
|
665
|
+
style: {
|
|
666
|
+
borderRadius: "50%",
|
|
667
|
+
display: "flex",
|
|
668
|
+
alignItems: "center",
|
|
669
|
+
justifyContent: "center",
|
|
670
|
+
background: "linear-gradient(135deg, var(--mantine-color-blue-6), var(--mantine-color-cyan-6))",
|
|
671
|
+
boxShadow: "0 12px 32px rgba(34, 139, 230, 0.35)"
|
|
672
|
+
},
|
|
673
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_icons_react3.IconFileOff, { size: 44, stroke: 1.5, color: "white" })
|
|
674
|
+
}
|
|
675
|
+
),
|
|
676
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
677
|
+
import_core5.Text,
|
|
678
|
+
{
|
|
679
|
+
fz: { base: 72, sm: 100 },
|
|
680
|
+
fw: 900,
|
|
681
|
+
lh: 1,
|
|
682
|
+
variant: "gradient",
|
|
683
|
+
gradient: { from: "blue.7", to: "cyan.5", deg: 45 },
|
|
684
|
+
children: "404"
|
|
685
|
+
}
|
|
686
|
+
),
|
|
687
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_core5.Badge, { variant: "light", color: "blue", size: "lg", mb: "xs", children: "NOT FOUND" }),
|
|
688
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_core5.Title, { order: 2, mt: "sm", mb: "xs", children: "Trang kh\xF4ng t\u1ED3n t\u1EA1i" }),
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_core5.Text, { c: "dimmed", size: "sm", maw: 440, mx: "auto", children: "Trang ho\u1EB7c \u0111\u01B0\u1EDDng d\u1EABn b\u1EA1n truy c\u1EADp kh\xF4ng t\u1ED3n t\u1EA1i ho\u1EB7c \u0111\xE3 \u0111\u01B0\u1EE3c di chuy\u1EC3n. Vui l\xF2ng ki\u1EC3m tra l\u1EA1i \u0111\u01B0\u1EDDng d\u1EABn ho\u1EB7c quay v\u1EC1 trang ch\u1EE7." }),
|
|
690
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_core5.Box, { mt: "lg", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_core5.Code, { color: "blue", variant: "light", px: "md", py: 6, children: currentPath }) }),
|
|
691
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_core5.Group, { gap: "sm", mt: "xl", justify: "center", children: [
|
|
692
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
693
|
+
import_core5.Button,
|
|
694
|
+
{
|
|
695
|
+
variant: "light",
|
|
696
|
+
leftSection: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_icons_react3.IconArrowLeft, { size: 16 }),
|
|
697
|
+
onClick: () => window.history.back(),
|
|
698
|
+
children: "Quay l\u1EA1i"
|
|
699
|
+
}
|
|
700
|
+
),
|
|
701
|
+
onSearchClick && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
702
|
+
import_core5.Button,
|
|
703
|
+
{
|
|
704
|
+
variant: "outline",
|
|
705
|
+
leftSection: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_icons_react3.IconSearch, { size: 16 }),
|
|
706
|
+
onClick: onSearchClick,
|
|
707
|
+
children: "T\xECm Docs"
|
|
708
|
+
}
|
|
709
|
+
),
|
|
710
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
711
|
+
import_core5.Button,
|
|
712
|
+
{
|
|
713
|
+
leftSection: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_icons_react3.IconHome, { size: 16 }),
|
|
714
|
+
onClick: onHomeClick || (() => window.location.href = "/"),
|
|
715
|
+
children: "Trang ch\u1EE7"
|
|
716
|
+
}
|
|
717
|
+
)
|
|
718
|
+
] })
|
|
719
|
+
] }) })
|
|
720
|
+
}
|
|
721
|
+
);
|
|
722
|
+
}
|
|
114
723
|
// Annotate the CommonJS export names for ESM import in node:
|
|
115
724
|
0 && (module.exports = {
|
|
116
|
-
|
|
725
|
+
DEFAULT_AUTHOR,
|
|
726
|
+
DEFAULT_AUTHOR_HREF,
|
|
727
|
+
DEFAULT_COPYRIGHT,
|
|
728
|
+
DEFAULT_LICENSE,
|
|
729
|
+
DEFAULT_LOCATION,
|
|
730
|
+
DEFAULT_VERSION_TYPE,
|
|
731
|
+
Footer,
|
|
732
|
+
InformationContent,
|
|
733
|
+
InformationModal,
|
|
734
|
+
NotFound,
|
|
735
|
+
ThemeMenu,
|
|
736
|
+
ThemeProvider,
|
|
737
|
+
UNKNOWN,
|
|
738
|
+
calculateRemainingTime,
|
|
739
|
+
copyToClipboard,
|
|
740
|
+
formatAbsolute,
|
|
741
|
+
formatAbsoluteAndRelativeTime,
|
|
742
|
+
formatHumanDate,
|
|
743
|
+
formatRelativeTime,
|
|
744
|
+
normalizeDate,
|
|
745
|
+
pad,
|
|
746
|
+
resolveColorScheme,
|
|
747
|
+
useTheme
|
|
117
748
|
});
|
|
118
749
|
//# sourceMappingURL=index.cjs.map
|