@otmc/ui 0.1.1 → 0.1.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.
- package/dist/index.cjs +380 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +72 -1
- package/dist/index.d.ts +72 -1
- package/dist/index.js +387 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,17 +20,42 @@ 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
|
+
UNKNOWN: () => UNKNOWN,
|
|
33
|
+
calculateRemainingTime: () => calculateRemainingTime,
|
|
34
|
+
copyToClipboard: () => copyToClipboard,
|
|
35
|
+
formatAbsolute: () => formatAbsolute,
|
|
36
|
+
formatAbsoluteAndRelativeTime: () => formatAbsoluteAndRelativeTime,
|
|
37
|
+
formatHumanDate: () => formatHumanDate,
|
|
38
|
+
formatRelativeTime: () => formatRelativeTime,
|
|
39
|
+
normalizeDate: () => normalizeDate,
|
|
40
|
+
pad: () => pad
|
|
24
41
|
});
|
|
25
42
|
module.exports = __toCommonJS(index_exports);
|
|
26
43
|
|
|
27
44
|
// src/branding/Footer.tsx
|
|
28
45
|
var import_core = require("@mantine/core");
|
|
29
46
|
var import_icons_react = require("@tabler/icons-react");
|
|
30
|
-
|
|
31
|
-
|
|
47
|
+
|
|
48
|
+
// src/utils/constants.ts
|
|
32
49
|
var DEFAULT_AUTHOR = "Nguyen Van Trung, OTMC Contributors.";
|
|
33
|
-
var DEFAULT_AUTHOR_HREF = "https://github.com";
|
|
50
|
+
var DEFAULT_AUTHOR_HREF = "https://github.com/otmc-sw";
|
|
51
|
+
var DEFAULT_COPYRIGHT = "OTMC Softwares. All rights reserved.";
|
|
52
|
+
var DEFAULT_LICENSE = "OTMC License.";
|
|
53
|
+
var DEFAULT_LOCATION = "An Nhon, Gia Lai, Viet Nam.";
|
|
54
|
+
var DEFAULT_VERSION_TYPE = "Internal";
|
|
55
|
+
var UNKNOWN = "Unknown";
|
|
56
|
+
|
|
57
|
+
// src/branding/Footer.tsx
|
|
58
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
34
59
|
var DEFAULT_SOCIAL_LINKS = [
|
|
35
60
|
{
|
|
36
61
|
label: "Facebook",
|
|
@@ -111,8 +136,358 @@ function Footer({
|
|
|
111
136
|
) }, link.href)) })
|
|
112
137
|
] });
|
|
113
138
|
}
|
|
139
|
+
|
|
140
|
+
// src/modals/Information.tsx
|
|
141
|
+
var import_react = require("react");
|
|
142
|
+
var import_core2 = require("@mantine/core");
|
|
143
|
+
var import_icons_react2 = require("@tabler/icons-react");
|
|
144
|
+
|
|
145
|
+
// src/utils/commonUtils.ts
|
|
146
|
+
var copyToClipboard = async (text) => {
|
|
147
|
+
try {
|
|
148
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
149
|
+
await navigator.clipboard.writeText(text);
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
const textarea = document.createElement("textarea");
|
|
153
|
+
textarea.value = text;
|
|
154
|
+
textarea.style.position = "fixed";
|
|
155
|
+
textarea.style.left = "-9999px";
|
|
156
|
+
textarea.style.top = "-9999px";
|
|
157
|
+
textarea.style.opacity = "0";
|
|
158
|
+
document.body.appendChild(textarea);
|
|
159
|
+
textarea.focus();
|
|
160
|
+
textarea.select();
|
|
161
|
+
const success = document.execCommand("copy");
|
|
162
|
+
document.body.removeChild(textarea);
|
|
163
|
+
return success;
|
|
164
|
+
} catch (err) {
|
|
165
|
+
console.error("Failed to copy to clipboard:", err);
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// src/utils/timeUtils.ts
|
|
171
|
+
function normalizeDate(dateInput) {
|
|
172
|
+
if (dateInput instanceof Date) {
|
|
173
|
+
return isNaN(dateInput.getTime()) ? null : dateInput;
|
|
174
|
+
}
|
|
175
|
+
if (typeof dateInput === "string") {
|
|
176
|
+
const date = new Date(dateInput);
|
|
177
|
+
return isNaN(date.getTime()) ? null : date;
|
|
178
|
+
}
|
|
179
|
+
if (typeof dateInput === "number") {
|
|
180
|
+
const timestamp = dateInput < 1e12 ? dateInput * 1e3 : dateInput;
|
|
181
|
+
const date = new Date(timestamp);
|
|
182
|
+
return isNaN(date.getTime()) ? null : date;
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
function pad(n, width = 2) {
|
|
187
|
+
return String(n).padStart(width, "0");
|
|
188
|
+
}
|
|
189
|
+
function formatAbsolute(date) {
|
|
190
|
+
const tz = -date.getTimezoneOffset();
|
|
191
|
+
const sign = tz >= 0 ? "+" : "-";
|
|
192
|
+
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)}`;
|
|
193
|
+
}
|
|
194
|
+
function formatRelativeTime(date) {
|
|
195
|
+
const normalizedDate = normalizeDate(date);
|
|
196
|
+
if (!normalizedDate) return "Invalid date";
|
|
197
|
+
const now = Date.now();
|
|
198
|
+
const diffMs = now - normalizedDate.getTime();
|
|
199
|
+
const diffSeconds = Math.floor(diffMs / 1e3);
|
|
200
|
+
if (diffSeconds < 0) {
|
|
201
|
+
return "Just now";
|
|
202
|
+
}
|
|
203
|
+
if (diffSeconds < 60) {
|
|
204
|
+
return "Just now";
|
|
205
|
+
}
|
|
206
|
+
const minute = 60;
|
|
207
|
+
const hour = minute * 60;
|
|
208
|
+
const day = hour * 24;
|
|
209
|
+
const week = day * 7;
|
|
210
|
+
const month = day * 30;
|
|
211
|
+
const year = day * 365;
|
|
212
|
+
if (diffSeconds < hour) {
|
|
213
|
+
const mins = Math.floor(diffSeconds / minute);
|
|
214
|
+
return `${mins} min${mins !== 1 ? "s" : ""} ago`;
|
|
215
|
+
} else if (diffSeconds < day) {
|
|
216
|
+
const hours = Math.floor(diffSeconds / hour);
|
|
217
|
+
return `${hours} hour${hours !== 1 ? "s" : ""} ago`;
|
|
218
|
+
} else if (diffSeconds < week) {
|
|
219
|
+
const days = Math.floor(diffSeconds / day);
|
|
220
|
+
return `${days} day${days !== 1 ? "s" : ""} ago`;
|
|
221
|
+
} else if (diffSeconds < month) {
|
|
222
|
+
const weeks = Math.floor(diffSeconds / week);
|
|
223
|
+
return `${weeks} week${weeks !== 1 ? "s" : ""} ago`;
|
|
224
|
+
} else if (diffSeconds < year) {
|
|
225
|
+
const months = Math.floor(diffSeconds / month);
|
|
226
|
+
return `${months} month${months !== 1 ? "s" : ""} ago`;
|
|
227
|
+
} else {
|
|
228
|
+
const years = Math.floor(diffSeconds / year);
|
|
229
|
+
return `${years} year${years !== 1 ? "s" : ""} ago`;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function formatAbsoluteAndRelativeTime(date) {
|
|
233
|
+
const normalizedDate = normalizeDate(date);
|
|
234
|
+
if (!normalizedDate) return "Invalid date";
|
|
235
|
+
const absoluteTime = formatAbsolute(normalizedDate);
|
|
236
|
+
const relativeTime = formatRelativeTime(normalizedDate);
|
|
237
|
+
return `${absoluteTime} (${relativeTime})`;
|
|
238
|
+
}
|
|
239
|
+
function calculateRemainingTime(targetDate) {
|
|
240
|
+
if (!targetDate) return "Not set";
|
|
241
|
+
const normalizedDate = normalizeDate(targetDate);
|
|
242
|
+
if (!normalizedDate) return "Invalid date";
|
|
243
|
+
const now = /* @__PURE__ */ new Date();
|
|
244
|
+
const diffMs = normalizedDate.getTime() - now.getTime();
|
|
245
|
+
if (diffMs < 0) {
|
|
246
|
+
const daysOverdue = Math.floor(Math.abs(diffMs) / (1e3 * 60 * 60 * 24));
|
|
247
|
+
return `Overdue ${daysOverdue}d`;
|
|
248
|
+
}
|
|
249
|
+
const days = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
250
|
+
const hours = Math.floor(diffMs % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
|
|
251
|
+
if (days > 0) {
|
|
252
|
+
return `${days}d ${hours}h`;
|
|
253
|
+
} else if (hours > 0) {
|
|
254
|
+
return `${hours}h`;
|
|
255
|
+
} else {
|
|
256
|
+
return "< 1h";
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
var MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
260
|
+
function formatHumanDate(date, options) {
|
|
261
|
+
const normalizedDate = normalizeDate(date);
|
|
262
|
+
if (!normalizedDate) return "Invalid date";
|
|
263
|
+
const month = MONTH_NAMES[normalizedDate.getMonth()];
|
|
264
|
+
const day = normalizedDate.getDate();
|
|
265
|
+
const year = normalizedDate.getFullYear();
|
|
266
|
+
if (!options?.showTime) {
|
|
267
|
+
return `${month} ${day}, ${year}`;
|
|
268
|
+
}
|
|
269
|
+
const hours = normalizedDate.getHours();
|
|
270
|
+
const minutes = normalizedDate.getMinutes();
|
|
271
|
+
const seconds = normalizedDate.getSeconds();
|
|
272
|
+
const ampm = hours >= 12 ? "PM" : "AM";
|
|
273
|
+
const hours12 = hours % 12 || 12;
|
|
274
|
+
let timeStr = `${hours12}:${pad(minutes)}`;
|
|
275
|
+
if (options.showSeconds) {
|
|
276
|
+
timeStr += `:${pad(seconds)}`;
|
|
277
|
+
}
|
|
278
|
+
timeStr += ` ${ampm}`;
|
|
279
|
+
return `${month} ${day}, ${year} ${timeStr}`;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/modals/Information.tsx
|
|
283
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
284
|
+
var DEFAULT_TITLE = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core2.Group, { gap: "xs", wrap: "nowrap", children: [
|
|
285
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons_react2.IconCpu, { size: 20 }),
|
|
286
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "System Information" })
|
|
287
|
+
] });
|
|
288
|
+
function InformationContent({ info }) {
|
|
289
|
+
const colorScheme = (0, import_core2.useComputedColorScheme)();
|
|
290
|
+
const author = info.author ?? DEFAULT_AUTHOR;
|
|
291
|
+
const versionType = info.versionType ?? DEFAULT_VERSION_TYPE;
|
|
292
|
+
const cards = [
|
|
293
|
+
{
|
|
294
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons_react2.IconUser, { size: 18 }),
|
|
295
|
+
label: "Author",
|
|
296
|
+
value: author,
|
|
297
|
+
color: "blue"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons_react2.IconLicense, { size: 18 }),
|
|
301
|
+
label: "License",
|
|
302
|
+
value: info.license ?? DEFAULT_LICENSE,
|
|
303
|
+
color: "orange"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons_react2.IconMapPin, { size: 18 }),
|
|
307
|
+
label: "Location",
|
|
308
|
+
value: info.location ?? DEFAULT_LOCATION,
|
|
309
|
+
color: "teal"
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons_react2.IconTag, { size: 18 }),
|
|
313
|
+
label: "Version Type",
|
|
314
|
+
value: versionType,
|
|
315
|
+
color: "red"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons_react2.IconCalendar, { size: 18 }),
|
|
319
|
+
label: "Build Time",
|
|
320
|
+
value: info.buildTime !== void 0 ? formatAbsoluteAndRelativeTime(info.buildTime) : UNKNOWN,
|
|
321
|
+
color: "green"
|
|
322
|
+
},
|
|
323
|
+
...info.metadata ?? []
|
|
324
|
+
];
|
|
325
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core2.Stack, { gap: "lg", children: [
|
|
326
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core2.Stack, { gap: "xs", align: "center", children: [
|
|
327
|
+
info.logo,
|
|
328
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core2.Stack, { gap: 2, align: "center", children: [
|
|
329
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core2.Title, { order: 2, children: info.name }),
|
|
330
|
+
info.tagline && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core2.Text, { size: "sm", c: "dimmed", w: 600, ta: "center", children: info.tagline })
|
|
331
|
+
] }),
|
|
332
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core2.Group, { gap: "xs", children: [
|
|
333
|
+
info.version && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
334
|
+
import_core2.Badge,
|
|
335
|
+
{
|
|
336
|
+
size: "lg",
|
|
337
|
+
color: "blue",
|
|
338
|
+
variant: "outline",
|
|
339
|
+
mt: "sm",
|
|
340
|
+
tt: "none",
|
|
341
|
+
fw: 600,
|
|
342
|
+
children: [
|
|
343
|
+
"\u2728 v",
|
|
344
|
+
info.version
|
|
345
|
+
]
|
|
346
|
+
}
|
|
347
|
+
),
|
|
348
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
349
|
+
import_core2.Badge,
|
|
350
|
+
{
|
|
351
|
+
size: "lg",
|
|
352
|
+
color: "teal",
|
|
353
|
+
variant: "light",
|
|
354
|
+
mt: "sm",
|
|
355
|
+
tt: "none",
|
|
356
|
+
fw: 600,
|
|
357
|
+
children: [
|
|
358
|
+
"\u{1F9E9} ",
|
|
359
|
+
versionType
|
|
360
|
+
]
|
|
361
|
+
}
|
|
362
|
+
)
|
|
363
|
+
] })
|
|
364
|
+
] }),
|
|
365
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core2.Divider, { label: "System Information", labelPosition: "center" }),
|
|
366
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core2.SimpleGrid, { cols: { base: 1, sm: 2 }, children: [
|
|
367
|
+
cards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
368
|
+
InfoCard,
|
|
369
|
+
{
|
|
370
|
+
icon: card.icon ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons_react2.IconAward, { size: 18 }),
|
|
371
|
+
label: card.label,
|
|
372
|
+
value: card.value,
|
|
373
|
+
color: card.color ?? "gray"
|
|
374
|
+
},
|
|
375
|
+
card.label
|
|
376
|
+
)),
|
|
377
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
378
|
+
import_core2.Paper,
|
|
379
|
+
{
|
|
380
|
+
withBorder: true,
|
|
381
|
+
p: "sm",
|
|
382
|
+
radius: "18px",
|
|
383
|
+
bg: colorScheme === "dark" ? "gray.9" : "gray.0",
|
|
384
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core2.Group, { justify: "space-between", wrap: "nowrap", children: [
|
|
385
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core2.Group, { gap: "sm", flex: 1, children: [
|
|
386
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core2.ThemeIcon, { variant: "light", color: "yellow", size: "lg", radius: "14px", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons_react2.IconHash, { size: 18 }) }),
|
|
387
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core2.Stack, { gap: 2, children: [
|
|
388
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core2.Text, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: "Build ID" }),
|
|
389
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core2.Text, { size: "sm", fw: 500, truncate: true, children: info.buildId ?? UNKNOWN })
|
|
390
|
+
] })
|
|
391
|
+
] }),
|
|
392
|
+
info.buildId && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CopyBuildIdButton, { buildId: info.buildId })
|
|
393
|
+
] })
|
|
394
|
+
}
|
|
395
|
+
)
|
|
396
|
+
] }),
|
|
397
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
398
|
+
Footer,
|
|
399
|
+
{
|
|
400
|
+
copyright: info.copyright,
|
|
401
|
+
author,
|
|
402
|
+
authorHref: info.authorHref,
|
|
403
|
+
socialLinks: info.socialLinks
|
|
404
|
+
}
|
|
405
|
+
)
|
|
406
|
+
] });
|
|
407
|
+
}
|
|
408
|
+
function InformationModal({
|
|
409
|
+
opened,
|
|
410
|
+
onClose,
|
|
411
|
+
info,
|
|
412
|
+
title = DEFAULT_TITLE
|
|
413
|
+
}) {
|
|
414
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
415
|
+
import_core2.Modal,
|
|
416
|
+
{
|
|
417
|
+
opened,
|
|
418
|
+
onClose,
|
|
419
|
+
withCloseButton: true,
|
|
420
|
+
centered: true,
|
|
421
|
+
radius: "lg",
|
|
422
|
+
size: "60%",
|
|
423
|
+
styles: {
|
|
424
|
+
content: {
|
|
425
|
+
maxHeight: "90vh",
|
|
426
|
+
height: "90vh"
|
|
427
|
+
},
|
|
428
|
+
body: {
|
|
429
|
+
flex: 1,
|
|
430
|
+
overflow: "auto"
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
title,
|
|
434
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(InformationContent, { info })
|
|
435
|
+
}
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
function CopyBuildIdButton({ buildId }) {
|
|
439
|
+
const [copied, setCopied] = (0, import_react.useState)(false);
|
|
440
|
+
const handleCopy = async () => {
|
|
441
|
+
const success = await copyToClipboard(buildId);
|
|
442
|
+
if (success) {
|
|
443
|
+
setCopied(true);
|
|
444
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core2.Tooltip, { label: copied ? "Copied!" : "Copy ID", withArrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
448
|
+
import_core2.ActionIcon,
|
|
449
|
+
{
|
|
450
|
+
variant: "subtle",
|
|
451
|
+
color: copied ? "teal" : "gray",
|
|
452
|
+
onClick: handleCopy,
|
|
453
|
+
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons_react2.IconCheck, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons_react2.IconCopy, { size: 16 })
|
|
454
|
+
}
|
|
455
|
+
) });
|
|
456
|
+
}
|
|
457
|
+
function InfoCard({
|
|
458
|
+
icon,
|
|
459
|
+
label,
|
|
460
|
+
value,
|
|
461
|
+
color
|
|
462
|
+
}) {
|
|
463
|
+
const colorScheme = (0, import_core2.useComputedColorScheme)();
|
|
464
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core2.Paper, { withBorder: true, p: "md", radius: "18px", h: "100%", bg: colorScheme === "dark" ? "gray.9" : "gray.0", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core2.Group, { gap: "sm", align: "flex-start", children: [
|
|
465
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core2.ThemeIcon, { color, variant: "light", size: "lg", radius: "14px", children: icon }),
|
|
466
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core2.Stack, { gap: 2, flex: 1, children: [
|
|
467
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core2.Text, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: label }),
|
|
468
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core2.Text, { size: "sm", fw: 500, lineClamp: 1, children: value })
|
|
469
|
+
] })
|
|
470
|
+
] }) });
|
|
471
|
+
}
|
|
114
472
|
// Annotate the CommonJS export names for ESM import in node:
|
|
115
473
|
0 && (module.exports = {
|
|
116
|
-
|
|
474
|
+
DEFAULT_AUTHOR,
|
|
475
|
+
DEFAULT_AUTHOR_HREF,
|
|
476
|
+
DEFAULT_COPYRIGHT,
|
|
477
|
+
DEFAULT_LICENSE,
|
|
478
|
+
DEFAULT_LOCATION,
|
|
479
|
+
DEFAULT_VERSION_TYPE,
|
|
480
|
+
Footer,
|
|
481
|
+
InformationContent,
|
|
482
|
+
InformationModal,
|
|
483
|
+
UNKNOWN,
|
|
484
|
+
calculateRemainingTime,
|
|
485
|
+
copyToClipboard,
|
|
486
|
+
formatAbsolute,
|
|
487
|
+
formatAbsoluteAndRelativeTime,
|
|
488
|
+
formatHumanDate,
|
|
489
|
+
formatRelativeTime,
|
|
490
|
+
normalizeDate,
|
|
491
|
+
pad
|
|
117
492
|
});
|
|
118
493
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/branding/Footer.tsx"],"sourcesContent":["/*\r\n * OTMC License.\r\n * Copyright (c) 2026 OTMC Softwares. All rights reserved.\r\n * Contributors: Nguyen Van Trung, OTMC Authors.\r\n */\r\n\r\nexport * from './branding';\r\n","/***\r\n * OTMC License.\r\n * Copyright (c) 2026 OTMC Softwares. All rights reserved.\r\n * Contributors: Nguyen Van Trung, OTMC Contributors.\r\n***/\r\n\r\nimport { Stack, Group, Text, Anchor, Tooltip, ActionIcon } from '@mantine/core';\r\nimport {\r\n IconCopyright,\r\n IconHeart,\r\n IconBrandFacebook,\r\n IconBrandGithub,\r\n IconMail,\r\n} from '@tabler/icons-react';\r\nimport { ReactNode } from 'react';\r\n\r\nexport interface FooterSocialLink {\r\n label: string;\r\n href: string;\r\n icon: ReactNode;\r\n color?: string;\r\n external?: boolean;\r\n}\r\n\r\nexport interface FooterProps {\r\n copyright?: string;\r\n author?: string;\r\n authorHref?: string;\r\n socialLinks?: FooterSocialLink[];\r\n showCopyright?: boolean;\r\n showAuthor?: boolean;\r\n showSocialLinks?: boolean;\r\n}\r\n\r\nconst DEFAULT_COPYRIGHT = 'OTMC Softwares. All rights reserved.';\r\nconst DEFAULT_AUTHOR = 'Nguyen Van Trung, OTMC Contributors.';\r\nconst DEFAULT_AUTHOR_HREF = 'https://github.com';\r\nconst DEFAULT_SOCIAL_LINKS: FooterSocialLink[] = [\r\n {\r\n label: 'Facebook',\r\n href: 'https://www.facebook.com',\r\n icon: <IconBrandFacebook size={20} />,\r\n color: 'blue.8',\r\n external: true,\r\n },\r\n {\r\n label: 'GitHub',\r\n href: 'https://github.com',\r\n icon: <IconBrandGithub size={20} />,\r\n color: 'gray.6',\r\n external: true,\r\n },\r\n {\r\n label: 'Gmail',\r\n href: 'mailto:test@gmail.com',\r\n icon: <IconMail size={20} />,\r\n color: 'red.8',\r\n external: false,\r\n },\r\n];\r\n\r\nexport function Footer({\r\n copyright = DEFAULT_COPYRIGHT,\r\n author = DEFAULT_AUTHOR,\r\n authorHref = DEFAULT_AUTHOR_HREF,\r\n socialLinks = DEFAULT_SOCIAL_LINKS,\r\n showSocialLinks = true,\r\n}: FooterProps) {\r\n\r\n return (\r\n <Stack gap=\"sm\" mt=\"md\" align=\"center\">\r\n <Stack gap={2} align=\"center\">\r\n <Group gap={4} wrap=\"nowrap\">\r\n <Text c=\"dimmed\" size=\"xs\">\r\n Copyright{' '}\r\n </Text>\r\n <IconCopyright size={15} />\r\n <Text size=\"xs\" c=\"dimmed\">\r\n {new Date().getFullYear()} {copyright}\r\n </Text>\r\n </Group>\r\n <Group gap={4} wrap=\"nowrap\">\r\n <Text size=\"xs\" c=\"dimmed\">\r\n Built with\r\n </Text>\r\n <IconHeart\r\n size={15}\r\n style={{ color: 'var(--mantine-color-red-7)' }}\r\n />\r\n <Text size=\"xs\" c=\"dimmed\">\r\n by\r\n </Text>\r\n <Anchor\r\n href={authorHref}\r\n size=\"xs\"\r\n fw={500}\r\n target=\"_blank\"\r\n >\r\n {author}\r\n </Anchor>\r\n </Group>\r\n </Stack>\r\n\r\n {showSocialLinks && socialLinks.length > 0 && (\r\n <Group gap=\"sm\">\r\n {socialLinks.map((link) => (\r\n <Tooltip key={link.href} label={link.label} withArrow>\r\n <ActionIcon\r\n variant=\"subtle\"\r\n color={link.color}\r\n component=\"a\"\r\n href={link.href}\r\n target={link.external ? '_blank' : undefined}\r\n rel={link.external ? 'noopener noreferrer' : undefined}\r\n >\r\n {link.icon}\r\n </ActionIcon>\r\n </Tooltip>\r\n ))}\r\n </Group>\r\n )}\r\n </Stack>\r\n );\r\n}\r\n\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACMA,kBAAgE;AAChE,yBAMO;AA4BG;AAPV,IAAM,oBAAoB;AAC1B,IAAM,iBAAiB;AACvB,IAAM,sBAAsB;AAC5B,IAAM,uBAA2C;AAAA,EAC/C;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM,4CAAC,wCAAkB,MAAM,IAAI;AAAA,IACnC,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM,4CAAC,sCAAgB,MAAM,IAAI;AAAA,IACjC,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM,4CAAC,+BAAS,MAAM,IAAI;AAAA,IAC1B,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AACF;AAEO,SAAS,OAAO;AAAA,EACrB,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,aAAa;AAAA,EACb,cAAc;AAAA,EACd,kBAAkB;AACpB,GAAgB;AAEd,SACE,6CAAC,qBAAM,KAAI,MAAK,IAAG,MAAK,OAAM,UAC5B;AAAA,iDAAC,qBAAM,KAAK,GAAG,OAAM,UACnB;AAAA,mDAAC,qBAAM,KAAK,GAAG,MAAK,UAClB;AAAA,qDAAC,oBAAK,GAAE,UAAS,MAAK,MAAK;AAAA;AAAA,UACf;AAAA,WACZ;AAAA,QACA,4CAAC,oCAAc,MAAM,IAAI;AAAA,QACzB,6CAAC,oBAAK,MAAK,MAAK,GAAE,UACf;AAAA,+BAAI,KAAK,GAAE,YAAY;AAAA,UAAE;AAAA,UAAE;AAAA,WAC9B;AAAA,SACF;AAAA,MACA,6CAAC,qBAAM,KAAK,GAAG,MAAK,UAClB;AAAA,oDAAC,oBAAK,MAAK,MAAK,GAAE,UAAS,wBAE3B;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,OAAO,EAAE,OAAO,6BAA6B;AAAA;AAAA,QAC/C;AAAA,QACA,4CAAC,oBAAK,MAAK,MAAK,GAAE,UAAS,gBAE3B;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,MAAK;AAAA,YACL,IAAI;AAAA,YACJ,QAAO;AAAA,YAEN;AAAA;AAAA,QACH;AAAA,SACF;AAAA,OACF;AAAA,IAEC,mBAAmB,YAAY,SAAS,KACvC,4CAAC,qBAAM,KAAI,MACR,sBAAY,IAAI,CAAC,SAChB,4CAAC,uBAAwB,OAAO,KAAK,OAAO,WAAS,MACnD;AAAA,MAAC;AAAA;AAAA,QACC,SAAQ;AAAA,QACR,OAAO,KAAK;AAAA,QACZ,WAAU;AAAA,QACV,MAAM,KAAK;AAAA,QACX,QAAQ,KAAK,WAAW,WAAW;AAAA,QACnC,KAAK,KAAK,WAAW,wBAAwB;AAAA,QAE5C,eAAK;AAAA;AAAA,IACR,KAVY,KAAK,IAWnB,CACD,GACH;AAAA,KAEJ;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/branding/Footer.tsx","../src/utils/constants.ts","../src/modals/Information.tsx","../src/utils/commonUtils.ts","../src/utils/timeUtils.ts"],"sourcesContent":["/*\r\n * OTMC License.\r\n * Copyright (c) 2026 OTMC Softwares. All rights reserved.\r\n * Contributors: Nguyen Van Trung, OTMC Authors.\r\n */\r\n\r\nexport * from './branding';\r\nexport * from './modals';\r\nexport * from './utils';\r\n","/***\r\n * OTMC License.\r\n * Copyright (c) 2026 OTMC Softwares. All rights reserved.\r\n * Contributors: Nguyen Van Trung, OTMC Contributors.\r\n***/\r\n\r\nimport { Stack, Group, Text, Anchor, Tooltip, ActionIcon } from '@mantine/core';\r\nimport {\r\n IconCopyright,\r\n IconHeart,\r\n IconBrandFacebook,\r\n IconBrandGithub,\r\n IconMail,\r\n} from '@tabler/icons-react';\r\nimport { ReactNode } from 'react';\r\n\r\nimport {\r\n DEFAULT_AUTHOR,\r\n DEFAULT_AUTHOR_HREF,\r\n DEFAULT_COPYRIGHT,\r\n} from '../utils/constants';\r\n\r\nexport interface FooterSocialLink {\r\n label: string;\r\n href: string;\r\n icon: ReactNode;\r\n color?: string;\r\n external?: boolean;\r\n}\r\n\r\nexport interface FooterProps {\r\n copyright?: string;\r\n author?: string;\r\n authorHref?: string;\r\n socialLinks?: FooterSocialLink[];\r\n showCopyright?: boolean;\r\n showAuthor?: boolean;\r\n showSocialLinks?: boolean;\r\n}\r\n\r\nconst DEFAULT_SOCIAL_LINKS: FooterSocialLink[] = [\r\n {\r\n label: 'Facebook',\r\n href: 'https://www.facebook.com',\r\n icon: <IconBrandFacebook size={20} />,\r\n color: 'blue.8',\r\n external: true,\r\n },\r\n {\r\n label: 'GitHub',\r\n href: 'https://github.com',\r\n icon: <IconBrandGithub size={20} />,\r\n color: 'gray.6',\r\n external: true,\r\n },\r\n {\r\n label: 'Gmail',\r\n href: 'mailto:test@gmail.com',\r\n icon: <IconMail size={20} />,\r\n color: 'red.8',\r\n external: false,\r\n },\r\n];\r\n\r\nexport function Footer({\r\n copyright = DEFAULT_COPYRIGHT,\r\n author = DEFAULT_AUTHOR,\r\n authorHref = DEFAULT_AUTHOR_HREF,\r\n socialLinks = DEFAULT_SOCIAL_LINKS,\r\n showSocialLinks = true,\r\n}: FooterProps) {\r\n\r\n return (\r\n <Stack gap=\"sm\" mt=\"md\" align=\"center\">\r\n <Stack gap={2} align=\"center\">\r\n <Group gap={4} wrap=\"nowrap\">\r\n <Text c=\"dimmed\" size=\"xs\">\r\n Copyright{' '}\r\n </Text>\r\n <IconCopyright size={15} />\r\n <Text size=\"xs\" c=\"dimmed\">\r\n {new Date().getFullYear()} {copyright}\r\n </Text>\r\n </Group>\r\n <Group gap={4} wrap=\"nowrap\">\r\n <Text size=\"xs\" c=\"dimmed\">\r\n Built with\r\n </Text>\r\n <IconHeart\r\n size={15}\r\n style={{ color: 'var(--mantine-color-red-7)' }}\r\n />\r\n <Text size=\"xs\" c=\"dimmed\">\r\n by\r\n </Text>\r\n <Anchor\r\n href={authorHref}\r\n size=\"xs\"\r\n fw={500}\r\n target=\"_blank\"\r\n >\r\n {author}\r\n </Anchor>\r\n </Group>\r\n </Stack>\r\n\r\n {showSocialLinks && socialLinks.length > 0 && (\r\n <Group gap=\"sm\">\r\n {socialLinks.map((link) => (\r\n <Tooltip key={link.href} label={link.label} withArrow>\r\n <ActionIcon\r\n variant=\"subtle\"\r\n color={link.color}\r\n component=\"a\"\r\n href={link.href}\r\n target={link.external ? '_blank' : undefined}\r\n rel={link.external ? 'noopener noreferrer' : undefined}\r\n >\r\n {link.icon}\r\n </ActionIcon>\r\n </Tooltip>\r\n ))}\r\n </Group>\r\n )}\r\n </Stack>\r\n );\r\n}\r\n\r\n","/**\r\n * @License OTMC License\r\n * @Copyright (c) 2026 OTMC Softwares. All rights reserved.\r\n * @Contributors Trung Ng, OTMC Authors.\r\n**/\r\n\r\nexport const DEFAULT_AUTHOR = 'Nguyen Van Trung, OTMC Contributors.';\r\nexport const DEFAULT_AUTHOR_HREF = 'https://github.com/otmc-sw';\r\nexport const DEFAULT_COPYRIGHT = 'OTMC Softwares. All rights reserved.';\r\nexport const DEFAULT_LICENSE = 'OTMC License.';\r\nexport const DEFAULT_LOCATION = 'An Nhon, Gia Lai, Viet Nam.';\r\nexport const DEFAULT_VERSION_TYPE = 'Internal';\r\nexport const UNKNOWN = 'Unknown';\r\n","/***\n * OTMC License.\n * Copyright (c) 2026 OTMC Softwares. All rights reserved.\n * Contributors: Nguyen Van Trung, OTMC Contributors.\n***/\n\nimport { useState, type ReactNode } from 'react';\nimport {\n Modal,\n Stack,\n Title,\n Text,\n Group,\n Divider,\n Badge,\n ThemeIcon,\n SimpleGrid,\n Paper,\n ActionIcon,\n Tooltip,\n useComputedColorScheme,\n} from '@mantine/core';\nimport {\n IconAward,\n IconCalendar,\n IconCheck,\n IconCopy,\n IconCpu,\n IconHash,\n IconLicense,\n IconMapPin,\n IconTag,\n IconUser,\n} from '@tabler/icons-react';\n\nimport { Footer, type FooterSocialLink } from '../branding';\nimport { copyToClipboard } from '../utils/commonUtils';\nimport {\n DEFAULT_AUTHOR,\n DEFAULT_LICENSE,\n DEFAULT_LOCATION,\n DEFAULT_VERSION_TYPE,\n UNKNOWN,\n} from '../utils/constants';\nimport { formatAbsoluteAndRelativeTime } from '../utils/timeUtils';\n\nexport interface InformationMetadata {\n icon?: ReactNode;\n label: string;\n value: string;\n color?: string;\n}\n\nexport interface ApplicationInfo {\n name: string;\n version?: string;\n versionType?: string;\n tagline?: string;\n logo?: ReactNode;\n author?: string;\n authorHref?: string;\n license?: string;\n location?: string;\n copyright?: string;\n buildId?: string;\n buildTime?: string | number | Date;\n metadata?: InformationMetadata[];\n socialLinks?: FooterSocialLink[];\n}\n\nexport interface InformationContentProps {\n info: ApplicationInfo;\n}\n\nexport interface InformationModalProps {\n opened: boolean;\n onClose: () => void;\n info: ApplicationInfo;\n title?: ReactNode;\n}\n\nconst DEFAULT_TITLE = (\n <Group gap=\"xs\" wrap=\"nowrap\">\n <IconCpu size={20} />\n <span>System Information</span>\n </Group>\n);\n\n\nexport function InformationContent({ info }: InformationContentProps) {\n const colorScheme = useComputedColorScheme();\n\n const author = info.author ?? DEFAULT_AUTHOR;\n const versionType = info.versionType ?? DEFAULT_VERSION_TYPE;\n\n const cards: InformationMetadata[] = [\n {\n icon: <IconUser size={18} />,\n label: 'Author',\n value: author,\n color: 'blue',\n },\n {\n icon: <IconLicense size={18} />,\n label: 'License',\n value: info.license ?? DEFAULT_LICENSE,\n color: 'orange',\n },\n {\n icon: <IconMapPin size={18} />,\n label: 'Location',\n value: info.location ?? DEFAULT_LOCATION,\n color: 'teal',\n },\n {\n icon: <IconTag size={18} />,\n label: 'Version Type',\n value: versionType,\n color: 'red',\n },\n {\n icon: <IconCalendar size={18} />,\n label: 'Build Time',\n value:\n info.buildTime !== undefined\n ? formatAbsoluteAndRelativeTime(info.buildTime)\n : UNKNOWN,\n color: 'green',\n },\n ...(info.metadata ?? []),\n ];\n\n return (\n <Stack gap=\"lg\">\n <Stack gap=\"xs\" align=\"center\">\n {info.logo}\n\n <Stack gap={2} align=\"center\">\n <Title order={2}>{info.name}</Title>\n {info.tagline && (\n <Text size=\"sm\" c=\"dimmed\" w={600} ta=\"center\">\n {info.tagline}\n </Text>\n )}\n </Stack>\n\n <Group gap=\"xs\">\n {info.version && (\n <Badge\n size=\"lg\"\n color=\"blue\"\n variant=\"outline\"\n mt=\"sm\"\n tt=\"none\"\n fw={600}\n >\n ✨ v{info.version}\n </Badge>\n )}\n <Badge\n size=\"lg\"\n color=\"teal\"\n variant=\"light\"\n mt=\"sm\"\n tt=\"none\"\n fw={600}\n >\n 🧩 {versionType}\n </Badge>\n </Group>\n </Stack>\n\n <Divider label=\"System Information\" labelPosition=\"center\" />\n\n <SimpleGrid cols={{ base: 1, sm: 2 }}>\n {cards.map((card) => (\n <InfoCard\n key={card.label}\n icon={card.icon ?? <IconAward size={18} />}\n label={card.label}\n value={card.value}\n color={card.color ?? 'gray'}\n />\n ))}\n\n <Paper\n withBorder\n p=\"sm\"\n radius=\"18px\"\n bg={colorScheme === 'dark' ? 'gray.9' : 'gray.0'}\n >\n <Group justify=\"space-between\" wrap=\"nowrap\">\n <Group gap=\"sm\" flex={1}>\n <ThemeIcon variant=\"light\" color=\"yellow\" size=\"lg\" radius=\"14px\">\n <IconHash size={18} />\n </ThemeIcon>\n\n <Stack gap={2}>\n <Text size=\"xs\" c=\"dimmed\" fw={700} tt=\"uppercase\">\n Build ID\n </Text>\n <Text size=\"sm\" fw={500} truncate>\n {info.buildId ?? UNKNOWN}\n </Text>\n </Stack>\n </Group>\n\n {info.buildId && <CopyBuildIdButton buildId={info.buildId} />}\n </Group>\n </Paper>\n </SimpleGrid>\n\n <Footer\n copyright={info.copyright}\n author={author}\n authorHref={info.authorHref}\n socialLinks={info.socialLinks}\n />\n </Stack>\n );\n}\n\nexport function InformationModal({\n opened,\n onClose,\n info,\n title = DEFAULT_TITLE,\n}: InformationModalProps) {\n return (\n <Modal\n opened={opened}\n onClose={onClose}\n withCloseButton\n centered\n radius=\"lg\"\n size=\"60%\"\n styles={{\n content: {\n maxHeight: '90vh',\n height: '90vh',\n },\n body: {\n flex: 1,\n overflow: 'auto',\n },\n }}\n title={title}\n >\n <InformationContent info={info} />\n </Modal>\n );\n}\n\nfunction CopyBuildIdButton({ buildId }: { buildId: string }) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = async () => {\n const success = await copyToClipboard(buildId);\n if (success) {\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }\n };\n\n return (\n <Tooltip label={copied ? 'Copied!' : 'Copy ID'} withArrow>\n <ActionIcon\n variant=\"subtle\"\n color={copied ? 'teal' : 'gray'}\n onClick={handleCopy}\n >\n {copied ? <IconCheck size={16} /> : <IconCopy size={16} />}\n </ActionIcon>\n </Tooltip>\n );\n}\n\nfunction InfoCard({\n icon,\n label,\n value,\n color,\n}: {\n icon: ReactNode;\n label: string;\n value: string;\n color: string;\n}) {\n const colorScheme = useComputedColorScheme();\n return (\n <Paper withBorder p=\"md\" radius=\"18px\" h=\"100%\" bg={colorScheme === 'dark' ? 'gray.9' : 'gray.0'}>\n <Group gap=\"sm\" align=\"flex-start\">\n <ThemeIcon color={color} variant=\"light\" size=\"lg\" radius=\"14px\">\n {icon}\n </ThemeIcon>\n\n <Stack gap={2} flex={1}>\n <Text size=\"xs\" c=\"dimmed\" fw={700} tt=\"uppercase\">\n {label}\n </Text>\n <Text size=\"sm\" fw={500} lineClamp={1}>\n {value}\n </Text>\n </Stack>\n </Group>\n </Paper>\n );\n}\n\n","/**\n * @License OTMC License\n * @Copyright (c) 2026 OTMC Softwares. All rights reserved.\n * @Contributors Trung Ng, OTMC Authors.\n**/\nexport const copyToClipboard = async (text: string): Promise<boolean> => {\n try {\n if (navigator.clipboard && window.isSecureContext) {\n await navigator.clipboard.writeText(text);\n return true;\n }\n \n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.position = 'fixed';\n textarea.style.left = '-9999px';\n textarea.style.top = '-9999px';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n textarea.focus();\n textarea.select();\n \n const success = document.execCommand('copy');\n document.body.removeChild(textarea);\n \n return success;\n } catch (err) {\n console.error('Failed to copy to clipboard:', err);\n return false;\n }\n};\n","/**\n * @License OTMC License\n * @Copyright (c) 2026 OTMC Softwares. All rights reserved.\n * @Contributors Trung Ng, OTMC Authors.\n**/\n\nexport type TimestampFormatType = \"absolute\" | \"relative\";\n\n\nexport function normalizeDate(dateInput: string | number | Date): Date | null {\n if (dateInput instanceof Date) {\n return isNaN(dateInput.getTime()) ? null : dateInput;\n }\n\n if (typeof dateInput === 'string') {\n const date = new Date(dateInput);\n return isNaN(date.getTime()) ? null : date;\n }\n\n if (typeof dateInput === 'number') {\n const timestamp = dateInput < 1e12 ? dateInput * 1000 : dateInput;\n const date = new Date(timestamp);\n return isNaN(date.getTime()) ? null : date;\n }\n\n return null;\n}\n\nexport function pad(n: number, width: number = 2): string {\n return String(n).padStart(width, \"0\");\n}\n\nexport function formatAbsolute(date: Date): string {\n const tz = -date.getTimezoneOffset();\n const sign = tz >= 0 ? \"+\" : \"-\";\n \n return (\n `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +\n `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())} ` +\n `${sign}${pad(Math.floor(Math.abs(tz) / 60))}:${pad(Math.abs(tz) % 60)}`\n );\n}\n\nexport function formatRelativeTime(date: string | number | Date): string {\n const normalizedDate = normalizeDate(date);\n if (!normalizedDate) return \"Invalid date\";\n\n const now = Date.now();\n const diffMs = now - normalizedDate.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n\n if (diffSeconds < 0) {\n return \"Just now\";\n }\n\n if (diffSeconds < 60) {\n return \"Just now\";\n }\n\n const minute = 60;\n const hour = minute * 60;\n const day = hour * 24;\n const week = day * 7;\n const month = day * 30;\n const year = day * 365;\n\n if (diffSeconds < hour) {\n const mins = Math.floor(diffSeconds / minute);\n return `${mins} min${mins !== 1 ? 's' : ''} ago`;\n } else if (diffSeconds < day) {\n const hours = Math.floor(diffSeconds / hour);\n return `${hours} hour${hours !== 1 ? 's' : ''} ago`;\n } else if (diffSeconds < week) {\n const days = Math.floor(diffSeconds / day);\n return `${days} day${days !== 1 ? 's' : ''} ago`;\n } else if (diffSeconds < month) {\n const weeks = Math.floor(diffSeconds / week);\n return `${weeks} week${weeks !== 1 ? 's' : ''} ago`;\n } else if (diffSeconds < year) {\n const months = Math.floor(diffSeconds / month);\n return `${months} month${months !== 1 ? 's' : ''} ago`;\n } else {\n const years = Math.floor(diffSeconds / year);\n return `${years} year${years !== 1 ? 's' : ''} ago`;\n }\n}\n\nexport function formatAbsoluteAndRelativeTime(date: string | number | Date): string {\n const normalizedDate = normalizeDate(date);\n if (!normalizedDate) return \"Invalid date\";\n\n const absoluteTime = formatAbsolute(normalizedDate);\n const relativeTime = formatRelativeTime(normalizedDate);\n\n return `${absoluteTime} (${relativeTime})`;\n}\n\nexport function calculateRemainingTime(targetDate: string | number | Date | undefined): string {\n if (!targetDate) return 'Not set';\n\n const normalizedDate = normalizeDate(targetDate);\n if (!normalizedDate) return 'Invalid date';\n\n const now = new Date();\n const diffMs = normalizedDate.getTime() - now.getTime();\n\n if (diffMs < 0) {\n const daysOverdue = Math.floor(Math.abs(diffMs) / (1000 * 60 * 60 * 24));\n return `Overdue ${daysOverdue}d`;\n }\n\n const days = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n const hours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));\n\n if (days > 0) {\n return `${days}d ${hours}h`;\n } else if (hours > 0) {\n return `${hours}h`;\n } else {\n return '< 1h';\n }\n}\n\nconst MONTH_NAMES = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\nexport function formatHumanDate(date: string | number | Date, options?: { showTime?: boolean; showSeconds?: boolean }): string {\n const normalizedDate = normalizeDate(date);\n if (!normalizedDate) return 'Invalid date';\n\n const month = MONTH_NAMES[normalizedDate.getMonth()];\n const day = normalizedDate.getDate();\n const year = normalizedDate.getFullYear();\n\n if (!options?.showTime) {\n return `${month} ${day}, ${year}`;\n }\n\n const hours = normalizedDate.getHours();\n const minutes = normalizedDate.getMinutes();\n const seconds = normalizedDate.getSeconds();\n const ampm = hours >= 12 ? 'PM' : 'AM';\n const hours12 = hours % 12 || 12;\n\n let timeStr = `${hours12}:${pad(minutes)}`;\n if (options.showSeconds) {\n timeStr += `:${pad(seconds)}`;\n }\n timeStr += ` ${ampm}`;\n\n return `${month} ${day}, ${year} ${timeStr}`;\n}\n\n"],"mappings":"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","names":["import_core","import_icons_react","import_jsx_runtime"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -19,4 +19,75 @@ interface FooterProps {
|
|
|
19
19
|
}
|
|
20
20
|
declare function Footer({ copyright, author, authorHref, socialLinks, showSocialLinks, }: FooterProps): react.JSX.Element;
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
interface InformationMetadata {
|
|
23
|
+
icon?: ReactNode;
|
|
24
|
+
label: string;
|
|
25
|
+
value: string;
|
|
26
|
+
color?: string;
|
|
27
|
+
}
|
|
28
|
+
interface ApplicationInfo {
|
|
29
|
+
name: string;
|
|
30
|
+
version?: string;
|
|
31
|
+
versionType?: string;
|
|
32
|
+
tagline?: string;
|
|
33
|
+
logo?: ReactNode;
|
|
34
|
+
author?: string;
|
|
35
|
+
authorHref?: string;
|
|
36
|
+
license?: string;
|
|
37
|
+
location?: string;
|
|
38
|
+
copyright?: string;
|
|
39
|
+
buildId?: string;
|
|
40
|
+
buildTime?: string | number | Date;
|
|
41
|
+
metadata?: InformationMetadata[];
|
|
42
|
+
socialLinks?: FooterSocialLink[];
|
|
43
|
+
}
|
|
44
|
+
interface InformationContentProps {
|
|
45
|
+
info: ApplicationInfo;
|
|
46
|
+
}
|
|
47
|
+
interface InformationModalProps {
|
|
48
|
+
opened: boolean;
|
|
49
|
+
onClose: () => void;
|
|
50
|
+
info: ApplicationInfo;
|
|
51
|
+
title?: ReactNode;
|
|
52
|
+
}
|
|
53
|
+
declare function InformationContent({ info }: InformationContentProps): react.JSX.Element;
|
|
54
|
+
declare function InformationModal({ opened, onClose, info, title, }: InformationModalProps): react.JSX.Element;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @License OTMC License
|
|
58
|
+
* @Copyright (c) 2026 OTMC Softwares. All rights reserved.
|
|
59
|
+
* @Contributors Trung Ng, OTMC Authors.
|
|
60
|
+
**/
|
|
61
|
+
declare const copyToClipboard: (text: string) => Promise<boolean>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @License OTMC License
|
|
65
|
+
* @Copyright (c) 2026 OTMC Softwares. All rights reserved.
|
|
66
|
+
* @Contributors Trung Ng, OTMC Authors.
|
|
67
|
+
**/
|
|
68
|
+
declare const DEFAULT_AUTHOR = "Nguyen Van Trung, OTMC Contributors.";
|
|
69
|
+
declare const DEFAULT_AUTHOR_HREF = "https://github.com/otmc-sw";
|
|
70
|
+
declare const DEFAULT_COPYRIGHT = "OTMC Softwares. All rights reserved.";
|
|
71
|
+
declare const DEFAULT_LICENSE = "OTMC License.";
|
|
72
|
+
declare const DEFAULT_LOCATION = "An Nhon, Gia Lai, Viet Nam.";
|
|
73
|
+
declare const DEFAULT_VERSION_TYPE = "Internal";
|
|
74
|
+
declare const UNKNOWN = "Unknown";
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @License OTMC License
|
|
78
|
+
* @Copyright (c) 2026 OTMC Softwares. All rights reserved.
|
|
79
|
+
* @Contributors Trung Ng, OTMC Authors.
|
|
80
|
+
**/
|
|
81
|
+
type TimestampFormatType = "absolute" | "relative";
|
|
82
|
+
declare function normalizeDate(dateInput: string | number | Date): Date | null;
|
|
83
|
+
declare function pad(n: number, width?: number): string;
|
|
84
|
+
declare function formatAbsolute(date: Date): string;
|
|
85
|
+
declare function formatRelativeTime(date: string | number | Date): string;
|
|
86
|
+
declare function formatAbsoluteAndRelativeTime(date: string | number | Date): string;
|
|
87
|
+
declare function calculateRemainingTime(targetDate: string | number | Date | undefined): string;
|
|
88
|
+
declare function formatHumanDate(date: string | number | Date, options?: {
|
|
89
|
+
showTime?: boolean;
|
|
90
|
+
showSeconds?: boolean;
|
|
91
|
+
}): string;
|
|
92
|
+
|
|
93
|
+
export { type ApplicationInfo, DEFAULT_AUTHOR, DEFAULT_AUTHOR_HREF, DEFAULT_COPYRIGHT, DEFAULT_LICENSE, DEFAULT_LOCATION, DEFAULT_VERSION_TYPE, Footer, type FooterProps, type FooterSocialLink, InformationContent, type InformationContentProps, type InformationMetadata, InformationModal, type InformationModalProps, type TimestampFormatType, UNKNOWN, calculateRemainingTime, copyToClipboard, formatAbsolute, formatAbsoluteAndRelativeTime, formatHumanDate, formatRelativeTime, normalizeDate, pad };
|
package/dist/index.d.ts
CHANGED
|
@@ -19,4 +19,75 @@ interface FooterProps {
|
|
|
19
19
|
}
|
|
20
20
|
declare function Footer({ copyright, author, authorHref, socialLinks, showSocialLinks, }: FooterProps): react.JSX.Element;
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
interface InformationMetadata {
|
|
23
|
+
icon?: ReactNode;
|
|
24
|
+
label: string;
|
|
25
|
+
value: string;
|
|
26
|
+
color?: string;
|
|
27
|
+
}
|
|
28
|
+
interface ApplicationInfo {
|
|
29
|
+
name: string;
|
|
30
|
+
version?: string;
|
|
31
|
+
versionType?: string;
|
|
32
|
+
tagline?: string;
|
|
33
|
+
logo?: ReactNode;
|
|
34
|
+
author?: string;
|
|
35
|
+
authorHref?: string;
|
|
36
|
+
license?: string;
|
|
37
|
+
location?: string;
|
|
38
|
+
copyright?: string;
|
|
39
|
+
buildId?: string;
|
|
40
|
+
buildTime?: string | number | Date;
|
|
41
|
+
metadata?: InformationMetadata[];
|
|
42
|
+
socialLinks?: FooterSocialLink[];
|
|
43
|
+
}
|
|
44
|
+
interface InformationContentProps {
|
|
45
|
+
info: ApplicationInfo;
|
|
46
|
+
}
|
|
47
|
+
interface InformationModalProps {
|
|
48
|
+
opened: boolean;
|
|
49
|
+
onClose: () => void;
|
|
50
|
+
info: ApplicationInfo;
|
|
51
|
+
title?: ReactNode;
|
|
52
|
+
}
|
|
53
|
+
declare function InformationContent({ info }: InformationContentProps): react.JSX.Element;
|
|
54
|
+
declare function InformationModal({ opened, onClose, info, title, }: InformationModalProps): react.JSX.Element;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @License OTMC License
|
|
58
|
+
* @Copyright (c) 2026 OTMC Softwares. All rights reserved.
|
|
59
|
+
* @Contributors Trung Ng, OTMC Authors.
|
|
60
|
+
**/
|
|
61
|
+
declare const copyToClipboard: (text: string) => Promise<boolean>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @License OTMC License
|
|
65
|
+
* @Copyright (c) 2026 OTMC Softwares. All rights reserved.
|
|
66
|
+
* @Contributors Trung Ng, OTMC Authors.
|
|
67
|
+
**/
|
|
68
|
+
declare const DEFAULT_AUTHOR = "Nguyen Van Trung, OTMC Contributors.";
|
|
69
|
+
declare const DEFAULT_AUTHOR_HREF = "https://github.com/otmc-sw";
|
|
70
|
+
declare const DEFAULT_COPYRIGHT = "OTMC Softwares. All rights reserved.";
|
|
71
|
+
declare const DEFAULT_LICENSE = "OTMC License.";
|
|
72
|
+
declare const DEFAULT_LOCATION = "An Nhon, Gia Lai, Viet Nam.";
|
|
73
|
+
declare const DEFAULT_VERSION_TYPE = "Internal";
|
|
74
|
+
declare const UNKNOWN = "Unknown";
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @License OTMC License
|
|
78
|
+
* @Copyright (c) 2026 OTMC Softwares. All rights reserved.
|
|
79
|
+
* @Contributors Trung Ng, OTMC Authors.
|
|
80
|
+
**/
|
|
81
|
+
type TimestampFormatType = "absolute" | "relative";
|
|
82
|
+
declare function normalizeDate(dateInput: string | number | Date): Date | null;
|
|
83
|
+
declare function pad(n: number, width?: number): string;
|
|
84
|
+
declare function formatAbsolute(date: Date): string;
|
|
85
|
+
declare function formatRelativeTime(date: string | number | Date): string;
|
|
86
|
+
declare function formatAbsoluteAndRelativeTime(date: string | number | Date): string;
|
|
87
|
+
declare function calculateRemainingTime(targetDate: string | number | Date | undefined): string;
|
|
88
|
+
declare function formatHumanDate(date: string | number | Date, options?: {
|
|
89
|
+
showTime?: boolean;
|
|
90
|
+
showSeconds?: boolean;
|
|
91
|
+
}): string;
|
|
92
|
+
|
|
93
|
+
export { type ApplicationInfo, DEFAULT_AUTHOR, DEFAULT_AUTHOR_HREF, DEFAULT_COPYRIGHT, DEFAULT_LICENSE, DEFAULT_LOCATION, DEFAULT_VERSION_TYPE, Footer, type FooterProps, type FooterSocialLink, InformationContent, type InformationContentProps, type InformationMetadata, InformationModal, type InformationModalProps, type TimestampFormatType, UNKNOWN, calculateRemainingTime, copyToClipboard, formatAbsolute, formatAbsoluteAndRelativeTime, formatHumanDate, formatRelativeTime, normalizeDate, pad };
|
package/dist/index.js
CHANGED
|
@@ -7,10 +7,18 @@ import {
|
|
|
7
7
|
IconBrandGithub,
|
|
8
8
|
IconMail
|
|
9
9
|
} from "@tabler/icons-react";
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
// src/utils/constants.ts
|
|
12
12
|
var DEFAULT_AUTHOR = "Nguyen Van Trung, OTMC Contributors.";
|
|
13
|
-
var DEFAULT_AUTHOR_HREF = "https://github.com";
|
|
13
|
+
var DEFAULT_AUTHOR_HREF = "https://github.com/otmc-sw";
|
|
14
|
+
var DEFAULT_COPYRIGHT = "OTMC Softwares. All rights reserved.";
|
|
15
|
+
var DEFAULT_LICENSE = "OTMC License.";
|
|
16
|
+
var DEFAULT_LOCATION = "An Nhon, Gia Lai, Viet Nam.";
|
|
17
|
+
var DEFAULT_VERSION_TYPE = "Internal";
|
|
18
|
+
var UNKNOWN = "Unknown";
|
|
19
|
+
|
|
20
|
+
// src/branding/Footer.tsx
|
|
21
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
22
|
var DEFAULT_SOCIAL_LINKS = [
|
|
15
23
|
{
|
|
16
24
|
label: "Facebook",
|
|
@@ -91,7 +99,382 @@ function Footer({
|
|
|
91
99
|
) }, link.href)) })
|
|
92
100
|
] });
|
|
93
101
|
}
|
|
102
|
+
|
|
103
|
+
// src/modals/Information.tsx
|
|
104
|
+
import { useState } from "react";
|
|
105
|
+
import {
|
|
106
|
+
Modal,
|
|
107
|
+
Stack as Stack2,
|
|
108
|
+
Title,
|
|
109
|
+
Text as Text2,
|
|
110
|
+
Group as Group2,
|
|
111
|
+
Divider,
|
|
112
|
+
Badge,
|
|
113
|
+
ThemeIcon,
|
|
114
|
+
SimpleGrid,
|
|
115
|
+
Paper,
|
|
116
|
+
ActionIcon as ActionIcon2,
|
|
117
|
+
Tooltip as Tooltip2,
|
|
118
|
+
useComputedColorScheme
|
|
119
|
+
} from "@mantine/core";
|
|
120
|
+
import {
|
|
121
|
+
IconAward,
|
|
122
|
+
IconCalendar,
|
|
123
|
+
IconCheck,
|
|
124
|
+
IconCopy,
|
|
125
|
+
IconCpu,
|
|
126
|
+
IconHash,
|
|
127
|
+
IconLicense,
|
|
128
|
+
IconMapPin,
|
|
129
|
+
IconTag,
|
|
130
|
+
IconUser
|
|
131
|
+
} from "@tabler/icons-react";
|
|
132
|
+
|
|
133
|
+
// src/utils/commonUtils.ts
|
|
134
|
+
var copyToClipboard = async (text) => {
|
|
135
|
+
try {
|
|
136
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
137
|
+
await navigator.clipboard.writeText(text);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
const textarea = document.createElement("textarea");
|
|
141
|
+
textarea.value = text;
|
|
142
|
+
textarea.style.position = "fixed";
|
|
143
|
+
textarea.style.left = "-9999px";
|
|
144
|
+
textarea.style.top = "-9999px";
|
|
145
|
+
textarea.style.opacity = "0";
|
|
146
|
+
document.body.appendChild(textarea);
|
|
147
|
+
textarea.focus();
|
|
148
|
+
textarea.select();
|
|
149
|
+
const success = document.execCommand("copy");
|
|
150
|
+
document.body.removeChild(textarea);
|
|
151
|
+
return success;
|
|
152
|
+
} catch (err) {
|
|
153
|
+
console.error("Failed to copy to clipboard:", err);
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// src/utils/timeUtils.ts
|
|
159
|
+
function normalizeDate(dateInput) {
|
|
160
|
+
if (dateInput instanceof Date) {
|
|
161
|
+
return isNaN(dateInput.getTime()) ? null : dateInput;
|
|
162
|
+
}
|
|
163
|
+
if (typeof dateInput === "string") {
|
|
164
|
+
const date = new Date(dateInput);
|
|
165
|
+
return isNaN(date.getTime()) ? null : date;
|
|
166
|
+
}
|
|
167
|
+
if (typeof dateInput === "number") {
|
|
168
|
+
const timestamp = dateInput < 1e12 ? dateInput * 1e3 : dateInput;
|
|
169
|
+
const date = new Date(timestamp);
|
|
170
|
+
return isNaN(date.getTime()) ? null : date;
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
function pad(n, width = 2) {
|
|
175
|
+
return String(n).padStart(width, "0");
|
|
176
|
+
}
|
|
177
|
+
function formatAbsolute(date) {
|
|
178
|
+
const tz = -date.getTimezoneOffset();
|
|
179
|
+
const sign = tz >= 0 ? "+" : "-";
|
|
180
|
+
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)}`;
|
|
181
|
+
}
|
|
182
|
+
function formatRelativeTime(date) {
|
|
183
|
+
const normalizedDate = normalizeDate(date);
|
|
184
|
+
if (!normalizedDate) return "Invalid date";
|
|
185
|
+
const now = Date.now();
|
|
186
|
+
const diffMs = now - normalizedDate.getTime();
|
|
187
|
+
const diffSeconds = Math.floor(diffMs / 1e3);
|
|
188
|
+
if (diffSeconds < 0) {
|
|
189
|
+
return "Just now";
|
|
190
|
+
}
|
|
191
|
+
if (diffSeconds < 60) {
|
|
192
|
+
return "Just now";
|
|
193
|
+
}
|
|
194
|
+
const minute = 60;
|
|
195
|
+
const hour = minute * 60;
|
|
196
|
+
const day = hour * 24;
|
|
197
|
+
const week = day * 7;
|
|
198
|
+
const month = day * 30;
|
|
199
|
+
const year = day * 365;
|
|
200
|
+
if (diffSeconds < hour) {
|
|
201
|
+
const mins = Math.floor(diffSeconds / minute);
|
|
202
|
+
return `${mins} min${mins !== 1 ? "s" : ""} ago`;
|
|
203
|
+
} else if (diffSeconds < day) {
|
|
204
|
+
const hours = Math.floor(diffSeconds / hour);
|
|
205
|
+
return `${hours} hour${hours !== 1 ? "s" : ""} ago`;
|
|
206
|
+
} else if (diffSeconds < week) {
|
|
207
|
+
const days = Math.floor(diffSeconds / day);
|
|
208
|
+
return `${days} day${days !== 1 ? "s" : ""} ago`;
|
|
209
|
+
} else if (diffSeconds < month) {
|
|
210
|
+
const weeks = Math.floor(diffSeconds / week);
|
|
211
|
+
return `${weeks} week${weeks !== 1 ? "s" : ""} ago`;
|
|
212
|
+
} else if (diffSeconds < year) {
|
|
213
|
+
const months = Math.floor(diffSeconds / month);
|
|
214
|
+
return `${months} month${months !== 1 ? "s" : ""} ago`;
|
|
215
|
+
} else {
|
|
216
|
+
const years = Math.floor(diffSeconds / year);
|
|
217
|
+
return `${years} year${years !== 1 ? "s" : ""} ago`;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function formatAbsoluteAndRelativeTime(date) {
|
|
221
|
+
const normalizedDate = normalizeDate(date);
|
|
222
|
+
if (!normalizedDate) return "Invalid date";
|
|
223
|
+
const absoluteTime = formatAbsolute(normalizedDate);
|
|
224
|
+
const relativeTime = formatRelativeTime(normalizedDate);
|
|
225
|
+
return `${absoluteTime} (${relativeTime})`;
|
|
226
|
+
}
|
|
227
|
+
function calculateRemainingTime(targetDate) {
|
|
228
|
+
if (!targetDate) return "Not set";
|
|
229
|
+
const normalizedDate = normalizeDate(targetDate);
|
|
230
|
+
if (!normalizedDate) return "Invalid date";
|
|
231
|
+
const now = /* @__PURE__ */ new Date();
|
|
232
|
+
const diffMs = normalizedDate.getTime() - now.getTime();
|
|
233
|
+
if (diffMs < 0) {
|
|
234
|
+
const daysOverdue = Math.floor(Math.abs(diffMs) / (1e3 * 60 * 60 * 24));
|
|
235
|
+
return `Overdue ${daysOverdue}d`;
|
|
236
|
+
}
|
|
237
|
+
const days = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
238
|
+
const hours = Math.floor(diffMs % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
|
|
239
|
+
if (days > 0) {
|
|
240
|
+
return `${days}d ${hours}h`;
|
|
241
|
+
} else if (hours > 0) {
|
|
242
|
+
return `${hours}h`;
|
|
243
|
+
} else {
|
|
244
|
+
return "< 1h";
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
var MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
248
|
+
function formatHumanDate(date, options) {
|
|
249
|
+
const normalizedDate = normalizeDate(date);
|
|
250
|
+
if (!normalizedDate) return "Invalid date";
|
|
251
|
+
const month = MONTH_NAMES[normalizedDate.getMonth()];
|
|
252
|
+
const day = normalizedDate.getDate();
|
|
253
|
+
const year = normalizedDate.getFullYear();
|
|
254
|
+
if (!options?.showTime) {
|
|
255
|
+
return `${month} ${day}, ${year}`;
|
|
256
|
+
}
|
|
257
|
+
const hours = normalizedDate.getHours();
|
|
258
|
+
const minutes = normalizedDate.getMinutes();
|
|
259
|
+
const seconds = normalizedDate.getSeconds();
|
|
260
|
+
const ampm = hours >= 12 ? "PM" : "AM";
|
|
261
|
+
const hours12 = hours % 12 || 12;
|
|
262
|
+
let timeStr = `${hours12}:${pad(minutes)}`;
|
|
263
|
+
if (options.showSeconds) {
|
|
264
|
+
timeStr += `:${pad(seconds)}`;
|
|
265
|
+
}
|
|
266
|
+
timeStr += ` ${ampm}`;
|
|
267
|
+
return `${month} ${day}, ${year} ${timeStr}`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// src/modals/Information.tsx
|
|
271
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
272
|
+
var DEFAULT_TITLE = /* @__PURE__ */ jsxs2(Group2, { gap: "xs", wrap: "nowrap", children: [
|
|
273
|
+
/* @__PURE__ */ jsx2(IconCpu, { size: 20 }),
|
|
274
|
+
/* @__PURE__ */ jsx2("span", { children: "System Information" })
|
|
275
|
+
] });
|
|
276
|
+
function InformationContent({ info }) {
|
|
277
|
+
const colorScheme = useComputedColorScheme();
|
|
278
|
+
const author = info.author ?? DEFAULT_AUTHOR;
|
|
279
|
+
const versionType = info.versionType ?? DEFAULT_VERSION_TYPE;
|
|
280
|
+
const cards = [
|
|
281
|
+
{
|
|
282
|
+
icon: /* @__PURE__ */ jsx2(IconUser, { size: 18 }),
|
|
283
|
+
label: "Author",
|
|
284
|
+
value: author,
|
|
285
|
+
color: "blue"
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
icon: /* @__PURE__ */ jsx2(IconLicense, { size: 18 }),
|
|
289
|
+
label: "License",
|
|
290
|
+
value: info.license ?? DEFAULT_LICENSE,
|
|
291
|
+
color: "orange"
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
icon: /* @__PURE__ */ jsx2(IconMapPin, { size: 18 }),
|
|
295
|
+
label: "Location",
|
|
296
|
+
value: info.location ?? DEFAULT_LOCATION,
|
|
297
|
+
color: "teal"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
icon: /* @__PURE__ */ jsx2(IconTag, { size: 18 }),
|
|
301
|
+
label: "Version Type",
|
|
302
|
+
value: versionType,
|
|
303
|
+
color: "red"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
icon: /* @__PURE__ */ jsx2(IconCalendar, { size: 18 }),
|
|
307
|
+
label: "Build Time",
|
|
308
|
+
value: info.buildTime !== void 0 ? formatAbsoluteAndRelativeTime(info.buildTime) : UNKNOWN,
|
|
309
|
+
color: "green"
|
|
310
|
+
},
|
|
311
|
+
...info.metadata ?? []
|
|
312
|
+
];
|
|
313
|
+
return /* @__PURE__ */ jsxs2(Stack2, { gap: "lg", children: [
|
|
314
|
+
/* @__PURE__ */ jsxs2(Stack2, { gap: "xs", align: "center", children: [
|
|
315
|
+
info.logo,
|
|
316
|
+
/* @__PURE__ */ jsxs2(Stack2, { gap: 2, align: "center", children: [
|
|
317
|
+
/* @__PURE__ */ jsx2(Title, { order: 2, children: info.name }),
|
|
318
|
+
info.tagline && /* @__PURE__ */ jsx2(Text2, { size: "sm", c: "dimmed", w: 600, ta: "center", children: info.tagline })
|
|
319
|
+
] }),
|
|
320
|
+
/* @__PURE__ */ jsxs2(Group2, { gap: "xs", children: [
|
|
321
|
+
info.version && /* @__PURE__ */ jsxs2(
|
|
322
|
+
Badge,
|
|
323
|
+
{
|
|
324
|
+
size: "lg",
|
|
325
|
+
color: "blue",
|
|
326
|
+
variant: "outline",
|
|
327
|
+
mt: "sm",
|
|
328
|
+
tt: "none",
|
|
329
|
+
fw: 600,
|
|
330
|
+
children: [
|
|
331
|
+
"\u2728 v",
|
|
332
|
+
info.version
|
|
333
|
+
]
|
|
334
|
+
}
|
|
335
|
+
),
|
|
336
|
+
/* @__PURE__ */ jsxs2(
|
|
337
|
+
Badge,
|
|
338
|
+
{
|
|
339
|
+
size: "lg",
|
|
340
|
+
color: "teal",
|
|
341
|
+
variant: "light",
|
|
342
|
+
mt: "sm",
|
|
343
|
+
tt: "none",
|
|
344
|
+
fw: 600,
|
|
345
|
+
children: [
|
|
346
|
+
"\u{1F9E9} ",
|
|
347
|
+
versionType
|
|
348
|
+
]
|
|
349
|
+
}
|
|
350
|
+
)
|
|
351
|
+
] })
|
|
352
|
+
] }),
|
|
353
|
+
/* @__PURE__ */ jsx2(Divider, { label: "System Information", labelPosition: "center" }),
|
|
354
|
+
/* @__PURE__ */ jsxs2(SimpleGrid, { cols: { base: 1, sm: 2 }, children: [
|
|
355
|
+
cards.map((card) => /* @__PURE__ */ jsx2(
|
|
356
|
+
InfoCard,
|
|
357
|
+
{
|
|
358
|
+
icon: card.icon ?? /* @__PURE__ */ jsx2(IconAward, { size: 18 }),
|
|
359
|
+
label: card.label,
|
|
360
|
+
value: card.value,
|
|
361
|
+
color: card.color ?? "gray"
|
|
362
|
+
},
|
|
363
|
+
card.label
|
|
364
|
+
)),
|
|
365
|
+
/* @__PURE__ */ jsx2(
|
|
366
|
+
Paper,
|
|
367
|
+
{
|
|
368
|
+
withBorder: true,
|
|
369
|
+
p: "sm",
|
|
370
|
+
radius: "18px",
|
|
371
|
+
bg: colorScheme === "dark" ? "gray.9" : "gray.0",
|
|
372
|
+
children: /* @__PURE__ */ jsxs2(Group2, { justify: "space-between", wrap: "nowrap", children: [
|
|
373
|
+
/* @__PURE__ */ jsxs2(Group2, { gap: "sm", flex: 1, children: [
|
|
374
|
+
/* @__PURE__ */ jsx2(ThemeIcon, { variant: "light", color: "yellow", size: "lg", radius: "14px", children: /* @__PURE__ */ jsx2(IconHash, { size: 18 }) }),
|
|
375
|
+
/* @__PURE__ */ jsxs2(Stack2, { gap: 2, children: [
|
|
376
|
+
/* @__PURE__ */ jsx2(Text2, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: "Build ID" }),
|
|
377
|
+
/* @__PURE__ */ jsx2(Text2, { size: "sm", fw: 500, truncate: true, children: info.buildId ?? UNKNOWN })
|
|
378
|
+
] })
|
|
379
|
+
] }),
|
|
380
|
+
info.buildId && /* @__PURE__ */ jsx2(CopyBuildIdButton, { buildId: info.buildId })
|
|
381
|
+
] })
|
|
382
|
+
}
|
|
383
|
+
)
|
|
384
|
+
] }),
|
|
385
|
+
/* @__PURE__ */ jsx2(
|
|
386
|
+
Footer,
|
|
387
|
+
{
|
|
388
|
+
copyright: info.copyright,
|
|
389
|
+
author,
|
|
390
|
+
authorHref: info.authorHref,
|
|
391
|
+
socialLinks: info.socialLinks
|
|
392
|
+
}
|
|
393
|
+
)
|
|
394
|
+
] });
|
|
395
|
+
}
|
|
396
|
+
function InformationModal({
|
|
397
|
+
opened,
|
|
398
|
+
onClose,
|
|
399
|
+
info,
|
|
400
|
+
title = DEFAULT_TITLE
|
|
401
|
+
}) {
|
|
402
|
+
return /* @__PURE__ */ jsx2(
|
|
403
|
+
Modal,
|
|
404
|
+
{
|
|
405
|
+
opened,
|
|
406
|
+
onClose,
|
|
407
|
+
withCloseButton: true,
|
|
408
|
+
centered: true,
|
|
409
|
+
radius: "lg",
|
|
410
|
+
size: "60%",
|
|
411
|
+
styles: {
|
|
412
|
+
content: {
|
|
413
|
+
maxHeight: "90vh",
|
|
414
|
+
height: "90vh"
|
|
415
|
+
},
|
|
416
|
+
body: {
|
|
417
|
+
flex: 1,
|
|
418
|
+
overflow: "auto"
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
title,
|
|
422
|
+
children: /* @__PURE__ */ jsx2(InformationContent, { info })
|
|
423
|
+
}
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
function CopyBuildIdButton({ buildId }) {
|
|
427
|
+
const [copied, setCopied] = useState(false);
|
|
428
|
+
const handleCopy = async () => {
|
|
429
|
+
const success = await copyToClipboard(buildId);
|
|
430
|
+
if (success) {
|
|
431
|
+
setCopied(true);
|
|
432
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
return /* @__PURE__ */ jsx2(Tooltip2, { label: copied ? "Copied!" : "Copy ID", withArrow: true, children: /* @__PURE__ */ jsx2(
|
|
436
|
+
ActionIcon2,
|
|
437
|
+
{
|
|
438
|
+
variant: "subtle",
|
|
439
|
+
color: copied ? "teal" : "gray",
|
|
440
|
+
onClick: handleCopy,
|
|
441
|
+
children: copied ? /* @__PURE__ */ jsx2(IconCheck, { size: 16 }) : /* @__PURE__ */ jsx2(IconCopy, { size: 16 })
|
|
442
|
+
}
|
|
443
|
+
) });
|
|
444
|
+
}
|
|
445
|
+
function InfoCard({
|
|
446
|
+
icon,
|
|
447
|
+
label,
|
|
448
|
+
value,
|
|
449
|
+
color
|
|
450
|
+
}) {
|
|
451
|
+
const colorScheme = useComputedColorScheme();
|
|
452
|
+
return /* @__PURE__ */ jsx2(Paper, { withBorder: true, p: "md", radius: "18px", h: "100%", bg: colorScheme === "dark" ? "gray.9" : "gray.0", children: /* @__PURE__ */ jsxs2(Group2, { gap: "sm", align: "flex-start", children: [
|
|
453
|
+
/* @__PURE__ */ jsx2(ThemeIcon, { color, variant: "light", size: "lg", radius: "14px", children: icon }),
|
|
454
|
+
/* @__PURE__ */ jsxs2(Stack2, { gap: 2, flex: 1, children: [
|
|
455
|
+
/* @__PURE__ */ jsx2(Text2, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: label }),
|
|
456
|
+
/* @__PURE__ */ jsx2(Text2, { size: "sm", fw: 500, lineClamp: 1, children: value })
|
|
457
|
+
] })
|
|
458
|
+
] }) });
|
|
459
|
+
}
|
|
94
460
|
export {
|
|
95
|
-
|
|
461
|
+
DEFAULT_AUTHOR,
|
|
462
|
+
DEFAULT_AUTHOR_HREF,
|
|
463
|
+
DEFAULT_COPYRIGHT,
|
|
464
|
+
DEFAULT_LICENSE,
|
|
465
|
+
DEFAULT_LOCATION,
|
|
466
|
+
DEFAULT_VERSION_TYPE,
|
|
467
|
+
Footer,
|
|
468
|
+
InformationContent,
|
|
469
|
+
InformationModal,
|
|
470
|
+
UNKNOWN,
|
|
471
|
+
calculateRemainingTime,
|
|
472
|
+
copyToClipboard,
|
|
473
|
+
formatAbsolute,
|
|
474
|
+
formatAbsoluteAndRelativeTime,
|
|
475
|
+
formatHumanDate,
|
|
476
|
+
formatRelativeTime,
|
|
477
|
+
normalizeDate,
|
|
478
|
+
pad
|
|
96
479
|
};
|
|
97
480
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/branding/Footer.tsx"],"sourcesContent":["/***\r\n * OTMC License.\r\n * Copyright (c) 2026 OTMC Softwares. All rights reserved.\r\n * Contributors: Nguyen Van Trung, OTMC Contributors.\r\n***/\r\n\r\nimport { Stack, Group, Text, Anchor, Tooltip, ActionIcon } from '@mantine/core';\r\nimport {\r\n IconCopyright,\r\n IconHeart,\r\n IconBrandFacebook,\r\n IconBrandGithub,\r\n IconMail,\r\n} from '@tabler/icons-react';\r\nimport { ReactNode } from 'react';\r\n\r\nexport interface FooterSocialLink {\r\n label: string;\r\n href: string;\r\n icon: ReactNode;\r\n color?: string;\r\n external?: boolean;\r\n}\r\n\r\nexport interface FooterProps {\r\n copyright?: string;\r\n author?: string;\r\n authorHref?: string;\r\n socialLinks?: FooterSocialLink[];\r\n showCopyright?: boolean;\r\n showAuthor?: boolean;\r\n showSocialLinks?: boolean;\r\n}\r\n\r\nconst DEFAULT_COPYRIGHT = 'OTMC Softwares. All rights reserved.';\r\nconst DEFAULT_AUTHOR = 'Nguyen Van Trung, OTMC Contributors.';\r\nconst DEFAULT_AUTHOR_HREF = 'https://github.com';\r\nconst DEFAULT_SOCIAL_LINKS: FooterSocialLink[] = [\r\n {\r\n label: 'Facebook',\r\n href: 'https://www.facebook.com',\r\n icon: <IconBrandFacebook size={20} />,\r\n color: 'blue.8',\r\n external: true,\r\n },\r\n {\r\n label: 'GitHub',\r\n href: 'https://github.com',\r\n icon: <IconBrandGithub size={20} />,\r\n color: 'gray.6',\r\n external: true,\r\n },\r\n {\r\n label: 'Gmail',\r\n href: 'mailto:test@gmail.com',\r\n icon: <IconMail size={20} />,\r\n color: 'red.8',\r\n external: false,\r\n },\r\n];\r\n\r\nexport function Footer({\r\n copyright = DEFAULT_COPYRIGHT,\r\n author = DEFAULT_AUTHOR,\r\n authorHref = DEFAULT_AUTHOR_HREF,\r\n socialLinks = DEFAULT_SOCIAL_LINKS,\r\n showSocialLinks = true,\r\n}: FooterProps) {\r\n\r\n return (\r\n <Stack gap=\"sm\" mt=\"md\" align=\"center\">\r\n <Stack gap={2} align=\"center\">\r\n <Group gap={4} wrap=\"nowrap\">\r\n <Text c=\"dimmed\" size=\"xs\">\r\n Copyright{' '}\r\n </Text>\r\n <IconCopyright size={15} />\r\n <Text size=\"xs\" c=\"dimmed\">\r\n {new Date().getFullYear()} {copyright}\r\n </Text>\r\n </Group>\r\n <Group gap={4} wrap=\"nowrap\">\r\n <Text size=\"xs\" c=\"dimmed\">\r\n Built with\r\n </Text>\r\n <IconHeart\r\n size={15}\r\n style={{ color: 'var(--mantine-color-red-7)' }}\r\n />\r\n <Text size=\"xs\" c=\"dimmed\">\r\n by\r\n </Text>\r\n <Anchor\r\n href={authorHref}\r\n size=\"xs\"\r\n fw={500}\r\n target=\"_blank\"\r\n >\r\n {author}\r\n </Anchor>\r\n </Group>\r\n </Stack>\r\n\r\n {showSocialLinks && socialLinks.length > 0 && (\r\n <Group gap=\"sm\">\r\n {socialLinks.map((link) => (\r\n <Tooltip key={link.href} label={link.label} withArrow>\r\n <ActionIcon\r\n variant=\"subtle\"\r\n color={link.color}\r\n component=\"a\"\r\n href={link.href}\r\n target={link.external ? '_blank' : undefined}\r\n rel={link.external ? 'noopener noreferrer' : undefined}\r\n >\r\n {link.icon}\r\n </ActionIcon>\r\n </Tooltip>\r\n ))}\r\n </Group>\r\n )}\r\n </Stack>\r\n );\r\n}\r\n\r\n"],"mappings":";AAMA,SAAS,OAAO,OAAO,MAAM,QAAQ,SAAS,kBAAkB;AAChE;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA4BG,cAgCA,YAhCA;AAPV,IAAM,oBAAoB;AAC1B,IAAM,iBAAiB;AACvB,IAAM,sBAAsB;AAC5B,IAAM,uBAA2C;AAAA,EAC/C;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM,oBAAC,qBAAkB,MAAM,IAAI;AAAA,IACnC,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM,oBAAC,mBAAgB,MAAM,IAAI;AAAA,IACjC,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM,oBAAC,YAAS,MAAM,IAAI;AAAA,IAC1B,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AACF;AAEO,SAAS,OAAO;AAAA,EACrB,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,aAAa;AAAA,EACb,cAAc;AAAA,EACd,kBAAkB;AACpB,GAAgB;AAEd,SACE,qBAAC,SAAM,KAAI,MAAK,IAAG,MAAK,OAAM,UAC5B;AAAA,yBAAC,SAAM,KAAK,GAAG,OAAM,UACnB;AAAA,2BAAC,SAAM,KAAK,GAAG,MAAK,UAClB;AAAA,6BAAC,QAAK,GAAE,UAAS,MAAK,MAAK;AAAA;AAAA,UACf;AAAA,WACZ;AAAA,QACA,oBAAC,iBAAc,MAAM,IAAI;AAAA,QACzB,qBAAC,QAAK,MAAK,MAAK,GAAE,UACf;AAAA,+BAAI,KAAK,GAAE,YAAY;AAAA,UAAE;AAAA,UAAE;AAAA,WAC9B;AAAA,SACF;AAAA,MACA,qBAAC,SAAM,KAAK,GAAG,MAAK,UAClB;AAAA,4BAAC,QAAK,MAAK,MAAK,GAAE,UAAS,wBAE3B;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,OAAO,EAAE,OAAO,6BAA6B;AAAA;AAAA,QAC/C;AAAA,QACA,oBAAC,QAAK,MAAK,MAAK,GAAE,UAAS,gBAE3B;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,MAAK;AAAA,YACL,IAAI;AAAA,YACJ,QAAO;AAAA,YAEN;AAAA;AAAA,QACH;AAAA,SACF;AAAA,OACF;AAAA,IAEC,mBAAmB,YAAY,SAAS,KACvC,oBAAC,SAAM,KAAI,MACR,sBAAY,IAAI,CAAC,SAChB,oBAAC,WAAwB,OAAO,KAAK,OAAO,WAAS,MACnD;AAAA,MAAC;AAAA;AAAA,QACC,SAAQ;AAAA,QACR,OAAO,KAAK;AAAA,QACZ,WAAU;AAAA,QACV,MAAM,KAAK;AAAA,QACX,QAAQ,KAAK,WAAW,WAAW;AAAA,QACnC,KAAK,KAAK,WAAW,wBAAwB;AAAA,QAE5C,eAAK;AAAA;AAAA,IACR,KAVY,KAAK,IAWnB,CACD,GACH;AAAA,KAEJ;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/branding/Footer.tsx","../src/utils/constants.ts","../src/modals/Information.tsx","../src/utils/commonUtils.ts","../src/utils/timeUtils.ts"],"sourcesContent":["/***\r\n * OTMC License.\r\n * Copyright (c) 2026 OTMC Softwares. All rights reserved.\r\n * Contributors: Nguyen Van Trung, OTMC Contributors.\r\n***/\r\n\r\nimport { Stack, Group, Text, Anchor, Tooltip, ActionIcon } from '@mantine/core';\r\nimport {\r\n IconCopyright,\r\n IconHeart,\r\n IconBrandFacebook,\r\n IconBrandGithub,\r\n IconMail,\r\n} from '@tabler/icons-react';\r\nimport { ReactNode } from 'react';\r\n\r\nimport {\r\n DEFAULT_AUTHOR,\r\n DEFAULT_AUTHOR_HREF,\r\n DEFAULT_COPYRIGHT,\r\n} from '../utils/constants';\r\n\r\nexport interface FooterSocialLink {\r\n label: string;\r\n href: string;\r\n icon: ReactNode;\r\n color?: string;\r\n external?: boolean;\r\n}\r\n\r\nexport interface FooterProps {\r\n copyright?: string;\r\n author?: string;\r\n authorHref?: string;\r\n socialLinks?: FooterSocialLink[];\r\n showCopyright?: boolean;\r\n showAuthor?: boolean;\r\n showSocialLinks?: boolean;\r\n}\r\n\r\nconst DEFAULT_SOCIAL_LINKS: FooterSocialLink[] = [\r\n {\r\n label: 'Facebook',\r\n href: 'https://www.facebook.com',\r\n icon: <IconBrandFacebook size={20} />,\r\n color: 'blue.8',\r\n external: true,\r\n },\r\n {\r\n label: 'GitHub',\r\n href: 'https://github.com',\r\n icon: <IconBrandGithub size={20} />,\r\n color: 'gray.6',\r\n external: true,\r\n },\r\n {\r\n label: 'Gmail',\r\n href: 'mailto:test@gmail.com',\r\n icon: <IconMail size={20} />,\r\n color: 'red.8',\r\n external: false,\r\n },\r\n];\r\n\r\nexport function Footer({\r\n copyright = DEFAULT_COPYRIGHT,\r\n author = DEFAULT_AUTHOR,\r\n authorHref = DEFAULT_AUTHOR_HREF,\r\n socialLinks = DEFAULT_SOCIAL_LINKS,\r\n showSocialLinks = true,\r\n}: FooterProps) {\r\n\r\n return (\r\n <Stack gap=\"sm\" mt=\"md\" align=\"center\">\r\n <Stack gap={2} align=\"center\">\r\n <Group gap={4} wrap=\"nowrap\">\r\n <Text c=\"dimmed\" size=\"xs\">\r\n Copyright{' '}\r\n </Text>\r\n <IconCopyright size={15} />\r\n <Text size=\"xs\" c=\"dimmed\">\r\n {new Date().getFullYear()} {copyright}\r\n </Text>\r\n </Group>\r\n <Group gap={4} wrap=\"nowrap\">\r\n <Text size=\"xs\" c=\"dimmed\">\r\n Built with\r\n </Text>\r\n <IconHeart\r\n size={15}\r\n style={{ color: 'var(--mantine-color-red-7)' }}\r\n />\r\n <Text size=\"xs\" c=\"dimmed\">\r\n by\r\n </Text>\r\n <Anchor\r\n href={authorHref}\r\n size=\"xs\"\r\n fw={500}\r\n target=\"_blank\"\r\n >\r\n {author}\r\n </Anchor>\r\n </Group>\r\n </Stack>\r\n\r\n {showSocialLinks && socialLinks.length > 0 && (\r\n <Group gap=\"sm\">\r\n {socialLinks.map((link) => (\r\n <Tooltip key={link.href} label={link.label} withArrow>\r\n <ActionIcon\r\n variant=\"subtle\"\r\n color={link.color}\r\n component=\"a\"\r\n href={link.href}\r\n target={link.external ? '_blank' : undefined}\r\n rel={link.external ? 'noopener noreferrer' : undefined}\r\n >\r\n {link.icon}\r\n </ActionIcon>\r\n </Tooltip>\r\n ))}\r\n </Group>\r\n )}\r\n </Stack>\r\n );\r\n}\r\n\r\n","/**\r\n * @License OTMC License\r\n * @Copyright (c) 2026 OTMC Softwares. All rights reserved.\r\n * @Contributors Trung Ng, OTMC Authors.\r\n**/\r\n\r\nexport const DEFAULT_AUTHOR = 'Nguyen Van Trung, OTMC Contributors.';\r\nexport const DEFAULT_AUTHOR_HREF = 'https://github.com/otmc-sw';\r\nexport const DEFAULT_COPYRIGHT = 'OTMC Softwares. All rights reserved.';\r\nexport const DEFAULT_LICENSE = 'OTMC License.';\r\nexport const DEFAULT_LOCATION = 'An Nhon, Gia Lai, Viet Nam.';\r\nexport const DEFAULT_VERSION_TYPE = 'Internal';\r\nexport const UNKNOWN = 'Unknown';\r\n","/***\n * OTMC License.\n * Copyright (c) 2026 OTMC Softwares. All rights reserved.\n * Contributors: Nguyen Van Trung, OTMC Contributors.\n***/\n\nimport { useState, type ReactNode } from 'react';\nimport {\n Modal,\n Stack,\n Title,\n Text,\n Group,\n Divider,\n Badge,\n ThemeIcon,\n SimpleGrid,\n Paper,\n ActionIcon,\n Tooltip,\n useComputedColorScheme,\n} from '@mantine/core';\nimport {\n IconAward,\n IconCalendar,\n IconCheck,\n IconCopy,\n IconCpu,\n IconHash,\n IconLicense,\n IconMapPin,\n IconTag,\n IconUser,\n} from '@tabler/icons-react';\n\nimport { Footer, type FooterSocialLink } from '../branding';\nimport { copyToClipboard } from '../utils/commonUtils';\nimport {\n DEFAULT_AUTHOR,\n DEFAULT_LICENSE,\n DEFAULT_LOCATION,\n DEFAULT_VERSION_TYPE,\n UNKNOWN,\n} from '../utils/constants';\nimport { formatAbsoluteAndRelativeTime } from '../utils/timeUtils';\n\nexport interface InformationMetadata {\n icon?: ReactNode;\n label: string;\n value: string;\n color?: string;\n}\n\nexport interface ApplicationInfo {\n name: string;\n version?: string;\n versionType?: string;\n tagline?: string;\n logo?: ReactNode;\n author?: string;\n authorHref?: string;\n license?: string;\n location?: string;\n copyright?: string;\n buildId?: string;\n buildTime?: string | number | Date;\n metadata?: InformationMetadata[];\n socialLinks?: FooterSocialLink[];\n}\n\nexport interface InformationContentProps {\n info: ApplicationInfo;\n}\n\nexport interface InformationModalProps {\n opened: boolean;\n onClose: () => void;\n info: ApplicationInfo;\n title?: ReactNode;\n}\n\nconst DEFAULT_TITLE = (\n <Group gap=\"xs\" wrap=\"nowrap\">\n <IconCpu size={20} />\n <span>System Information</span>\n </Group>\n);\n\n\nexport function InformationContent({ info }: InformationContentProps) {\n const colorScheme = useComputedColorScheme();\n\n const author = info.author ?? DEFAULT_AUTHOR;\n const versionType = info.versionType ?? DEFAULT_VERSION_TYPE;\n\n const cards: InformationMetadata[] = [\n {\n icon: <IconUser size={18} />,\n label: 'Author',\n value: author,\n color: 'blue',\n },\n {\n icon: <IconLicense size={18} />,\n label: 'License',\n value: info.license ?? DEFAULT_LICENSE,\n color: 'orange',\n },\n {\n icon: <IconMapPin size={18} />,\n label: 'Location',\n value: info.location ?? DEFAULT_LOCATION,\n color: 'teal',\n },\n {\n icon: <IconTag size={18} />,\n label: 'Version Type',\n value: versionType,\n color: 'red',\n },\n {\n icon: <IconCalendar size={18} />,\n label: 'Build Time',\n value:\n info.buildTime !== undefined\n ? formatAbsoluteAndRelativeTime(info.buildTime)\n : UNKNOWN,\n color: 'green',\n },\n ...(info.metadata ?? []),\n ];\n\n return (\n <Stack gap=\"lg\">\n <Stack gap=\"xs\" align=\"center\">\n {info.logo}\n\n <Stack gap={2} align=\"center\">\n <Title order={2}>{info.name}</Title>\n {info.tagline && (\n <Text size=\"sm\" c=\"dimmed\" w={600} ta=\"center\">\n {info.tagline}\n </Text>\n )}\n </Stack>\n\n <Group gap=\"xs\">\n {info.version && (\n <Badge\n size=\"lg\"\n color=\"blue\"\n variant=\"outline\"\n mt=\"sm\"\n tt=\"none\"\n fw={600}\n >\n ✨ v{info.version}\n </Badge>\n )}\n <Badge\n size=\"lg\"\n color=\"teal\"\n variant=\"light\"\n mt=\"sm\"\n tt=\"none\"\n fw={600}\n >\n 🧩 {versionType}\n </Badge>\n </Group>\n </Stack>\n\n <Divider label=\"System Information\" labelPosition=\"center\" />\n\n <SimpleGrid cols={{ base: 1, sm: 2 }}>\n {cards.map((card) => (\n <InfoCard\n key={card.label}\n icon={card.icon ?? <IconAward size={18} />}\n label={card.label}\n value={card.value}\n color={card.color ?? 'gray'}\n />\n ))}\n\n <Paper\n withBorder\n p=\"sm\"\n radius=\"18px\"\n bg={colorScheme === 'dark' ? 'gray.9' : 'gray.0'}\n >\n <Group justify=\"space-between\" wrap=\"nowrap\">\n <Group gap=\"sm\" flex={1}>\n <ThemeIcon variant=\"light\" color=\"yellow\" size=\"lg\" radius=\"14px\">\n <IconHash size={18} />\n </ThemeIcon>\n\n <Stack gap={2}>\n <Text size=\"xs\" c=\"dimmed\" fw={700} tt=\"uppercase\">\n Build ID\n </Text>\n <Text size=\"sm\" fw={500} truncate>\n {info.buildId ?? UNKNOWN}\n </Text>\n </Stack>\n </Group>\n\n {info.buildId && <CopyBuildIdButton buildId={info.buildId} />}\n </Group>\n </Paper>\n </SimpleGrid>\n\n <Footer\n copyright={info.copyright}\n author={author}\n authorHref={info.authorHref}\n socialLinks={info.socialLinks}\n />\n </Stack>\n );\n}\n\nexport function InformationModal({\n opened,\n onClose,\n info,\n title = DEFAULT_TITLE,\n}: InformationModalProps) {\n return (\n <Modal\n opened={opened}\n onClose={onClose}\n withCloseButton\n centered\n radius=\"lg\"\n size=\"60%\"\n styles={{\n content: {\n maxHeight: '90vh',\n height: '90vh',\n },\n body: {\n flex: 1,\n overflow: 'auto',\n },\n }}\n title={title}\n >\n <InformationContent info={info} />\n </Modal>\n );\n}\n\nfunction CopyBuildIdButton({ buildId }: { buildId: string }) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = async () => {\n const success = await copyToClipboard(buildId);\n if (success) {\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }\n };\n\n return (\n <Tooltip label={copied ? 'Copied!' : 'Copy ID'} withArrow>\n <ActionIcon\n variant=\"subtle\"\n color={copied ? 'teal' : 'gray'}\n onClick={handleCopy}\n >\n {copied ? <IconCheck size={16} /> : <IconCopy size={16} />}\n </ActionIcon>\n </Tooltip>\n );\n}\n\nfunction InfoCard({\n icon,\n label,\n value,\n color,\n}: {\n icon: ReactNode;\n label: string;\n value: string;\n color: string;\n}) {\n const colorScheme = useComputedColorScheme();\n return (\n <Paper withBorder p=\"md\" radius=\"18px\" h=\"100%\" bg={colorScheme === 'dark' ? 'gray.9' : 'gray.0'}>\n <Group gap=\"sm\" align=\"flex-start\">\n <ThemeIcon color={color} variant=\"light\" size=\"lg\" radius=\"14px\">\n {icon}\n </ThemeIcon>\n\n <Stack gap={2} flex={1}>\n <Text size=\"xs\" c=\"dimmed\" fw={700} tt=\"uppercase\">\n {label}\n </Text>\n <Text size=\"sm\" fw={500} lineClamp={1}>\n {value}\n </Text>\n </Stack>\n </Group>\n </Paper>\n );\n}\n\n","/**\n * @License OTMC License\n * @Copyright (c) 2026 OTMC Softwares. All rights reserved.\n * @Contributors Trung Ng, OTMC Authors.\n**/\nexport const copyToClipboard = async (text: string): Promise<boolean> => {\n try {\n if (navigator.clipboard && window.isSecureContext) {\n await navigator.clipboard.writeText(text);\n return true;\n }\n \n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.position = 'fixed';\n textarea.style.left = '-9999px';\n textarea.style.top = '-9999px';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n textarea.focus();\n textarea.select();\n \n const success = document.execCommand('copy');\n document.body.removeChild(textarea);\n \n return success;\n } catch (err) {\n console.error('Failed to copy to clipboard:', err);\n return false;\n }\n};\n","/**\n * @License OTMC License\n * @Copyright (c) 2026 OTMC Softwares. All rights reserved.\n * @Contributors Trung Ng, OTMC Authors.\n**/\n\nexport type TimestampFormatType = \"absolute\" | \"relative\";\n\n\nexport function normalizeDate(dateInput: string | number | Date): Date | null {\n if (dateInput instanceof Date) {\n return isNaN(dateInput.getTime()) ? null : dateInput;\n }\n\n if (typeof dateInput === 'string') {\n const date = new Date(dateInput);\n return isNaN(date.getTime()) ? null : date;\n }\n\n if (typeof dateInput === 'number') {\n const timestamp = dateInput < 1e12 ? dateInput * 1000 : dateInput;\n const date = new Date(timestamp);\n return isNaN(date.getTime()) ? null : date;\n }\n\n return null;\n}\n\nexport function pad(n: number, width: number = 2): string {\n return String(n).padStart(width, \"0\");\n}\n\nexport function formatAbsolute(date: Date): string {\n const tz = -date.getTimezoneOffset();\n const sign = tz >= 0 ? \"+\" : \"-\";\n \n return (\n `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +\n `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())} ` +\n `${sign}${pad(Math.floor(Math.abs(tz) / 60))}:${pad(Math.abs(tz) % 60)}`\n );\n}\n\nexport function formatRelativeTime(date: string | number | Date): string {\n const normalizedDate = normalizeDate(date);\n if (!normalizedDate) return \"Invalid date\";\n\n const now = Date.now();\n const diffMs = now - normalizedDate.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n\n if (diffSeconds < 0) {\n return \"Just now\";\n }\n\n if (diffSeconds < 60) {\n return \"Just now\";\n }\n\n const minute = 60;\n const hour = minute * 60;\n const day = hour * 24;\n const week = day * 7;\n const month = day * 30;\n const year = day * 365;\n\n if (diffSeconds < hour) {\n const mins = Math.floor(diffSeconds / minute);\n return `${mins} min${mins !== 1 ? 's' : ''} ago`;\n } else if (diffSeconds < day) {\n const hours = Math.floor(diffSeconds / hour);\n return `${hours} hour${hours !== 1 ? 's' : ''} ago`;\n } else if (diffSeconds < week) {\n const days = Math.floor(diffSeconds / day);\n return `${days} day${days !== 1 ? 's' : ''} ago`;\n } else if (diffSeconds < month) {\n const weeks = Math.floor(diffSeconds / week);\n return `${weeks} week${weeks !== 1 ? 's' : ''} ago`;\n } else if (diffSeconds < year) {\n const months = Math.floor(diffSeconds / month);\n return `${months} month${months !== 1 ? 's' : ''} ago`;\n } else {\n const years = Math.floor(diffSeconds / year);\n return `${years} year${years !== 1 ? 's' : ''} ago`;\n }\n}\n\nexport function formatAbsoluteAndRelativeTime(date: string | number | Date): string {\n const normalizedDate = normalizeDate(date);\n if (!normalizedDate) return \"Invalid date\";\n\n const absoluteTime = formatAbsolute(normalizedDate);\n const relativeTime = formatRelativeTime(normalizedDate);\n\n return `${absoluteTime} (${relativeTime})`;\n}\n\nexport function calculateRemainingTime(targetDate: string | number | Date | undefined): string {\n if (!targetDate) return 'Not set';\n\n const normalizedDate = normalizeDate(targetDate);\n if (!normalizedDate) return 'Invalid date';\n\n const now = new Date();\n const diffMs = normalizedDate.getTime() - now.getTime();\n\n if (diffMs < 0) {\n const daysOverdue = Math.floor(Math.abs(diffMs) / (1000 * 60 * 60 * 24));\n return `Overdue ${daysOverdue}d`;\n }\n\n const days = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n const hours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));\n\n if (days > 0) {\n return `${days}d ${hours}h`;\n } else if (hours > 0) {\n return `${hours}h`;\n } else {\n return '< 1h';\n }\n}\n\nconst MONTH_NAMES = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\nexport function formatHumanDate(date: string | number | Date, options?: { showTime?: boolean; showSeconds?: boolean }): string {\n const normalizedDate = normalizeDate(date);\n if (!normalizedDate) return 'Invalid date';\n\n const month = MONTH_NAMES[normalizedDate.getMonth()];\n const day = normalizedDate.getDate();\n const year = normalizedDate.getFullYear();\n\n if (!options?.showTime) {\n return `${month} ${day}, ${year}`;\n }\n\n const hours = normalizedDate.getHours();\n const minutes = normalizedDate.getMinutes();\n const seconds = normalizedDate.getSeconds();\n const ampm = hours >= 12 ? 'PM' : 'AM';\n const hours12 = hours % 12 || 12;\n\n let timeStr = `${hours12}:${pad(minutes)}`;\n if (options.showSeconds) {\n timeStr += `:${pad(seconds)}`;\n }\n timeStr += ` ${ampm}`;\n\n return `${month} ${day}, ${year} ${timeStr}`;\n}\n\n"],"mappings":";AAMA,SAAS,OAAO,OAAO,MAAM,QAAQ,SAAS,kBAAkB;AAChE;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACPA,IAAM,iBAAiB;AACvB,IAAM,sBAAsB;AAC5B,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AACxB,IAAM,mBAAmB;AACzB,IAAM,uBAAuB;AAC7B,IAAM,UAAU;;;ADgCb,cAgCA,YAhCA;AAJV,IAAM,uBAA2C;AAAA,EAC/C;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM,oBAAC,qBAAkB,MAAM,IAAI;AAAA,IACnC,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM,oBAAC,mBAAgB,MAAM,IAAI;AAAA,IACjC,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM,oBAAC,YAAS,MAAM,IAAI;AAAA,IAC1B,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AACF;AAEO,SAAS,OAAO;AAAA,EACrB,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,aAAa;AAAA,EACb,cAAc;AAAA,EACd,kBAAkB;AACpB,GAAgB;AAEd,SACE,qBAAC,SAAM,KAAI,MAAK,IAAG,MAAK,OAAM,UAC5B;AAAA,yBAAC,SAAM,KAAK,GAAG,OAAM,UACnB;AAAA,2BAAC,SAAM,KAAK,GAAG,MAAK,UAClB;AAAA,6BAAC,QAAK,GAAE,UAAS,MAAK,MAAK;AAAA;AAAA,UACf;AAAA,WACZ;AAAA,QACA,oBAAC,iBAAc,MAAM,IAAI;AAAA,QACzB,qBAAC,QAAK,MAAK,MAAK,GAAE,UACf;AAAA,+BAAI,KAAK,GAAE,YAAY;AAAA,UAAE;AAAA,UAAE;AAAA,WAC9B;AAAA,SACF;AAAA,MACA,qBAAC,SAAM,KAAK,GAAG,MAAK,UAClB;AAAA,4BAAC,QAAK,MAAK,MAAK,GAAE,UAAS,wBAE3B;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,OAAO,EAAE,OAAO,6BAA6B;AAAA;AAAA,QAC/C;AAAA,QACA,oBAAC,QAAK,MAAK,MAAK,GAAE,UAAS,gBAE3B;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,MAAK;AAAA,YACL,IAAI;AAAA,YACJ,QAAO;AAAA,YAEN;AAAA;AAAA,QACH;AAAA,SACF;AAAA,OACF;AAAA,IAEC,mBAAmB,YAAY,SAAS,KACvC,oBAAC,SAAM,KAAI,MACR,sBAAY,IAAI,CAAC,SAChB,oBAAC,WAAwB,OAAO,KAAK,OAAO,WAAS,MACnD;AAAA,MAAC;AAAA;AAAA,QACC,SAAQ;AAAA,QACR,OAAO,KAAK;AAAA,QACZ,WAAU;AAAA,QACV,MAAM,KAAK;AAAA,QACX,QAAQ,KAAK,WAAW,WAAW;AAAA,QACnC,KAAK,KAAK,WAAW,wBAAwB;AAAA,QAE5C,eAAK;AAAA;AAAA,IACR,KAVY,KAAK,IAWnB,CACD,GACH;AAAA,KAEJ;AAEJ;;;AExHA,SAAS,gBAAgC;AACzC;AAAA,EACE;AAAA,EACA,SAAAA;AAAA,EACA;AAAA,EACA,QAAAC;AAAA,EACA,SAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAAC;AAAA,EACA,WAAAC;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;AC5BA,IAAM,kBAAkB,OAAO,SAAmC;AACvE,MAAI;AACF,QAAI,UAAU,aAAa,OAAO,iBAAiB;AACjD,YAAM,UAAU,UAAU,UAAU,IAAI;AACxC,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,SAAS,cAAc,UAAU;AAClD,aAAS,QAAQ;AACjB,aAAS,MAAM,WAAW;AAC1B,aAAS,MAAM,OAAO;AACtB,aAAS,MAAM,MAAM;AACrB,aAAS,MAAM,UAAU;AACzB,aAAS,KAAK,YAAY,QAAQ;AAClC,aAAS,MAAM;AACf,aAAS,OAAO;AAEhB,UAAM,UAAU,SAAS,YAAY,MAAM;AAC3C,aAAS,KAAK,YAAY,QAAQ;AAElC,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,YAAQ,MAAM,gCAAgC,GAAG;AACjD,WAAO;AAAA,EACT;AACF;;;ACrBO,SAAS,cAAc,WAAgD;AAC5E,MAAI,qBAAqB,MAAM;AAC7B,WAAO,MAAM,UAAU,QAAQ,CAAC,IAAI,OAAO;AAAA,EAC7C;AAEA,MAAI,OAAO,cAAc,UAAU;AACjC,UAAM,OAAO,IAAI,KAAK,SAAS;AAC/B,WAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;AAAA,EACxC;AAEA,MAAI,OAAO,cAAc,UAAU;AACjC,UAAM,YAAY,YAAY,OAAO,YAAY,MAAO;AACxD,UAAM,OAAO,IAAI,KAAK,SAAS;AAC/B,WAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;AAAA,EACxC;AAEA,SAAO;AACT;AAEO,SAAS,IAAI,GAAW,QAAgB,GAAW;AACxD,SAAO,OAAO,CAAC,EAAE,SAAS,OAAO,GAAG;AACtC;AAEO,SAAS,eAAe,MAAoB;AACjD,QAAM,KAAK,CAAC,KAAK,kBAAkB;AACnC,QAAM,OAAO,MAAM,IAAI,MAAM;AAE7B,SACE,GAAG,KAAK,YAAY,CAAC,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC,IACrE,IAAI,KAAK,SAAS,CAAC,CAAC,IAAI,IAAI,KAAK,WAAW,CAAC,CAAC,IAAI,IAAI,KAAK,WAAW,CAAC,CAAC,IACxE,IAAI,GAAG,IAAI,KAAK,MAAM,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC;AAE1E;AAEO,SAAS,mBAAmB,MAAsC;AACvE,QAAM,iBAAiB,cAAc,IAAI;AACzC,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,SAAS,MAAM,eAAe,QAAQ;AAC5C,QAAM,cAAc,KAAK,MAAM,SAAS,GAAI;AAE5C,MAAI,cAAc,GAAG;AACnB,WAAO;AAAA,EACT;AAEA,MAAI,cAAc,IAAI;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS;AACf,QAAM,OAAO,SAAS;AACtB,QAAM,MAAM,OAAO;AACnB,QAAM,OAAO,MAAM;AACnB,QAAM,QAAQ,MAAM;AACpB,QAAM,OAAO,MAAM;AAEnB,MAAI,cAAc,MAAM;AACtB,UAAM,OAAO,KAAK,MAAM,cAAc,MAAM;AAC5C,WAAO,GAAG,IAAI,OAAO,SAAS,IAAI,MAAM,EAAE;AAAA,EAC5C,WAAW,cAAc,KAAK;AAC5B,UAAM,QAAQ,KAAK,MAAM,cAAc,IAAI;AAC3C,WAAO,GAAG,KAAK,QAAQ,UAAU,IAAI,MAAM,EAAE;AAAA,EAC/C,WAAW,cAAc,MAAM;AAC7B,UAAM,OAAO,KAAK,MAAM,cAAc,GAAG;AACzC,WAAO,GAAG,IAAI,OAAO,SAAS,IAAI,MAAM,EAAE;AAAA,EAC5C,WAAW,cAAc,OAAO;AAC9B,UAAM,QAAQ,KAAK,MAAM,cAAc,IAAI;AAC3C,WAAO,GAAG,KAAK,QAAQ,UAAU,IAAI,MAAM,EAAE;AAAA,EAC/C,WAAW,cAAc,MAAM;AAC7B,UAAM,SAAS,KAAK,MAAM,cAAc,KAAK;AAC7C,WAAO,GAAG,MAAM,SAAS,WAAW,IAAI,MAAM,EAAE;AAAA,EAClD,OAAO;AACL,UAAM,QAAQ,KAAK,MAAM,cAAc,IAAI;AAC3C,WAAO,GAAG,KAAK,QAAQ,UAAU,IAAI,MAAM,EAAE;AAAA,EAC/C;AACF;AAEO,SAAS,8BAA8B,MAAsC;AAClF,QAAM,iBAAiB,cAAc,IAAI;AACzC,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,eAAe,eAAe,cAAc;AAClD,QAAM,eAAe,mBAAmB,cAAc;AAEtD,SAAO,GAAG,YAAY,KAAK,YAAY;AACzC;AAEO,SAAS,uBAAuB,YAAwD;AAC7F,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,iBAAiB,cAAc,UAAU;AAC/C,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,SAAS,eAAe,QAAQ,IAAI,IAAI,QAAQ;AAEtD,MAAI,SAAS,GAAG;AACd,UAAM,cAAc,KAAK,MAAM,KAAK,IAAI,MAAM,KAAK,MAAO,KAAK,KAAK,GAAG;AACvE,WAAO,WAAW,WAAW;AAAA,EAC/B;AAEA,QAAM,OAAO,KAAK,MAAM,UAAU,MAAO,KAAK,KAAK,GAAG;AACtD,QAAM,QAAQ,KAAK,MAAO,UAAU,MAAO,KAAK,KAAK,OAAQ,MAAO,KAAK,GAAG;AAE5E,MAAI,OAAO,GAAG;AACZ,WAAO,GAAG,IAAI,KAAK,KAAK;AAAA,EAC1B,WAAW,QAAQ,GAAG;AACpB,WAAO,GAAG,KAAK;AAAA,EACjB,OAAO;AACL,WAAO;AAAA,EACT;AACF;AAEA,IAAM,cAAc,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;AAEhG,SAAS,gBAAgB,MAA8B,SAAiE;AAC7H,QAAM,iBAAiB,cAAc,IAAI;AACzC,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,QAAQ,YAAY,eAAe,SAAS,CAAC;AACnD,QAAM,MAAM,eAAe,QAAQ;AACnC,QAAM,OAAO,eAAe,YAAY;AAExC,MAAI,CAAC,SAAS,UAAU;AACtB,WAAO,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI;AAAA,EACjC;AAEA,QAAM,QAAQ,eAAe,SAAS;AACtC,QAAM,UAAU,eAAe,WAAW;AAC1C,QAAM,UAAU,eAAe,WAAW;AAC1C,QAAM,OAAO,SAAS,KAAK,OAAO;AAClC,QAAM,UAAU,QAAQ,MAAM;AAE9B,MAAI,UAAU,GAAG,OAAO,IAAI,IAAI,OAAO,CAAC;AACxC,MAAI,QAAQ,aAAa;AACvB,eAAW,IAAI,IAAI,OAAO,CAAC;AAAA,EAC7B;AACA,aAAW,IAAI,IAAI;AAEnB,SAAO,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO;AAC5C;;;AFpEE,SACE,OAAAC,MADF,QAAAC,aAAA;AADF,IAAM,gBACJ,gBAAAA,MAACC,QAAA,EAAM,KAAI,MAAK,MAAK,UACnB;AAAA,kBAAAF,KAAC,WAAQ,MAAM,IAAI;AAAA,EACnB,gBAAAA,KAAC,UAAK,gCAAkB;AAAA,GAC1B;AAIK,SAAS,mBAAmB,EAAE,KAAK,GAA4B;AACpE,QAAM,cAAc,uBAAuB;AAE3C,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,cAAc,KAAK,eAAe;AAExC,QAAM,QAA+B;AAAA,IACnC;AAAA,MACE,MAAM,gBAAAA,KAAC,YAAS,MAAM,IAAI;AAAA,MAC1B,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAM,gBAAAA,KAAC,eAAY,MAAM,IAAI;AAAA,MAC7B,OAAO;AAAA,MACP,OAAO,KAAK,WAAW;AAAA,MACvB,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAM,gBAAAA,KAAC,cAAW,MAAM,IAAI;AAAA,MAC5B,OAAO;AAAA,MACP,OAAO,KAAK,YAAY;AAAA,MACxB,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAM,gBAAAA,KAAC,WAAQ,MAAM,IAAI;AAAA,MACzB,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,MAAM,gBAAAA,KAAC,gBAAa,MAAM,IAAI;AAAA,MAC9B,OAAO;AAAA,MACP,OACE,KAAK,cAAc,SACf,8BAA8B,KAAK,SAAS,IAC5C;AAAA,MACN,OAAO;AAAA,IACT;AAAA,IACA,GAAI,KAAK,YAAY,CAAC;AAAA,EACxB;AAEA,SACE,gBAAAC,MAACE,QAAA,EAAM,KAAI,MACT;AAAA,oBAAAF,MAACE,QAAA,EAAM,KAAI,MAAK,OAAM,UACnB;AAAA,WAAK;AAAA,MAEN,gBAAAF,MAACE,QAAA,EAAM,KAAK,GAAG,OAAM,UACnB;AAAA,wBAAAH,KAAC,SAAM,OAAO,GAAI,eAAK,MAAK;AAAA,QAC3B,KAAK,WACJ,gBAAAA,KAACI,OAAA,EAAK,MAAK,MAAK,GAAE,UAAS,GAAG,KAAK,IAAG,UACnC,eAAK,SACR;AAAA,SAEJ;AAAA,MAEA,gBAAAH,MAACC,QAAA,EAAM,KAAI,MACR;AAAA,aAAK,WACJ,gBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAM;AAAA,YACN,SAAQ;AAAA,YACR,IAAG;AAAA,YACH,IAAG;AAAA,YACH,IAAI;AAAA,YACL;AAAA;AAAA,cACI,KAAK;AAAA;AAAA;AAAA,QACV;AAAA,QAEF,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAM;AAAA,YACN,SAAQ;AAAA,YACR,IAAG;AAAA,YACH,IAAG;AAAA,YACH,IAAI;AAAA,YACL;AAAA;AAAA,cACK;AAAA;AAAA;AAAA,QACN;AAAA,SACF;AAAA,OACF;AAAA,IAEA,gBAAAD,KAAC,WAAQ,OAAM,sBAAqB,eAAc,UAAS;AAAA,IAE3D,gBAAAC,MAAC,cAAW,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,GAChC;AAAA,YAAM,IAAI,CAAC,SACV,gBAAAD;AAAA,QAAC;AAAA;AAAA,UAEC,MAAM,KAAK,QAAQ,gBAAAA,KAAC,aAAU,MAAM,IAAI;AAAA,UACxC,OAAO,KAAK;AAAA,UACZ,OAAO,KAAK;AAAA,UACZ,OAAO,KAAK,SAAS;AAAA;AAAA,QAJhB,KAAK;AAAA,MAKZ,CACD;AAAA,MAED,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,YAAU;AAAA,UACV,GAAE;AAAA,UACF,QAAO;AAAA,UACP,IAAI,gBAAgB,SAAS,WAAW;AAAA,UAExC,0BAAAC,MAACC,QAAA,EAAM,SAAQ,iBAAgB,MAAK,UAClC;AAAA,4BAAAD,MAACC,QAAA,EAAM,KAAI,MAAK,MAAM,GACpB;AAAA,8BAAAF,KAAC,aAAU,SAAQ,SAAQ,OAAM,UAAS,MAAK,MAAK,QAAO,QACzD,0BAAAA,KAAC,YAAS,MAAM,IAAI,GACtB;AAAA,cAEA,gBAAAC,MAACE,QAAA,EAAM,KAAK,GACV;AAAA,gCAAAH,KAACI,OAAA,EAAK,MAAK,MAAK,GAAE,UAAS,IAAI,KAAK,IAAG,aAAY,sBAEnD;AAAA,gBACA,gBAAAJ,KAACI,OAAA,EAAK,MAAK,MAAK,IAAI,KAAK,UAAQ,MAC9B,eAAK,WAAW,SACnB;AAAA,iBACF;AAAA,eACF;AAAA,YAEC,KAAK,WAAW,gBAAAJ,KAAC,qBAAkB,SAAS,KAAK,SAAS;AAAA,aAC7D;AAAA;AAAA,MACF;AAAA,OACF;AAAA,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,KAAK;AAAA,QAChB;AAAA,QACA,YAAY,KAAK;AAAA,QACjB,aAAa,KAAK;AAAA;AAAA,IACpB;AAAA,KACF;AAEJ;AAEO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AACV,GAA0B;AACxB,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,iBAAe;AAAA,MACf,UAAQ;AAAA,MACR,QAAO;AAAA,MACP,MAAK;AAAA,MACL,QAAQ;AAAA,QACN,SAAS;AAAA,UACP,WAAW;AAAA,UACX,QAAQ;AAAA,QACV;AAAA,QACA,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,MACA;AAAA,MAEA,0BAAAA,KAAC,sBAAmB,MAAY;AAAA;AAAA,EAClC;AAEJ;AAEA,SAAS,kBAAkB,EAAE,QAAQ,GAAwB;AAC3D,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAE1C,QAAM,aAAa,YAAY;AAC7B,UAAM,UAAU,MAAM,gBAAgB,OAAO;AAC7C,QAAI,SAAS;AACX,gBAAU,IAAI;AACd,iBAAW,MAAM,UAAU,KAAK,GAAG,GAAI;AAAA,IACzC;AAAA,EACF;AAEA,SACE,gBAAAA,KAACK,UAAA,EAAQ,OAAO,SAAS,YAAY,WAAW,WAAS,MACvD,0BAAAL;AAAA,IAACM;AAAA,IAAA;AAAA,MACC,SAAQ;AAAA,MACR,OAAO,SAAS,SAAS;AAAA,MACzB,SAAS;AAAA,MAER,mBAAS,gBAAAN,KAAC,aAAU,MAAM,IAAI,IAAK,gBAAAA,KAAC,YAAS,MAAM,IAAI;AAAA;AAAA,EAC1D,GACF;AAEJ;AAEA,SAAS,SAAS;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,cAAc,uBAAuB;AAC3C,SACE,gBAAAA,KAAC,SAAM,YAAU,MAAC,GAAE,MAAK,QAAO,QAAO,GAAE,QAAO,IAAI,gBAAgB,SAAS,WAAW,UACtF,0BAAAC,MAACC,QAAA,EAAM,KAAI,MAAK,OAAM,cACpB;AAAA,oBAAAF,KAAC,aAAU,OAAc,SAAQ,SAAQ,MAAK,MAAK,QAAO,QACvD,gBACH;AAAA,IAEA,gBAAAC,MAACE,QAAA,EAAM,KAAK,GAAG,MAAM,GACnB;AAAA,sBAAAH,KAACI,OAAA,EAAK,MAAK,MAAK,GAAE,UAAS,IAAI,KAAK,IAAG,aACpC,iBACH;AAAA,MACA,gBAAAJ,KAACI,OAAA,EAAK,MAAK,MAAK,IAAI,KAAK,WAAW,GACjC,iBACH;AAAA,OACF;AAAA,KACF,GACF;AAEJ;","names":["Stack","Text","Group","ActionIcon","Tooltip","jsx","jsxs","Group","Stack","Text","Tooltip","ActionIcon"]}
|