@adminlte/react 0.1.0
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/CHANGELOG.md +161 -0
- package/README.md +454 -0
- package/dist/context/accessibility.js +141 -0
- package/dist/context/body-class-sync.js +22 -0
- package/dist/context/color-mode-context.js +61 -0
- package/dist/context/command-palette-context.js +28 -0
- package/dist/context/html-dir.js +17 -0
- package/dist/context/link-context.js +18 -0
- package/dist/context/lte-behaviors.js +52 -0
- package/dist/context/sidebar-context.js +87 -0
- package/dist/css/adminlte.css +17259 -0
- package/dist/form/button.js +21 -0
- package/dist/form/input-color.js +30 -0
- package/dist/form/input-file.js +29 -0
- package/dist/form/input-flatpickr.js +45 -0
- package/dist/form/input-switch.js +26 -0
- package/dist/form/input-tom-select.js +59 -0
- package/dist/form/input.js +23 -0
- package/dist/form/select.js +25 -0
- package/dist/form/textarea.js +22 -0
- package/dist/hooks/use-card-widget.js +44 -0
- package/dist/hooks/use-direct-chat.js +16 -0
- package/dist/hooks/use-fullscreen.js +44 -0
- package/dist/hooks/use-push-menu.js +54 -0
- package/dist/hooks/use-sortable.js +26 -0
- package/dist/hooks/use-treeview-animation.js +27 -0
- package/dist/index.d.ts +1010 -0
- package/dist/index.js +145 -0
- package/dist/layout/app-content.js +18 -0
- package/dist/layout/auth-layout.js +25 -0
- package/dist/layout/color-mode-toggle.js +67 -0
- package/dist/layout/dashboard-layout.js +101 -0
- package/dist/layout/footer.js +19 -0
- package/dist/layout/sidebar-brand.js +16 -0
- package/dist/layout/sidebar-nav-item.js +46 -0
- package/dist/layout/sidebar-nav.js +43 -0
- package/dist/layout/sidebar-overlay.js +18 -0
- package/dist/layout/sidebar.js +48 -0
- package/dist/layout/topbar.js +128 -0
- package/dist/lib/class-name.js +6 -0
- package/dist/lib/flatten-menu.js +23 -0
- package/dist/tool/datatable.js +45 -0
- package/dist/tool/editor.js +72 -0
- package/dist/tool/modal.js +28 -0
- package/dist/types/direct-chat.js +0 -0
- package/dist/types/layout.js +0 -0
- package/dist/types/menu.js +0 -0
- package/dist/types/theme.js +0 -0
- package/dist/widget/accordion.js +35 -0
- package/dist/widget/alert.js +18 -0
- package/dist/widget/apex-chart.js +40 -0
- package/dist/widget/avatar.js +72 -0
- package/dist/widget/badge.js +20 -0
- package/dist/widget/breadcrumb.js +26 -0
- package/dist/widget/callout.js +11 -0
- package/dist/widget/card.js +84 -0
- package/dist/widget/carousel.js +56 -0
- package/dist/widget/command-palette.js +137 -0
- package/dist/widget/description-block.js +19 -0
- package/dist/widget/direct-chat.js +96 -0
- package/dist/widget/dropdown.js +63 -0
- package/dist/widget/info-box.js +24 -0
- package/dist/widget/list-group.js +47 -0
- package/dist/widget/nav-messages.js +48 -0
- package/dist/widget/nav-notifications.js +40 -0
- package/dist/widget/nav-tasks.js +60 -0
- package/dist/widget/offcanvas.js +61 -0
- package/dist/widget/pagination.js +93 -0
- package/dist/widget/profile-card.js +32 -0
- package/dist/widget/progress-group.js +23 -0
- package/dist/widget/progress.js +25 -0
- package/dist/widget/ratings.js +20 -0
- package/dist/widget/small-box.js +34 -0
- package/dist/widget/sparkline-chart.js +43 -0
- package/dist/widget/spinner.js +26 -0
- package/dist/widget/stepper.js +57 -0
- package/dist/widget/table.js +50 -0
- package/dist/widget/tabs.js +46 -0
- package/dist/widget/timeline.js +15 -0
- package/dist/widget/toast.js +41 -0
- package/dist/widget/tooltip.js +30 -0
- package/dist/widget/world-map.js +42 -0
- package/package.json +116 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/class-name.js";
|
|
3
|
+
function buildRange(page, total, sibling) {
|
|
4
|
+
const tokens = /* @__PURE__ */ new Set([1, total]);
|
|
5
|
+
for (let p = page - sibling; p <= page + sibling; p++) {
|
|
6
|
+
if (p >= 1 && p <= total) tokens.add(p);
|
|
7
|
+
}
|
|
8
|
+
const sorted = [...tokens].sort((a, b) => a - b);
|
|
9
|
+
const out = [];
|
|
10
|
+
let prev = 0;
|
|
11
|
+
for (const p of sorted) {
|
|
12
|
+
if (prev && p - prev > 1) out.push("ellipsis");
|
|
13
|
+
out.push(p);
|
|
14
|
+
prev = p;
|
|
15
|
+
}
|
|
16
|
+
return out;
|
|
17
|
+
}
|
|
18
|
+
function Pagination({
|
|
19
|
+
page,
|
|
20
|
+
totalPages,
|
|
21
|
+
onPageChange,
|
|
22
|
+
size,
|
|
23
|
+
siblingCount = 1,
|
|
24
|
+
align = "start",
|
|
25
|
+
hideControls,
|
|
26
|
+
label = "Pagination",
|
|
27
|
+
className
|
|
28
|
+
}) {
|
|
29
|
+
if (totalPages < 1) return null;
|
|
30
|
+
const tokens = buildRange(page, totalPages, siblingCount);
|
|
31
|
+
const item = (key, content, target, opts = {}) => {
|
|
32
|
+
const { active, disabled, ariaLabel } = opts;
|
|
33
|
+
const go = (e) => {
|
|
34
|
+
if (disabled || active) return;
|
|
35
|
+
if (onPageChange) {
|
|
36
|
+
e.preventDefault();
|
|
37
|
+
onPageChange(target);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return /* @__PURE__ */ jsx("li", { className: cn("page-item", active && "active", disabled && "disabled"), children: onPageChange ? /* @__PURE__ */ jsx(
|
|
41
|
+
"button",
|
|
42
|
+
{
|
|
43
|
+
type: "button",
|
|
44
|
+
className: "page-link",
|
|
45
|
+
onClick: go,
|
|
46
|
+
"aria-label": ariaLabel,
|
|
47
|
+
"aria-current": active ? "page" : void 0,
|
|
48
|
+
disabled,
|
|
49
|
+
children: content
|
|
50
|
+
}
|
|
51
|
+
) : /* @__PURE__ */ jsx(
|
|
52
|
+
"a",
|
|
53
|
+
{
|
|
54
|
+
className: "page-link",
|
|
55
|
+
href: "#",
|
|
56
|
+
onClick: go,
|
|
57
|
+
"aria-label": ariaLabel,
|
|
58
|
+
"aria-current": active ? "page" : void 0,
|
|
59
|
+
"aria-disabled": disabled,
|
|
60
|
+
tabIndex: disabled ? -1 : void 0,
|
|
61
|
+
children: content
|
|
62
|
+
}
|
|
63
|
+
) }, key);
|
|
64
|
+
};
|
|
65
|
+
return /* @__PURE__ */ jsx("nav", { "aria-label": label, children: /* @__PURE__ */ jsxs(
|
|
66
|
+
"ul",
|
|
67
|
+
{
|
|
68
|
+
className: cn(
|
|
69
|
+
"pagination mb-0",
|
|
70
|
+
size && `pagination-${size}`,
|
|
71
|
+
align === "center" && "justify-content-center",
|
|
72
|
+
align === "end" && "justify-content-end",
|
|
73
|
+
className
|
|
74
|
+
),
|
|
75
|
+
children: [
|
|
76
|
+
!hideControls && item("prev", /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2039" }), page - 1, {
|
|
77
|
+
disabled: page <= 1,
|
|
78
|
+
ariaLabel: "Previous page"
|
|
79
|
+
}),
|
|
80
|
+
tokens.map(
|
|
81
|
+
(t, i) => t === "ellipsis" ? /* @__PURE__ */ jsx("li", { className: "page-item disabled", children: /* @__PURE__ */ jsx("span", { className: "page-link", children: "\u2026" }) }, `e${i}`) : item(t, t, t, { active: t === page })
|
|
82
|
+
),
|
|
83
|
+
!hideControls && item("next", /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u203A" }), page + 1, {
|
|
84
|
+
disabled: page >= totalPages,
|
|
85
|
+
ariaLabel: "Next page"
|
|
86
|
+
})
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
) });
|
|
90
|
+
}
|
|
91
|
+
export {
|
|
92
|
+
Pagination
|
|
93
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
function ProfileCard({
|
|
3
|
+
name,
|
|
4
|
+
title,
|
|
5
|
+
image,
|
|
6
|
+
imageAlt = "User",
|
|
7
|
+
socials,
|
|
8
|
+
description,
|
|
9
|
+
className,
|
|
10
|
+
children
|
|
11
|
+
}) {
|
|
12
|
+
return /* @__PURE__ */ jsx("div", { className: `card ${className || ""}`, children: /* @__PURE__ */ jsxs("div", { className: "card-body text-center", children: [
|
|
13
|
+
image && /* @__PURE__ */ jsx("img", { src: image, alt: imageAlt, className: "img-fluid rounded-circle mb-3" }),
|
|
14
|
+
/* @__PURE__ */ jsx("h5", { className: "card-title", children: name }),
|
|
15
|
+
title && /* @__PURE__ */ jsx("p", { className: "text-muted", children: title }),
|
|
16
|
+
description && /* @__PURE__ */ jsx("p", { className: "card-text small", children: description }),
|
|
17
|
+
socials && socials.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3", children: socials.map((link, idx) => /* @__PURE__ */ jsx(
|
|
18
|
+
"a",
|
|
19
|
+
{
|
|
20
|
+
href: link.url,
|
|
21
|
+
className: "btn btn-sm btn-outline-secondary me-1",
|
|
22
|
+
title: link.label,
|
|
23
|
+
children: /* @__PURE__ */ jsx("i", { className: `bi ${link.icon}` })
|
|
24
|
+
},
|
|
25
|
+
idx
|
|
26
|
+
)) }),
|
|
27
|
+
children
|
|
28
|
+
] }) });
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
ProfileCard
|
|
32
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
function ProgressGroup({
|
|
3
|
+
label,
|
|
4
|
+
value,
|
|
5
|
+
color = "primary",
|
|
6
|
+
max = 100,
|
|
7
|
+
showPercentage = true
|
|
8
|
+
}) {
|
|
9
|
+
const percentage = Math.round(value / max * 100);
|
|
10
|
+
return /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
|
|
11
|
+
/* @__PURE__ */ jsxs("div", { className: "d-flex justify-content-between mb-1", children: [
|
|
12
|
+
/* @__PURE__ */ jsx("span", { children: label }),
|
|
13
|
+
showPercentage && /* @__PURE__ */ jsxs("span", { className: "text-muted", children: [
|
|
14
|
+
percentage,
|
|
15
|
+
"%"
|
|
16
|
+
] })
|
|
17
|
+
] }),
|
|
18
|
+
/* @__PURE__ */ jsx("div", { className: "progress", children: /* @__PURE__ */ jsx("div", { className: `progress-bar bg-${color}`, style: { width: `${percentage}%` } }) })
|
|
19
|
+
] });
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
ProgressGroup
|
|
23
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
function Progress({
|
|
3
|
+
value = 0,
|
|
4
|
+
theme = "primary",
|
|
5
|
+
striped,
|
|
6
|
+
animated,
|
|
7
|
+
height,
|
|
8
|
+
showLabel
|
|
9
|
+
}) {
|
|
10
|
+
return /* @__PURE__ */ jsx("div", { className: "progress", style: height ? { height } : {}, children: /* @__PURE__ */ jsx(
|
|
11
|
+
"div",
|
|
12
|
+
{
|
|
13
|
+
className: `progress-bar bg-${theme} ${striped ? "progress-bar-striped" : ""} ${animated ? "progress-bar-animated" : ""}`,
|
|
14
|
+
role: "progressbar",
|
|
15
|
+
style: { width: `${value}%` },
|
|
16
|
+
"aria-valuenow": value,
|
|
17
|
+
"aria-valuemin": 0,
|
|
18
|
+
"aria-valuemax": 100,
|
|
19
|
+
children: showLabel && `${value}%`
|
|
20
|
+
}
|
|
21
|
+
) });
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
Progress
|
|
25
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
function Ratings({
|
|
3
|
+
value,
|
|
4
|
+
max = 5,
|
|
5
|
+
color = "warning",
|
|
6
|
+
readonly = true,
|
|
7
|
+
className
|
|
8
|
+
}) {
|
|
9
|
+
return /* @__PURE__ */ jsx("div", { className, children: Array.from({ length: max }).map((_, i) => /* @__PURE__ */ jsx(
|
|
10
|
+
"i",
|
|
11
|
+
{
|
|
12
|
+
className: `bi bi-star${i < value ? "-fill" : ""} text-${color}`,
|
|
13
|
+
style: { cursor: readonly ? "default" : "pointer" }
|
|
14
|
+
},
|
|
15
|
+
i
|
|
16
|
+
)) });
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
Ratings
|
|
20
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
const DARK_LINK_THEMES = ["warning", "light"];
|
|
3
|
+
function SmallBox({
|
|
4
|
+
title,
|
|
5
|
+
text,
|
|
6
|
+
icon,
|
|
7
|
+
theme = "primary",
|
|
8
|
+
url,
|
|
9
|
+
urlText = "More info"
|
|
10
|
+
}) {
|
|
11
|
+
const linkColor = DARK_LINK_THEMES.includes(theme) ? "link-dark" : "link-light";
|
|
12
|
+
return /* @__PURE__ */ jsxs("div", { className: `small-box text-bg-${theme}`, children: [
|
|
13
|
+
/* @__PURE__ */ jsxs("div", { className: "inner", children: [
|
|
14
|
+
/* @__PURE__ */ jsx("h3", { children: title }),
|
|
15
|
+
text && /* @__PURE__ */ jsx("p", { children: text })
|
|
16
|
+
] }),
|
|
17
|
+
icon,
|
|
18
|
+
url && /* @__PURE__ */ jsxs(
|
|
19
|
+
"a",
|
|
20
|
+
{
|
|
21
|
+
href: url,
|
|
22
|
+
className: `small-box-footer ${linkColor} link-underline-opacity-0 link-underline-opacity-50-hover`,
|
|
23
|
+
children: [
|
|
24
|
+
urlText,
|
|
25
|
+
" ",
|
|
26
|
+
/* @__PURE__ */ jsx("i", { className: "bi bi-link-45deg" })
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
] });
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
SmallBox
|
|
34
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
function SparklineChart({ id, data }) {
|
|
5
|
+
const containerRef = useRef(null);
|
|
6
|
+
const chartRef = useRef(null);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
let cancelled = false;
|
|
9
|
+
const el = containerRef.current;
|
|
10
|
+
if (!el) return;
|
|
11
|
+
const initChart = async () => {
|
|
12
|
+
const ApexCharts = (await import("apexcharts")).default;
|
|
13
|
+
if (cancelled || !containerRef.current) return;
|
|
14
|
+
const options = {
|
|
15
|
+
series: [{ data }],
|
|
16
|
+
chart: {
|
|
17
|
+
type: "area",
|
|
18
|
+
height: 50,
|
|
19
|
+
sparkline: { enabled: true }
|
|
20
|
+
},
|
|
21
|
+
stroke: { curve: "straight" },
|
|
22
|
+
fill: { opacity: 0.3 },
|
|
23
|
+
yaxis: { min: 0 },
|
|
24
|
+
colors: ["#DCE6EC"]
|
|
25
|
+
};
|
|
26
|
+
const chart = new ApexCharts(el, options);
|
|
27
|
+
chartRef.current = chart;
|
|
28
|
+
chart.render();
|
|
29
|
+
};
|
|
30
|
+
initChart().catch((err) => console.error("SparklineChart init error:", err));
|
|
31
|
+
return () => {
|
|
32
|
+
cancelled = true;
|
|
33
|
+
if (chartRef.current) {
|
|
34
|
+
chartRef.current.destroy();
|
|
35
|
+
chartRef.current = null;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}, [id, data]);
|
|
39
|
+
return /* @__PURE__ */ jsx("div", { id, ref: containerRef });
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
SparklineChart
|
|
43
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/class-name.js";
|
|
3
|
+
function Spinner({
|
|
4
|
+
theme,
|
|
5
|
+
variant = "border",
|
|
6
|
+
small,
|
|
7
|
+
label = "Loading\u2026",
|
|
8
|
+
className
|
|
9
|
+
}) {
|
|
10
|
+
return /* @__PURE__ */ jsx(
|
|
11
|
+
"div",
|
|
12
|
+
{
|
|
13
|
+
className: cn(
|
|
14
|
+
`spinner-${variant}`,
|
|
15
|
+
small && `spinner-${variant}-sm`,
|
|
16
|
+
theme && `text-${theme}`,
|
|
17
|
+
className
|
|
18
|
+
),
|
|
19
|
+
role: "status",
|
|
20
|
+
children: /* @__PURE__ */ jsx("span", { className: "visually-hidden", children: label })
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
Spinner
|
|
26
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/class-name.js";
|
|
3
|
+
function Stepper({ steps, active, orientation = "horizontal", onStepClick, className }) {
|
|
4
|
+
const vertical = orientation === "vertical";
|
|
5
|
+
const marker = (state, index, icon) => {
|
|
6
|
+
const bg = state === "complete" ? "text-bg-success" : state === "active" ? "text-bg-primary" : "text-bg-secondary";
|
|
7
|
+
const content = icon ? /* @__PURE__ */ jsx("i", { className: cn("bi", icon), "aria-hidden": "true" }) : state === "complete" ? /* @__PURE__ */ jsx("i", { className: "bi bi-check-lg", "aria-hidden": "true" }) : index + 1;
|
|
8
|
+
const cls = cn(
|
|
9
|
+
"d-inline-flex align-items-center justify-content-center rounded-circle flex-shrink-0 fw-semibold",
|
|
10
|
+
bg,
|
|
11
|
+
state === "upcoming" && "opacity-75"
|
|
12
|
+
);
|
|
13
|
+
const style = { width: 38, height: 38 };
|
|
14
|
+
return onStepClick ? /* @__PURE__ */ jsx(
|
|
15
|
+
"button",
|
|
16
|
+
{
|
|
17
|
+
type: "button",
|
|
18
|
+
className: cn(cls, "border-0"),
|
|
19
|
+
style,
|
|
20
|
+
onClick: () => onStepClick(index),
|
|
21
|
+
"aria-label": `Go to step ${index + 1}`,
|
|
22
|
+
children: content
|
|
23
|
+
}
|
|
24
|
+
) : /* @__PURE__ */ jsx("span", { className: cls, style, children: content });
|
|
25
|
+
};
|
|
26
|
+
return /* @__PURE__ */ jsx(
|
|
27
|
+
"ol",
|
|
28
|
+
{
|
|
29
|
+
className: cn(
|
|
30
|
+
"list-unstyled d-flex mb-0",
|
|
31
|
+
vertical ? "flex-column gap-3" : "flex-row align-items-start",
|
|
32
|
+
className
|
|
33
|
+
),
|
|
34
|
+
children: steps.map((step, idx) => {
|
|
35
|
+
const state = idx < active ? "complete" : idx === active ? "active" : "upcoming";
|
|
36
|
+
return /* @__PURE__ */ jsxs(
|
|
37
|
+
"li",
|
|
38
|
+
{
|
|
39
|
+
className: cn("d-flex", vertical ? "flex-row gap-3" : "flex-column align-items-center text-center flex-fill"),
|
|
40
|
+
"aria-current": state === "active" ? "step" : void 0,
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ jsx("div", { className: cn("d-flex align-items-center", !vertical && "w-100 justify-content-center"), children: marker(state, idx, step.icon) }),
|
|
43
|
+
/* @__PURE__ */ jsxs("div", { className: cn(vertical ? "" : "mt-2"), children: [
|
|
44
|
+
/* @__PURE__ */ jsx("div", { className: cn("fw-semibold", state === "upcoming" && "text-secondary"), children: step.label }),
|
|
45
|
+
step.description && /* @__PURE__ */ jsx("div", { className: "small text-secondary", children: step.description })
|
|
46
|
+
] })
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
idx
|
|
50
|
+
);
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
Stepper
|
|
57
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/class-name.js";
|
|
3
|
+
function Table({
|
|
4
|
+
columns,
|
|
5
|
+
data,
|
|
6
|
+
rowKey,
|
|
7
|
+
striped,
|
|
8
|
+
hover,
|
|
9
|
+
bordered,
|
|
10
|
+
borderless,
|
|
11
|
+
small,
|
|
12
|
+
responsive,
|
|
13
|
+
theme,
|
|
14
|
+
caption,
|
|
15
|
+
emptyMessage = "No data",
|
|
16
|
+
className
|
|
17
|
+
}) {
|
|
18
|
+
const table = /* @__PURE__ */ jsxs(
|
|
19
|
+
"table",
|
|
20
|
+
{
|
|
21
|
+
className: cn(
|
|
22
|
+
"table",
|
|
23
|
+
striped && "table-striped",
|
|
24
|
+
hover && "table-hover",
|
|
25
|
+
bordered && "table-bordered",
|
|
26
|
+
borderless && "table-borderless",
|
|
27
|
+
small && "table-sm",
|
|
28
|
+
theme && `table-${theme}`,
|
|
29
|
+
className
|
|
30
|
+
),
|
|
31
|
+
children: [
|
|
32
|
+
caption && /* @__PURE__ */ jsx("caption", { children: caption }),
|
|
33
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsx(
|
|
34
|
+
"th",
|
|
35
|
+
{
|
|
36
|
+
scope: "col",
|
|
37
|
+
className: cn(col.align && `text-${col.align}`, col.headerClassName),
|
|
38
|
+
children: col.header
|
|
39
|
+
},
|
|
40
|
+
col.key
|
|
41
|
+
)) }) }),
|
|
42
|
+
/* @__PURE__ */ jsx("tbody", { children: data.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: columns.length, className: "text-center text-secondary py-3", children: emptyMessage }) }) : data.map((row, i) => /* @__PURE__ */ jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsx("td", { className: cn(col.align && `text-${col.align}`, col.className), children: col.render ? col.render(row, i) : String(row[col.key] ?? "") }, col.key)) }, rowKey ? rowKey(row, i) : i)) })
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
return responsive ? /* @__PURE__ */ jsx("div", { className: "table-responsive", children: table }) : table;
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
Table
|
|
50
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
function Tabs({
|
|
5
|
+
items,
|
|
6
|
+
defaultIndex = 0,
|
|
7
|
+
variant = "tabs",
|
|
8
|
+
fill,
|
|
9
|
+
justified,
|
|
10
|
+
className
|
|
11
|
+
}) {
|
|
12
|
+
const [active, setActive] = useState(defaultIndex);
|
|
13
|
+
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
14
|
+
/* @__PURE__ */ jsx(
|
|
15
|
+
"ul",
|
|
16
|
+
{
|
|
17
|
+
className: `nav nav-${variant}${fill ? " nav-fill" : ""}${justified ? " nav-justified" : ""}`,
|
|
18
|
+
role: "tablist",
|
|
19
|
+
children: items.map((item, i) => /* @__PURE__ */ jsx("li", { className: "nav-item", role: "presentation", children: /* @__PURE__ */ jsx(
|
|
20
|
+
"button",
|
|
21
|
+
{
|
|
22
|
+
type: "button",
|
|
23
|
+
className: `nav-link${i === active ? " active" : ""}`,
|
|
24
|
+
role: "tab",
|
|
25
|
+
"aria-selected": i === active,
|
|
26
|
+
onClick: () => setActive(i),
|
|
27
|
+
children: item.label
|
|
28
|
+
}
|
|
29
|
+
) }, i))
|
|
30
|
+
}
|
|
31
|
+
),
|
|
32
|
+
/* @__PURE__ */ jsx("div", { className: "tab-content pt-3", children: items.map((item, i) => /* @__PURE__ */ jsx(
|
|
33
|
+
"div",
|
|
34
|
+
{
|
|
35
|
+
role: "tabpanel",
|
|
36
|
+
className: `tab-pane fade${i === active ? " show active" : ""}`,
|
|
37
|
+
hidden: i !== active,
|
|
38
|
+
children: item.children
|
|
39
|
+
},
|
|
40
|
+
i
|
|
41
|
+
)) })
|
|
42
|
+
] });
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
Tabs
|
|
46
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
function Timeline({ items, className }) {
|
|
3
|
+
return /* @__PURE__ */ jsx("div", { className: `timeline ${className || ""}`, children: items.map((item, idx) => /* @__PURE__ */ jsxs("div", { className: "timeline-item", children: [
|
|
4
|
+
item.icon && /* @__PURE__ */ jsx("span", { className: `timeline-icon bg-${item.iconTheme || "primary"}`, children: /* @__PURE__ */ jsx("i", { className: `bi ${item.icon}` }) }),
|
|
5
|
+
/* @__PURE__ */ jsxs("div", { className: "timeline-content", children: [
|
|
6
|
+
/* @__PURE__ */ jsx("h3", { className: "timeline-header", children: item.title }),
|
|
7
|
+
item.body && /* @__PURE__ */ jsx("p", { children: item.body }),
|
|
8
|
+
item.footer && /* @__PURE__ */ jsx("div", { className: "timeline-footer", children: item.footer }),
|
|
9
|
+
/* @__PURE__ */ jsx("div", { className: "timeline-time", children: item.time })
|
|
10
|
+
] })
|
|
11
|
+
] }, idx)) });
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
Timeline
|
|
15
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
function Toast({ show, onClose, title, theme, autohideMs = 4e3, children }) {
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
if (!show || !autohideMs) return;
|
|
7
|
+
const t = setTimeout(onClose, autohideMs);
|
|
8
|
+
return () => clearTimeout(t);
|
|
9
|
+
}, [show, autohideMs, onClose]);
|
|
10
|
+
if (!show) return null;
|
|
11
|
+
return /* @__PURE__ */ jsxs(
|
|
12
|
+
"div",
|
|
13
|
+
{
|
|
14
|
+
className: `toast show${theme ? ` text-bg-${theme} border-0` : ""}`,
|
|
15
|
+
role: "alert",
|
|
16
|
+
"aria-live": "assertive",
|
|
17
|
+
"aria-atomic": "true",
|
|
18
|
+
children: [
|
|
19
|
+
title && /* @__PURE__ */ jsxs("div", { className: "toast-header", children: [
|
|
20
|
+
/* @__PURE__ */ jsx("strong", { className: "me-auto", children: title }),
|
|
21
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "btn-close", "aria-label": "Close", onClick: onClose })
|
|
22
|
+
] }),
|
|
23
|
+
/* @__PURE__ */ jsxs("div", { className: "d-flex", children: [
|
|
24
|
+
/* @__PURE__ */ jsx("div", { className: "toast-body", children }),
|
|
25
|
+
!title && /* @__PURE__ */ jsx(
|
|
26
|
+
"button",
|
|
27
|
+
{
|
|
28
|
+
type: "button",
|
|
29
|
+
className: `btn-close me-2 m-auto${theme ? " btn-close-white" : ""}`,
|
|
30
|
+
"aria-label": "Close",
|
|
31
|
+
onClick: onClose
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
] })
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
Toast
|
|
41
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
const POS = {
|
|
5
|
+
top: { cls: "bs-tooltip-top", style: { bottom: "100%", left: "50%", transform: "translateX(-50%)", marginBottom: 6 } },
|
|
6
|
+
bottom: { cls: "bs-tooltip-bottom", style: { top: "100%", left: "50%", transform: "translateX(-50%)", marginTop: 6 } },
|
|
7
|
+
left: { cls: "bs-tooltip-start", style: { right: "100%", top: "50%", transform: "translateY(-50%)", marginRight: 6 } },
|
|
8
|
+
right: { cls: "bs-tooltip-end", style: { left: "100%", top: "50%", transform: "translateY(-50%)", marginLeft: 6 } }
|
|
9
|
+
};
|
|
10
|
+
function Tooltip({ title, placement = "top", children }) {
|
|
11
|
+
const [show, setShow] = useState(false);
|
|
12
|
+
const { cls, style } = POS[placement];
|
|
13
|
+
return /* @__PURE__ */ jsxs(
|
|
14
|
+
"span",
|
|
15
|
+
{
|
|
16
|
+
style: { position: "relative", display: "inline-block" },
|
|
17
|
+
onMouseEnter: () => setShow(true),
|
|
18
|
+
onMouseLeave: () => setShow(false),
|
|
19
|
+
onFocus: () => setShow(true),
|
|
20
|
+
onBlur: () => setShow(false),
|
|
21
|
+
children: [
|
|
22
|
+
children,
|
|
23
|
+
show && /* @__PURE__ */ jsx("span", { className: `tooltip ${cls} show`, role: "tooltip", style: { position: "absolute", zIndex: 1080, ...style }, children: /* @__PURE__ */ jsx("span", { className: "tooltip-inner", children: title }) })
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
Tooltip
|
|
30
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
function WorldMap({ id, height = 220 }) {
|
|
5
|
+
const containerRef = useRef(null);
|
|
6
|
+
const mapRef = useRef(null);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
let cancelled = false;
|
|
9
|
+
const el = containerRef.current;
|
|
10
|
+
if (!el) return;
|
|
11
|
+
const initMap = async () => {
|
|
12
|
+
try {
|
|
13
|
+
const mod = await import("jsvectormap");
|
|
14
|
+
await import("jsvectormap/dist/maps/world.js");
|
|
15
|
+
if (cancelled || !containerRef.current) return;
|
|
16
|
+
const JsVectorMap = mod.default ?? mod.jsVectorMap ?? mod;
|
|
17
|
+
if (typeof JsVectorMap !== "function") return;
|
|
18
|
+
mapRef.current = new JsVectorMap({
|
|
19
|
+
selector: el,
|
|
20
|
+
map: "world"
|
|
21
|
+
});
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error("WorldMap init error:", error);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
initMap();
|
|
27
|
+
return () => {
|
|
28
|
+
cancelled = true;
|
|
29
|
+
if (mapRef.current) {
|
|
30
|
+
if (typeof mapRef.current.destroy === "function") {
|
|
31
|
+
mapRef.current.destroy();
|
|
32
|
+
}
|
|
33
|
+
mapRef.current = null;
|
|
34
|
+
if (containerRef.current) containerRef.current.innerHTML = "";
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}, [id]);
|
|
38
|
+
return /* @__PURE__ */ jsx("div", { id, ref: containerRef, style: { height: `${height}px` } });
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
WorldMap
|
|
42
|
+
};
|