@underverse-ui/underverse 0.2.73 → 0.2.75
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 +535 -465
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -13
- package/dist/index.d.ts +14 -13
- package/dist/index.js +525 -455
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -594,7 +594,7 @@ var Card = ({
|
|
|
594
594
|
{
|
|
595
595
|
className: cn(
|
|
596
596
|
"rounded-2xl md:rounded-3xl bg-card text-card-foreground transition-[transform,box-shadow,border-color,background-color] duration-300 ease-soft",
|
|
597
|
-
"shadow-sm md:hover:shadow-md
|
|
597
|
+
"shadow-sm md:hover:shadow-md border border-border",
|
|
598
598
|
hoverable && "md:hover:-translate-y-0.5 md:hover:border-primary/15",
|
|
599
599
|
clickable && "cursor-pointer active:translate-y-px md:hover:bg-accent/5",
|
|
600
600
|
"backdrop-blur-sm",
|
|
@@ -13051,10 +13051,183 @@ TableCell.displayName = "TableCell";
|
|
|
13051
13051
|
var TableCaption = import_react31.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props }));
|
|
13052
13052
|
TableCaption.displayName = "TableCaption";
|
|
13053
13053
|
|
|
13054
|
-
// ../../components/ui/DataTable.tsx
|
|
13054
|
+
// ../../components/ui/DataTable/DataTable.tsx
|
|
13055
13055
|
var import_lucide_react27 = require("lucide-react");
|
|
13056
|
-
var
|
|
13056
|
+
var import_react35 = __toESM(require("react"), 1);
|
|
13057
|
+
|
|
13058
|
+
// ../../components/ui/DataTable/components/Pagination.tsx
|
|
13057
13059
|
var import_jsx_runtime57 = require("react/jsx-runtime");
|
|
13060
|
+
function DataTablePagination({
|
|
13061
|
+
totalItems,
|
|
13062
|
+
curPage,
|
|
13063
|
+
curPageSize,
|
|
13064
|
+
setCurPage,
|
|
13065
|
+
pageSizeOptions,
|
|
13066
|
+
setCurPageSize
|
|
13067
|
+
}) {
|
|
13068
|
+
const totalPages = Math.ceil(totalItems / curPageSize);
|
|
13069
|
+
if (!(totalItems > 0 && totalPages > 1)) return null;
|
|
13070
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "flex items-center justify-between gap-2 px-1 pt-3 text-xs text-muted-foreground", children: [
|
|
13071
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "tabular-nums", children: [
|
|
13072
|
+
(curPage - 1) * curPageSize + 1,
|
|
13073
|
+
"-",
|
|
13074
|
+
Math.min(curPage * curPageSize, totalItems),
|
|
13075
|
+
"/",
|
|
13076
|
+
totalItems
|
|
13077
|
+
] }),
|
|
13078
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "flex items-center gap-0.5", children: [
|
|
13079
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13080
|
+
Button_default,
|
|
13081
|
+
{
|
|
13082
|
+
variant: "ghost",
|
|
13083
|
+
size: "sm",
|
|
13084
|
+
className: "h-7 w-7 p-0 rounded-full",
|
|
13085
|
+
onClick: () => setCurPage(Math.max(1, curPage - 1)),
|
|
13086
|
+
disabled: curPage === 1,
|
|
13087
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("svg", { className: "h-4 w-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
|
|
13088
|
+
}
|
|
13089
|
+
),
|
|
13090
|
+
(() => {
|
|
13091
|
+
const pages = [];
|
|
13092
|
+
if (totalPages <= 5) {
|
|
13093
|
+
for (let i = 1; i <= totalPages; i++) pages.push(i);
|
|
13094
|
+
} else {
|
|
13095
|
+
pages.push(1);
|
|
13096
|
+
if (curPage > 3) pages.push("...");
|
|
13097
|
+
const start = Math.max(2, curPage - 1);
|
|
13098
|
+
const end = Math.min(totalPages - 1, curPage + 1);
|
|
13099
|
+
for (let i = start; i <= end; i++) pages.push(i);
|
|
13100
|
+
if (curPage < totalPages - 2) pages.push("...");
|
|
13101
|
+
pages.push(totalPages);
|
|
13102
|
+
}
|
|
13103
|
+
return pages.map(
|
|
13104
|
+
(p, i) => p === "..." ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "px-1 text-muted-foreground/60", children: "\u2026" }, `dots-${i}`) : /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13105
|
+
"button",
|
|
13106
|
+
{
|
|
13107
|
+
onClick: () => setCurPage(p),
|
|
13108
|
+
className: cn(
|
|
13109
|
+
"h-7 min-w-7 px-2 rounded-full text-xs font-medium transition-colors",
|
|
13110
|
+
curPage === p ? "bg-primary text-primary-foreground" : "hover:bg-accent hover:text-accent-foreground"
|
|
13111
|
+
),
|
|
13112
|
+
children: p
|
|
13113
|
+
},
|
|
13114
|
+
p
|
|
13115
|
+
)
|
|
13116
|
+
);
|
|
13117
|
+
})(),
|
|
13118
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13119
|
+
Button_default,
|
|
13120
|
+
{
|
|
13121
|
+
variant: "ghost",
|
|
13122
|
+
size: "sm",
|
|
13123
|
+
className: "h-7 w-7 p-0 rounded-full",
|
|
13124
|
+
onClick: () => setCurPage(Math.min(totalPages, curPage + 1)),
|
|
13125
|
+
disabled: curPage === totalPages,
|
|
13126
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("svg", { className: "h-4 w-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
|
|
13127
|
+
}
|
|
13128
|
+
)
|
|
13129
|
+
] }),
|
|
13130
|
+
pageSizeOptions && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13131
|
+
Combobox,
|
|
13132
|
+
{
|
|
13133
|
+
options: pageSizeOptions.map(String),
|
|
13134
|
+
value: String(curPageSize),
|
|
13135
|
+
onChange: (v) => {
|
|
13136
|
+
setCurPage(1);
|
|
13137
|
+
setCurPageSize(Number(v));
|
|
13138
|
+
},
|
|
13139
|
+
size: "sm",
|
|
13140
|
+
className: "w-20"
|
|
13141
|
+
}
|
|
13142
|
+
)
|
|
13143
|
+
] });
|
|
13144
|
+
}
|
|
13145
|
+
|
|
13146
|
+
// ../../components/ui/DataTable/components/Toolbar.tsx
|
|
13147
|
+
var import_jsx_runtime58 = require("react/jsx-runtime");
|
|
13148
|
+
function DataTableToolbar({
|
|
13149
|
+
caption,
|
|
13150
|
+
toolbar,
|
|
13151
|
+
columns,
|
|
13152
|
+
visibleCols,
|
|
13153
|
+
setVisibleCols,
|
|
13154
|
+
enableDensityToggle,
|
|
13155
|
+
enableColumnVisibilityToggle,
|
|
13156
|
+
enableHeaderAlignToggle,
|
|
13157
|
+
density,
|
|
13158
|
+
setDensity,
|
|
13159
|
+
setHeaderAlign,
|
|
13160
|
+
labels,
|
|
13161
|
+
t
|
|
13162
|
+
}) {
|
|
13163
|
+
return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "flex items-center justify-between gap-4 mb-1", children: [
|
|
13164
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "text-sm text-muted-foreground", children: caption }),
|
|
13165
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
13166
|
+
enableDensityToggle && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
13167
|
+
DropdownMenu_default,
|
|
13168
|
+
{
|
|
13169
|
+
trigger: /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
13170
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("svg", { className: "w-4 h-4 mr-1", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
|
|
13171
|
+
labels?.density || t("density")
|
|
13172
|
+
] }),
|
|
13173
|
+
items: [
|
|
13174
|
+
{ label: labels?.compact || t("compact"), onClick: () => setDensity("compact") },
|
|
13175
|
+
{ label: labels?.normal || t("normal"), onClick: () => setDensity("normal") },
|
|
13176
|
+
{ label: labels?.comfortable || t("comfortable"), onClick: () => setDensity("comfortable") }
|
|
13177
|
+
]
|
|
13178
|
+
}
|
|
13179
|
+
),
|
|
13180
|
+
enableColumnVisibilityToggle && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
13181
|
+
DropdownMenu_default,
|
|
13182
|
+
{
|
|
13183
|
+
trigger: /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
13184
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("svg", { className: "w-4 h-4 mr-1", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
13185
|
+
"path",
|
|
13186
|
+
{
|
|
13187
|
+
strokeLinecap: "round",
|
|
13188
|
+
strokeLinejoin: "round",
|
|
13189
|
+
strokeWidth: 2,
|
|
13190
|
+
d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2"
|
|
13191
|
+
}
|
|
13192
|
+
) }),
|
|
13193
|
+
labels?.columns || t("columns")
|
|
13194
|
+
] }),
|
|
13195
|
+
children: columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
|
|
13196
|
+
DropdownMenuItem,
|
|
13197
|
+
{
|
|
13198
|
+
onClick: () => {
|
|
13199
|
+
setVisibleCols((prev) => prev.includes(c.key) ? prev.filter((k) => k !== c.key) : [...prev, c.key]);
|
|
13200
|
+
},
|
|
13201
|
+
children: [
|
|
13202
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("input", { type: "checkbox", className: "mr-2 rounded-md border-border", readOnly: true, checked: visibleCols.includes(c.key) }),
|
|
13203
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "truncate", children: c.title })
|
|
13204
|
+
]
|
|
13205
|
+
},
|
|
13206
|
+
c.key
|
|
13207
|
+
))
|
|
13208
|
+
}
|
|
13209
|
+
),
|
|
13210
|
+
enableHeaderAlignToggle && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
13211
|
+
DropdownMenu_default,
|
|
13212
|
+
{
|
|
13213
|
+
trigger: /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
13214
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("svg", { className: "w-4 h-4 mr-1", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h10M4 18h16" }) }),
|
|
13215
|
+
labels?.headerAlign || t("headerAlign")
|
|
13216
|
+
] }),
|
|
13217
|
+
items: [
|
|
13218
|
+
{ label: labels?.alignLeft || t("alignLeft"), onClick: () => setHeaderAlign("left") },
|
|
13219
|
+
{ label: labels?.alignCenter || t("alignCenter"), onClick: () => setHeaderAlign("center") },
|
|
13220
|
+
{ label: labels?.alignRight || t("alignRight"), onClick: () => setHeaderAlign("right") }
|
|
13221
|
+
]
|
|
13222
|
+
}
|
|
13223
|
+
),
|
|
13224
|
+
toolbar
|
|
13225
|
+
] })
|
|
13226
|
+
] });
|
|
13227
|
+
}
|
|
13228
|
+
|
|
13229
|
+
// ../../components/ui/DataTable/hooks/useDebounced.ts
|
|
13230
|
+
var import_react32 = __toESM(require("react"), 1);
|
|
13058
13231
|
function useDebounced(value, delay = 300) {
|
|
13059
13232
|
const [debounced, setDebounced] = import_react32.default.useState(value);
|
|
13060
13233
|
import_react32.default.useEffect(() => {
|
|
@@ -13063,40 +13236,12 @@ function useDebounced(value, delay = 300) {
|
|
|
13063
13236
|
}, [value, delay]);
|
|
13064
13237
|
return debounced;
|
|
13065
13238
|
}
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
page = 1,
|
|
13073
|
-
pageSize = 20,
|
|
13074
|
-
pageSizeOptions,
|
|
13075
|
-
onQueryChange,
|
|
13076
|
-
caption,
|
|
13077
|
-
toolbar,
|
|
13078
|
-
enableColumnVisibilityToggle = true,
|
|
13079
|
-
enableDensityToggle = true,
|
|
13080
|
-
enableHeaderAlignToggle = false,
|
|
13081
|
-
striped = true,
|
|
13082
|
-
// Mặc định bật màu nền sẽn kẽ cho các dòng
|
|
13083
|
-
columnDividers = false,
|
|
13084
|
-
className,
|
|
13085
|
-
storageKey,
|
|
13086
|
-
stickyHeader = true,
|
|
13087
|
-
maxHeight = 500,
|
|
13088
|
-
labels
|
|
13089
|
-
}) {
|
|
13090
|
-
const t = useTranslations("Common");
|
|
13091
|
-
const [headerAlign, setHeaderAlign] = import_react32.default.useState("left");
|
|
13092
|
-
const [visibleCols, setVisibleCols] = import_react32.default.useState(() => columns.filter((c) => c.visible !== false).map((c) => c.key));
|
|
13093
|
-
const [filters, setFilters] = import_react32.default.useState({});
|
|
13094
|
-
const [sort, setSort] = import_react32.default.useState(null);
|
|
13095
|
-
const [density, setDensity] = import_react32.default.useState("normal");
|
|
13096
|
-
const [curPage, setCurPage] = import_react32.default.useState(page);
|
|
13097
|
-
const hasMounted = import_react32.default.useRef(false);
|
|
13098
|
-
const loadedFromStorage = import_react32.default.useRef(false);
|
|
13099
|
-
const [curPageSize, setCurPageSize] = import_react32.default.useState(() => {
|
|
13239
|
+
|
|
13240
|
+
// ../../components/ui/DataTable/hooks/usePageSizeStorage.ts
|
|
13241
|
+
var import_react33 = __toESM(require("react"), 1);
|
|
13242
|
+
function usePageSizeStorage({ pageSize, storageKey }) {
|
|
13243
|
+
const loadedFromStorage = import_react33.default.useRef(false);
|
|
13244
|
+
const [curPageSize, setCurPageSize] = import_react33.default.useState(() => {
|
|
13100
13245
|
if (typeof window === "undefined" || !storageKey) return pageSize;
|
|
13101
13246
|
try {
|
|
13102
13247
|
const saved = localStorage.getItem(`datatable_${storageKey}_pageSize`);
|
|
@@ -13111,7 +13256,11 @@ function DataTable({
|
|
|
13111
13256
|
}
|
|
13112
13257
|
return pageSize;
|
|
13113
13258
|
});
|
|
13114
|
-
|
|
13259
|
+
const hasMounted = import_react33.default.useRef(false);
|
|
13260
|
+
import_react33.default.useEffect(() => {
|
|
13261
|
+
hasMounted.current = true;
|
|
13262
|
+
}, []);
|
|
13263
|
+
import_react33.default.useEffect(() => {
|
|
13115
13264
|
if (typeof window === "undefined" || !storageKey) return;
|
|
13116
13265
|
if (!hasMounted.current) return;
|
|
13117
13266
|
try {
|
|
@@ -13119,49 +13268,33 @@ function DataTable({
|
|
|
13119
13268
|
} catch {
|
|
13120
13269
|
}
|
|
13121
13270
|
}, [curPageSize, storageKey]);
|
|
13122
|
-
|
|
13123
|
-
|
|
13124
|
-
setVisibleCols((prev) => {
|
|
13125
|
-
const uniqueKeys = /* @__PURE__ */ new Set([...prev, ...newColKeys]);
|
|
13126
|
-
return [...uniqueKeys].filter((k) => columns.some((c) => c.key === k));
|
|
13127
|
-
});
|
|
13128
|
-
}, [columns]);
|
|
13129
|
-
const debouncedFilters = useDebounced(filters, 350);
|
|
13130
|
-
import_react32.default.useEffect(() => {
|
|
13131
|
-
setCurPage(page);
|
|
13132
|
-
}, [page]);
|
|
13133
|
-
import_react32.default.useEffect(() => {
|
|
13134
|
-
if (storageKey && loadedFromStorage.current) {
|
|
13135
|
-
return;
|
|
13136
|
-
}
|
|
13271
|
+
import_react33.default.useEffect(() => {
|
|
13272
|
+
if (storageKey && loadedFromStorage.current) return;
|
|
13137
13273
|
setCurPageSize(pageSize);
|
|
13138
13274
|
}, [pageSize, storageKey]);
|
|
13139
|
-
|
|
13140
|
-
|
|
13141
|
-
|
|
13142
|
-
|
|
13143
|
-
|
|
13144
|
-
|
|
13145
|
-
|
|
13146
|
-
|
|
13147
|
-
|
|
13148
|
-
const
|
|
13149
|
-
const
|
|
13150
|
-
|
|
13151
|
-
|
|
13152
|
-
|
|
13153
|
-
|
|
13154
|
-
|
|
13155
|
-
|
|
13156
|
-
}, [visibleColumns]);
|
|
13157
|
-
const stickyPositions = import_react32.default.useMemo(() => {
|
|
13275
|
+
return { curPageSize, setCurPageSize, loadedFromStorage };
|
|
13276
|
+
}
|
|
13277
|
+
|
|
13278
|
+
// ../../components/ui/DataTable/hooks/useStickyColumns.ts
|
|
13279
|
+
var import_react34 = __toESM(require("react"), 1);
|
|
13280
|
+
|
|
13281
|
+
// ../../components/ui/DataTable/utils/columns.ts
|
|
13282
|
+
function getColumnWidth(col, fallback = 150) {
|
|
13283
|
+
if (typeof col.width === "number") return col.width;
|
|
13284
|
+
const raw = col.width ? String(col.width) : String(fallback);
|
|
13285
|
+
const parsed = parseInt(raw, 10);
|
|
13286
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
13287
|
+
}
|
|
13288
|
+
|
|
13289
|
+
// ../../components/ui/DataTable/hooks/useStickyColumns.ts
|
|
13290
|
+
function useStickyColumns(visibleColumns) {
|
|
13291
|
+
const stickyPositions = import_react34.default.useMemo(() => {
|
|
13158
13292
|
const positions = {};
|
|
13159
13293
|
let leftOffset = 0;
|
|
13160
13294
|
for (const col of visibleColumns) {
|
|
13161
13295
|
if (col.fixed === "left") {
|
|
13162
13296
|
positions[col.key] = { left: leftOffset };
|
|
13163
|
-
|
|
13164
|
-
leftOffset += colWidth;
|
|
13297
|
+
leftOffset += getColumnWidth(col);
|
|
13165
13298
|
}
|
|
13166
13299
|
}
|
|
13167
13300
|
let rightOffset = 0;
|
|
@@ -13169,30 +13302,105 @@ function DataTable({
|
|
|
13169
13302
|
const col = visibleColumns[i];
|
|
13170
13303
|
if (col.fixed === "right") {
|
|
13171
13304
|
positions[col.key] = { right: rightOffset };
|
|
13172
|
-
|
|
13173
|
-
rightOffset += colWidth;
|
|
13305
|
+
rightOffset += getColumnWidth(col);
|
|
13174
13306
|
}
|
|
13175
13307
|
}
|
|
13176
13308
|
return positions;
|
|
13177
13309
|
}, [visibleColumns]);
|
|
13178
|
-
const
|
|
13310
|
+
const getStickyColumnStyle = import_react34.default.useCallback(
|
|
13311
|
+
(col) => {
|
|
13312
|
+
if (!col.fixed) return {};
|
|
13313
|
+
const pos = stickyPositions[col.key];
|
|
13314
|
+
return {
|
|
13315
|
+
...pos?.left !== void 0 && { left: pos.left },
|
|
13316
|
+
...pos?.right !== void 0 && { right: pos.right }
|
|
13317
|
+
};
|
|
13318
|
+
},
|
|
13319
|
+
[stickyPositions]
|
|
13320
|
+
);
|
|
13321
|
+
const getStickyHeaderClass = import_react34.default.useCallback((col) => {
|
|
13179
13322
|
if (!col.fixed) return "";
|
|
13180
13323
|
return cn(
|
|
13181
13324
|
"sticky",
|
|
13182
13325
|
col.fixed === "left" && "left-0 shadow-[2px_0_5px_-2px_rgba(0,0,0,0.15)]",
|
|
13183
13326
|
col.fixed === "right" && "right-0 shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.15)]",
|
|
13184
|
-
|
|
13185
|
-
isHeader ? "z-50 bg-muted!" : "z-10 bg-card!"
|
|
13327
|
+
"z-50 bg-muted!"
|
|
13186
13328
|
);
|
|
13187
|
-
};
|
|
13188
|
-
const
|
|
13189
|
-
if (!col.fixed) return
|
|
13190
|
-
|
|
13191
|
-
|
|
13192
|
-
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
|
|
13329
|
+
}, []);
|
|
13330
|
+
const getStickyCellClass = import_react34.default.useCallback((col, isStripedRow) => {
|
|
13331
|
+
if (!col.fixed) return "";
|
|
13332
|
+
return cn(
|
|
13333
|
+
"sticky z-10",
|
|
13334
|
+
col.fixed === "left" && "left-0 shadow-[2px_0_5px_-2px_rgba(0,0,0,0.15)]",
|
|
13335
|
+
col.fixed === "right" && "right-0 shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.15)]",
|
|
13336
|
+
isStripedRow ? "bg-muted!" : "bg-card!"
|
|
13337
|
+
);
|
|
13338
|
+
}, []);
|
|
13339
|
+
return { getStickyColumnStyle, getStickyHeaderClass, getStickyCellClass };
|
|
13340
|
+
}
|
|
13341
|
+
|
|
13342
|
+
// ../../components/ui/DataTable/DataTable.tsx
|
|
13343
|
+
var import_jsx_runtime59 = require("react/jsx-runtime");
|
|
13344
|
+
function DataTable({
|
|
13345
|
+
columns,
|
|
13346
|
+
data,
|
|
13347
|
+
rowKey,
|
|
13348
|
+
loading: loading2,
|
|
13349
|
+
total = 0,
|
|
13350
|
+
page = 1,
|
|
13351
|
+
pageSize = 20,
|
|
13352
|
+
pageSizeOptions,
|
|
13353
|
+
onQueryChange,
|
|
13354
|
+
caption,
|
|
13355
|
+
toolbar,
|
|
13356
|
+
enableColumnVisibilityToggle = true,
|
|
13357
|
+
enableDensityToggle = true,
|
|
13358
|
+
enableHeaderAlignToggle = false,
|
|
13359
|
+
striped = true,
|
|
13360
|
+
columnDividers = false,
|
|
13361
|
+
className,
|
|
13362
|
+
storageKey,
|
|
13363
|
+
stickyHeader = true,
|
|
13364
|
+
maxHeight = 500,
|
|
13365
|
+
labels
|
|
13366
|
+
}) {
|
|
13367
|
+
const t = useTranslations("Common");
|
|
13368
|
+
const [headerAlign, setHeaderAlign] = import_react35.default.useState("left");
|
|
13369
|
+
const [visibleCols, setVisibleCols] = import_react35.default.useState(() => columns.filter((c) => c.visible !== false).map((c) => c.key));
|
|
13370
|
+
const [filters, setFilters] = import_react35.default.useState({});
|
|
13371
|
+
const [sort, setSort] = import_react35.default.useState(null);
|
|
13372
|
+
const [density, setDensity] = import_react35.default.useState("normal");
|
|
13373
|
+
const [curPage, setCurPage] = import_react35.default.useState(page);
|
|
13374
|
+
const { curPageSize, setCurPageSize } = usePageSizeStorage({ pageSize, storageKey });
|
|
13375
|
+
import_react35.default.useEffect(() => {
|
|
13376
|
+
const newColKeys = columns.filter((c) => c.visible !== false).map((c) => c.key);
|
|
13377
|
+
setVisibleCols((prev) => {
|
|
13378
|
+
const uniqueKeys = /* @__PURE__ */ new Set([...prev, ...newColKeys]);
|
|
13379
|
+
return [...uniqueKeys].filter((k) => columns.some((c) => c.key === k));
|
|
13380
|
+
});
|
|
13381
|
+
}, [columns]);
|
|
13382
|
+
const debouncedFilters = useDebounced(filters, 350);
|
|
13383
|
+
import_react35.default.useEffect(() => {
|
|
13384
|
+
setCurPage(page);
|
|
13385
|
+
}, [page]);
|
|
13386
|
+
const isServerMode = Boolean(onQueryChange);
|
|
13387
|
+
const hasEmittedQuery = import_react35.default.useRef(false);
|
|
13388
|
+
import_react35.default.useEffect(() => {
|
|
13389
|
+
if (!onQueryChange) return;
|
|
13390
|
+
if (!hasEmittedQuery.current) {
|
|
13391
|
+
hasEmittedQuery.current = true;
|
|
13392
|
+
return;
|
|
13393
|
+
}
|
|
13394
|
+
onQueryChange({ filters: debouncedFilters, sort, page: curPage, pageSize: curPageSize });
|
|
13395
|
+
}, [debouncedFilters, sort, curPage, curPageSize, onQueryChange]);
|
|
13396
|
+
const densityRowClass = density === "compact" ? "h-9" : density === "comfortable" ? "h-14" : "h-12";
|
|
13397
|
+
const cellPadding = density === "compact" ? "py-1.5 px-3" : density === "comfortable" ? "py-3 px-4" : "py-2.5 px-4";
|
|
13398
|
+
const visibleColsSet = import_react35.default.useMemo(() => new Set(visibleCols), [visibleCols]);
|
|
13399
|
+
const visibleColumns = columns.filter((c) => visibleColsSet.has(c.key));
|
|
13400
|
+
const totalColumnsWidth = import_react35.default.useMemo(() => {
|
|
13401
|
+
return visibleColumns.reduce((sum, col) => sum + getColumnWidth(col), 0);
|
|
13402
|
+
}, [visibleColumns]);
|
|
13403
|
+
const { getStickyCellClass, getStickyColumnStyle, getStickyHeaderClass } = useStickyColumns(visibleColumns);
|
|
13196
13404
|
const getRowKey = (row, idx) => {
|
|
13197
13405
|
if (!rowKey) return String(idx);
|
|
13198
13406
|
if (typeof rowKey === "function") return String(rowKey(row));
|
|
@@ -13201,11 +13409,9 @@ function DataTable({
|
|
|
13201
13409
|
const renderFilterControl = (col) => {
|
|
13202
13410
|
if (!col.filter) return null;
|
|
13203
13411
|
const k = col.key;
|
|
13204
|
-
const commonProps = {
|
|
13205
|
-
className: "h-8 w-full text-sm"
|
|
13206
|
-
};
|
|
13412
|
+
const commonProps = { className: "h-8 w-full text-sm" };
|
|
13207
13413
|
if (col.filter.type === "text") {
|
|
13208
|
-
return /* @__PURE__ */ (0,
|
|
13414
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13209
13415
|
Input_default,
|
|
13210
13416
|
{
|
|
13211
13417
|
...commonProps,
|
|
@@ -13220,7 +13426,7 @@ function DataTable({
|
|
|
13220
13426
|
}
|
|
13221
13427
|
if (col.filter.type === "select") {
|
|
13222
13428
|
const options = col.filter.options || [];
|
|
13223
|
-
return /* @__PURE__ */ (0,
|
|
13429
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13224
13430
|
Combobox,
|
|
13225
13431
|
{
|
|
13226
13432
|
options: ["", ...options],
|
|
@@ -13236,7 +13442,7 @@ function DataTable({
|
|
|
13236
13442
|
);
|
|
13237
13443
|
}
|
|
13238
13444
|
if (col.filter.type === "date") {
|
|
13239
|
-
return /* @__PURE__ */ (0,
|
|
13445
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13240
13446
|
DatePicker,
|
|
13241
13447
|
{
|
|
13242
13448
|
placeholder: col.filter.placeholder || `Select ${String(col.title)}`,
|
|
@@ -13250,122 +13456,105 @@ function DataTable({
|
|
|
13250
13456
|
}
|
|
13251
13457
|
return null;
|
|
13252
13458
|
};
|
|
13253
|
-
const renderHeader = /* @__PURE__ */ (0,
|
|
13459
|
+
const renderHeader = /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(TableRow, { children: visibleColumns.map((col, colIdx) => {
|
|
13254
13460
|
const prevCol = colIdx > 0 ? visibleColumns[colIdx - 1] : null;
|
|
13255
13461
|
const isAfterFixedLeft = prevCol?.fixed === "left";
|
|
13256
13462
|
const showBorderLeft = columnDividers && colIdx > 0 && !isAfterFixedLeft && !col.fixed;
|
|
13257
|
-
return /* @__PURE__ */ (0,
|
|
13463
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13258
13464
|
TableHead,
|
|
13259
13465
|
{
|
|
13260
13466
|
style: { width: col.width, ...getStickyColumnStyle(col) },
|
|
13261
13467
|
className: cn(
|
|
13262
|
-
// Use column-specific align if defined, otherwise use global headerAlign
|
|
13263
13468
|
(col.align === "right" || !col.align && headerAlign === "right") && "text-right",
|
|
13264
13469
|
(col.align === "center" || !col.align && headerAlign === "center") && "text-center",
|
|
13265
13470
|
showBorderLeft && "border-l border-border/60",
|
|
13266
|
-
|
|
13471
|
+
getStickyHeaderClass(col)
|
|
13267
13472
|
),
|
|
13268
13473
|
children: (() => {
|
|
13269
13474
|
const isRightAlign = col.align === "right" || !col.align && headerAlign === "right";
|
|
13270
13475
|
const isCenterAlign = col.align === "center" || !col.align && headerAlign === "center";
|
|
13271
|
-
const titleContent = /* @__PURE__ */ (0,
|
|
13272
|
-
"
|
|
13273
|
-
|
|
13274
|
-
|
|
13275
|
-
|
|
13276
|
-
|
|
13277
|
-
|
|
13278
|
-
|
|
13279
|
-
|
|
13280
|
-
|
|
13281
|
-
|
|
13282
|
-
|
|
13283
|
-
|
|
13284
|
-
|
|
13285
|
-
|
|
13286
|
-
|
|
13287
|
-
|
|
13288
|
-
|
|
13289
|
-
|
|
13290
|
-
|
|
13291
|
-
|
|
13292
|
-
|
|
13293
|
-
|
|
13294
|
-
|
|
13295
|
-
|
|
13296
|
-
|
|
13297
|
-
|
|
13298
|
-
|
|
13299
|
-
|
|
13300
|
-
|
|
13301
|
-
|
|
13302
|
-
|
|
13303
|
-
|
|
13304
|
-
|
|
13305
|
-
|
|
13306
|
-
|
|
13307
|
-
|
|
13308
|
-
|
|
13309
|
-
|
|
13310
|
-
|
|
13311
|
-
|
|
13312
|
-
|
|
13313
|
-
|
|
13314
|
-
|
|
13315
|
-
|
|
13316
|
-
|
|
13317
|
-
|
|
13318
|
-
opacity: sort?.key === col.key && sort.order === "desc" ? 1 : 0.4
|
|
13319
|
-
}
|
|
13320
|
-
)
|
|
13321
|
-
] })
|
|
13322
|
-
}
|
|
13323
|
-
)
|
|
13324
|
-
]
|
|
13325
|
-
}
|
|
13326
|
-
);
|
|
13327
|
-
const filterContent = col.filter && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13476
|
+
const titleContent = /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: cn("flex items-center gap-1", !col.fixed && "min-w-0 shrink"), children: [
|
|
13477
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: cn("font-medium text-sm", !col.fixed && "truncate"), children: col.title }),
|
|
13478
|
+
col.sortable && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13479
|
+
"button",
|
|
13480
|
+
{
|
|
13481
|
+
className: cn(
|
|
13482
|
+
"p-1 rounded-lg transition-all duration-200 hover:bg-accent",
|
|
13483
|
+
sort?.key === col.key ? "opacity-100 bg-accent" : "opacity-60 hover:opacity-100"
|
|
13484
|
+
),
|
|
13485
|
+
onClick: () => {
|
|
13486
|
+
setCurPage(1);
|
|
13487
|
+
setSort((s) => {
|
|
13488
|
+
if (!s || s.key !== col.key) return { key: col.key, order: "asc" };
|
|
13489
|
+
if (s.order === "asc") return { key: col.key, order: "desc" };
|
|
13490
|
+
return null;
|
|
13491
|
+
});
|
|
13492
|
+
},
|
|
13493
|
+
"aria-label": "Sort",
|
|
13494
|
+
title: `Sort by ${String(col.title)}`,
|
|
13495
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 20 20", fill: "none", className: "inline-block", children: [
|
|
13496
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13497
|
+
"path",
|
|
13498
|
+
{
|
|
13499
|
+
d: "M7 8l3-3 3 3",
|
|
13500
|
+
stroke: "currentColor",
|
|
13501
|
+
strokeWidth: "1.5",
|
|
13502
|
+
strokeLinecap: "round",
|
|
13503
|
+
strokeLinejoin: "round",
|
|
13504
|
+
opacity: sort?.key === col.key && sort.order === "asc" ? 1 : 0.4
|
|
13505
|
+
}
|
|
13506
|
+
),
|
|
13507
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13508
|
+
"path",
|
|
13509
|
+
{
|
|
13510
|
+
d: "M7 12l3 3 3-3",
|
|
13511
|
+
stroke: "currentColor",
|
|
13512
|
+
strokeWidth: "1.5",
|
|
13513
|
+
strokeLinecap: "round",
|
|
13514
|
+
strokeLinejoin: "round",
|
|
13515
|
+
opacity: sort?.key === col.key && sort.order === "desc" ? 1 : 0.4
|
|
13516
|
+
}
|
|
13517
|
+
)
|
|
13518
|
+
] })
|
|
13519
|
+
}
|
|
13520
|
+
)
|
|
13521
|
+
] });
|
|
13522
|
+
const filterContent = col.filter ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13328
13523
|
Popover,
|
|
13329
13524
|
{
|
|
13330
|
-
placement:
|
|
13331
|
-
trigger: /* @__PURE__ */ (0,
|
|
13525
|
+
placement: "bottom-start",
|
|
13526
|
+
trigger: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13332
13527
|
"button",
|
|
13333
13528
|
{
|
|
13334
13529
|
className: cn(
|
|
13335
|
-
"p-1.5 rounded-lg
|
|
13336
|
-
"
|
|
13337
|
-
filters[col.key] && "bg-accent text-foreground"
|
|
13530
|
+
"p-1.5 rounded-lg transition-all duration-200 hover:bg-accent",
|
|
13531
|
+
filters[col.key] ? "bg-accent text-primary" : "text-muted-foreground"
|
|
13338
13532
|
),
|
|
13339
13533
|
"aria-label": "Filter",
|
|
13340
|
-
title:
|
|
13341
|
-
children: /* @__PURE__ */ (0,
|
|
13534
|
+
title: `Filter by ${String(col.title)}`,
|
|
13535
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(import_lucide_react27.Filter, { className: "w-4 h-4" })
|
|
13342
13536
|
}
|
|
13343
13537
|
),
|
|
13344
|
-
children: /* @__PURE__ */ (0,
|
|
13345
|
-
/* @__PURE__ */ (0,
|
|
13346
|
-
"
|
|
13347
|
-
col.
|
|
13538
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "p-3 w-64 space-y-3", children: [
|
|
13539
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
13540
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "text-sm font-medium", children: col.title }),
|
|
13541
|
+
filters[col.key] !== void 0 && filters[col.key] !== null && filters[col.key] !== "" && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13542
|
+
"button",
|
|
13543
|
+
{
|
|
13544
|
+
onClick: () => {
|
|
13545
|
+
setCurPage(1);
|
|
13546
|
+
setFilters((f) => ({ ...f, [col.key]: void 0 }));
|
|
13547
|
+
},
|
|
13548
|
+
className: "text-xs text-destructive hover:underline",
|
|
13549
|
+
children: t("clearFilter")
|
|
13550
|
+
}
|
|
13551
|
+
)
|
|
13348
13552
|
] }),
|
|
13349
|
-
renderFilterControl(col)
|
|
13350
|
-
filters[col.key] && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13351
|
-
"button",
|
|
13352
|
-
{
|
|
13353
|
-
onClick: () => {
|
|
13354
|
-
setCurPage(1);
|
|
13355
|
-
setFilters((f) => {
|
|
13356
|
-
const newFilters = { ...f };
|
|
13357
|
-
delete newFilters[col.key];
|
|
13358
|
-
return newFilters;
|
|
13359
|
-
});
|
|
13360
|
-
},
|
|
13361
|
-
className: "text-xs text-destructive hover:underline",
|
|
13362
|
-
children: t("clearFilter")
|
|
13363
|
-
}
|
|
13364
|
-
)
|
|
13553
|
+
renderFilterControl(col)
|
|
13365
13554
|
] })
|
|
13366
13555
|
}
|
|
13367
|
-
);
|
|
13368
|
-
return /* @__PURE__ */ (0,
|
|
13556
|
+
) : null;
|
|
13557
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13369
13558
|
"div",
|
|
13370
13559
|
{
|
|
13371
13560
|
className: cn(
|
|
@@ -13374,10 +13563,10 @@ function DataTable({
|
|
|
13374
13563
|
isCenterAlign && "justify-center",
|
|
13375
13564
|
!isRightAlign && !isCenterAlign && "justify-start"
|
|
13376
13565
|
),
|
|
13377
|
-
children: isRightAlign ? /* @__PURE__ */ (0,
|
|
13566
|
+
children: isRightAlign ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(import_jsx_runtime59.Fragment, { children: [
|
|
13378
13567
|
filterContent,
|
|
13379
13568
|
titleContent
|
|
13380
|
-
] }) : /* @__PURE__ */ (0,
|
|
13569
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(import_jsx_runtime59.Fragment, { children: [
|
|
13381
13570
|
titleContent,
|
|
13382
13571
|
filterContent
|
|
13383
13572
|
] })
|
|
@@ -13388,13 +13577,12 @@ function DataTable({
|
|
|
13388
13577
|
col.key
|
|
13389
13578
|
);
|
|
13390
13579
|
}) });
|
|
13391
|
-
const
|
|
13392
|
-
const processedData = import_react32.default.useMemo(() => {
|
|
13580
|
+
const processedData = import_react35.default.useMemo(() => {
|
|
13393
13581
|
if (isServerMode) return data;
|
|
13394
13582
|
let result = [...data];
|
|
13395
13583
|
if (Object.keys(filters).length > 0) {
|
|
13396
|
-
result = result.filter(
|
|
13397
|
-
|
|
13584
|
+
result = result.filter(
|
|
13585
|
+
(row) => Object.entries(filters).every(([key, value]) => {
|
|
13398
13586
|
if (value === void 0 || value === null || value === "") return true;
|
|
13399
13587
|
const col = columns.find((c) => c.key === key);
|
|
13400
13588
|
const rowValue = col?.dataIndex ? row[col.dataIndex] : row[key];
|
|
@@ -13402,8 +13590,8 @@ function DataTable({
|
|
|
13402
13590
|
return new Date(rowValue).toDateString() === value.toDateString();
|
|
13403
13591
|
}
|
|
13404
13592
|
return String(rowValue ?? "").toLowerCase().includes(String(value).toLowerCase());
|
|
13405
|
-
})
|
|
13406
|
-
|
|
13593
|
+
})
|
|
13594
|
+
);
|
|
13407
13595
|
}
|
|
13408
13596
|
if (sort) {
|
|
13409
13597
|
result.sort((a, b) => {
|
|
@@ -13421,78 +13609,30 @@ function DataTable({
|
|
|
13421
13609
|
return result;
|
|
13422
13610
|
}, [data, isServerMode, filters, sort, columns]);
|
|
13423
13611
|
const totalItems = isServerMode ? total : processedData.length;
|
|
13424
|
-
const displayedData = isServerMode ? data :
|
|
13612
|
+
const displayedData = isServerMode ? data : import_react35.default.useMemo(() => {
|
|
13425
13613
|
const start = (curPage - 1) * curPageSize;
|
|
13426
|
-
if (start >= processedData.length && curPage > 1) {
|
|
13427
|
-
}
|
|
13428
13614
|
return processedData.slice(start, start + curPageSize);
|
|
13429
13615
|
}, [processedData, curPage, curPageSize]);
|
|
13430
|
-
return /* @__PURE__ */ (0,
|
|
13431
|
-
/* @__PURE__ */ (0,
|
|
13432
|
-
|
|
13433
|
-
|
|
13434
|
-
|
|
13435
|
-
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
|
|
13441
|
-
|
|
13442
|
-
|
|
13443
|
-
|
|
13444
|
-
|
|
13445
|
-
|
|
13446
|
-
|
|
13447
|
-
|
|
13448
|
-
|
|
13449
|
-
|
|
13450
|
-
{
|
|
13451
|
-
trigger: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
13452
|
-
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("svg", { className: "w-4 h-4 mr-1", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13453
|
-
"path",
|
|
13454
|
-
{
|
|
13455
|
-
strokeLinecap: "round",
|
|
13456
|
-
strokeLinejoin: "round",
|
|
13457
|
-
strokeWidth: 2,
|
|
13458
|
-
d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2"
|
|
13459
|
-
}
|
|
13460
|
-
) }),
|
|
13461
|
-
labels?.columns || t("columns")
|
|
13462
|
-
] }),
|
|
13463
|
-
children: columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
|
|
13464
|
-
DropdownMenuItem,
|
|
13465
|
-
{
|
|
13466
|
-
onClick: () => {
|
|
13467
|
-
setVisibleCols((prev) => prev.includes(c.key) ? prev.filter((k) => k !== c.key) : [...prev, c.key]);
|
|
13468
|
-
},
|
|
13469
|
-
children: [
|
|
13470
|
-
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("input", { type: "checkbox", className: "mr-2 rounded-md border-border", readOnly: true, checked: visibleCols.includes(c.key) }),
|
|
13471
|
-
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "truncate", children: c.title })
|
|
13472
|
-
]
|
|
13473
|
-
},
|
|
13474
|
-
c.key
|
|
13475
|
-
))
|
|
13476
|
-
}
|
|
13477
|
-
),
|
|
13478
|
-
enableHeaderAlignToggle && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13479
|
-
DropdownMenu_default,
|
|
13480
|
-
{
|
|
13481
|
-
trigger: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
13482
|
-
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("svg", { className: "w-4 h-4 mr-1", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h10M4 18h16" }) }),
|
|
13483
|
-
labels?.headerAlign || t("headerAlign")
|
|
13484
|
-
] }),
|
|
13485
|
-
items: [
|
|
13486
|
-
{ label: labels?.alignLeft || t("alignLeft"), onClick: () => setHeaderAlign("left") },
|
|
13487
|
-
{ label: labels?.alignCenter || t("alignCenter"), onClick: () => setHeaderAlign("center") },
|
|
13488
|
-
{ label: labels?.alignRight || t("alignRight"), onClick: () => setHeaderAlign("right") }
|
|
13489
|
-
]
|
|
13490
|
-
}
|
|
13491
|
-
),
|
|
13492
|
-
toolbar
|
|
13493
|
-
] })
|
|
13494
|
-
] }),
|
|
13495
|
-
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13616
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: cn("space-y-2", className), children: [
|
|
13617
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13618
|
+
DataTableToolbar,
|
|
13619
|
+
{
|
|
13620
|
+
caption,
|
|
13621
|
+
toolbar,
|
|
13622
|
+
columns,
|
|
13623
|
+
visibleCols,
|
|
13624
|
+
setVisibleCols,
|
|
13625
|
+
enableDensityToggle,
|
|
13626
|
+
enableColumnVisibilityToggle,
|
|
13627
|
+
enableHeaderAlignToggle,
|
|
13628
|
+
density,
|
|
13629
|
+
setDensity,
|
|
13630
|
+
setHeaderAlign,
|
|
13631
|
+
labels,
|
|
13632
|
+
t
|
|
13633
|
+
}
|
|
13634
|
+
),
|
|
13635
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13496
13636
|
"div",
|
|
13497
13637
|
{
|
|
13498
13638
|
className: cn("relative rounded-2xl md:rounded-3xl border border-border/50", loading2 && "opacity-60 pointer-events-none"),
|
|
@@ -13501,7 +13641,7 @@ function DataTable({
|
|
|
13501
13641
|
overflowY: "auto",
|
|
13502
13642
|
overflowX: "auto"
|
|
13503
13643
|
} : { overflowX: "auto" },
|
|
13504
|
-
children: /* @__PURE__ */ (0,
|
|
13644
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
|
|
13505
13645
|
Table,
|
|
13506
13646
|
{
|
|
13507
13647
|
containerClassName: cn("border-0 md:border-0 rounded-none md:rounded-none shadow-none bg-transparent", "overflow-visible"),
|
|
@@ -13511,11 +13651,11 @@ function DataTable({
|
|
|
13511
13651
|
),
|
|
13512
13652
|
style: { minWidth: totalColumnsWidth > 0 ? `${totalColumnsWidth}px` : void 0 },
|
|
13513
13653
|
children: [
|
|
13514
|
-
/* @__PURE__ */ (0,
|
|
13515
|
-
/* @__PURE__ */ (0,
|
|
13516
|
-
/* @__PURE__ */ (0,
|
|
13517
|
-
/* @__PURE__ */ (0,
|
|
13518
|
-
/* @__PURE__ */ (0,
|
|
13654
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(TableHeader, { children: renderHeader }),
|
|
13655
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(TableBody, { children: loading2 ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(TableCell, { colSpan: visibleColumns.length, className: "text-center py-8", children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "flex items-center justify-center gap-2 text-muted-foreground", children: [
|
|
13656
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("svg", { className: "animate-spin h-4 w-4", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
13657
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
13658
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13519
13659
|
"path",
|
|
13520
13660
|
{
|
|
13521
13661
|
className: "opacity-75",
|
|
@@ -13524,18 +13664,17 @@ function DataTable({
|
|
|
13524
13664
|
}
|
|
13525
13665
|
)
|
|
13526
13666
|
] }),
|
|
13527
|
-
/* @__PURE__ */ (0,
|
|
13667
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "text-sm", children: [
|
|
13528
13668
|
t("loading"),
|
|
13529
13669
|
"\u2026"
|
|
13530
13670
|
] })
|
|
13531
|
-
] }) }) }) : !displayedData || displayedData.length === 0 ? /* @__PURE__ */ (0,
|
|
13671
|
+
] }) }) }) : !displayedData || displayedData.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(TableCell, { colSpan: visibleColumns.length, className: "text-center py-6 text-muted-foreground", children: t("noData") }) }) : displayedData.map((row, idx) => {
|
|
13532
13672
|
const isLastRow = idx === displayedData.length - 1;
|
|
13533
|
-
return /* @__PURE__ */ (0,
|
|
13673
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13534
13674
|
TableRow,
|
|
13535
13675
|
{
|
|
13536
13676
|
className: cn(densityRowClass),
|
|
13537
13677
|
style: {
|
|
13538
|
-
// content-visibility: auto for rendering performance (skip off-screen rows)
|
|
13539
13678
|
contentVisibility: "auto",
|
|
13540
13679
|
containIntrinsicSize: density === "compact" ? "0 36px" : density === "comfortable" ? "0 56px" : "0 48px"
|
|
13541
13680
|
},
|
|
@@ -13545,7 +13684,7 @@ function DataTable({
|
|
|
13545
13684
|
const prevCol = colIdx > 0 ? visibleColumns[colIdx - 1] : null;
|
|
13546
13685
|
const isAfterFixedLeft = prevCol?.fixed === "left";
|
|
13547
13686
|
const showBorderLeft = columnDividers && colIdx > 0 && !isAfterFixedLeft && !col.fixed;
|
|
13548
|
-
return /* @__PURE__ */ (0,
|
|
13687
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13549
13688
|
TableCell,
|
|
13550
13689
|
{
|
|
13551
13690
|
style: getStickyColumnStyle(col),
|
|
@@ -13556,13 +13695,8 @@ function DataTable({
|
|
|
13556
13695
|
showBorderLeft && "border-l border-border/60",
|
|
13557
13696
|
isLastRow && col === visibleColumns[0] && "rounded-bl-2xl md:rounded-bl-3xl",
|
|
13558
13697
|
isLastRow && col === visibleColumns[visibleColumns.length - 1] && "rounded-br-2xl md:rounded-br-3xl",
|
|
13559
|
-
|
|
13560
|
-
col.fixed
|
|
13561
|
-
"sticky z-10",
|
|
13562
|
-
col.fixed === "left" && "left-0 shadow-[2px_0_5px_-2px_rgba(0,0,0,0.15)]",
|
|
13563
|
-
col.fixed === "right" && "right-0 shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.15)]",
|
|
13564
|
-
isStripedRow ? "bg-muted!" : "bg-card!"
|
|
13565
|
-
) : isStripedRow && "bg-muted/50"
|
|
13698
|
+
getStickyCellClass(col, isStripedRow),
|
|
13699
|
+
!col.fixed && isStripedRow && "bg-muted/50"
|
|
13566
13700
|
),
|
|
13567
13701
|
children: col.render ? col.render(value, row, idx) : String(value ?? "")
|
|
13568
13702
|
},
|
|
@@ -13578,90 +13712,26 @@ function DataTable({
|
|
|
13578
13712
|
)
|
|
13579
13713
|
}
|
|
13580
13714
|
),
|
|
13581
|
-
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
|
|
13587
|
-
|
|
13588
|
-
|
|
13589
|
-
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
{
|
|
13593
|
-
variant: "ghost",
|
|
13594
|
-
size: "sm",
|
|
13595
|
-
className: "h-7 w-7 p-0 rounded-full",
|
|
13596
|
-
onClick: () => setCurPage(Math.max(1, curPage - 1)),
|
|
13597
|
-
disabled: curPage === 1,
|
|
13598
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("svg", { className: "h-4 w-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
|
|
13599
|
-
}
|
|
13600
|
-
),
|
|
13601
|
-
(() => {
|
|
13602
|
-
const totalPages = Math.ceil(totalItems / curPageSize);
|
|
13603
|
-
const pages = [];
|
|
13604
|
-
if (totalPages <= 5) {
|
|
13605
|
-
for (let i = 1; i <= totalPages; i++) pages.push(i);
|
|
13606
|
-
} else {
|
|
13607
|
-
pages.push(1);
|
|
13608
|
-
if (curPage > 3) pages.push("...");
|
|
13609
|
-
const start = Math.max(2, curPage - 1);
|
|
13610
|
-
const end = Math.min(totalPages - 1, curPage + 1);
|
|
13611
|
-
for (let i = start; i <= end; i++) pages.push(i);
|
|
13612
|
-
if (curPage < totalPages - 2) pages.push("...");
|
|
13613
|
-
pages.push(totalPages);
|
|
13614
|
-
}
|
|
13615
|
-
return pages.map(
|
|
13616
|
-
(p, i) => p === "..." ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "px-1 text-muted-foreground/60", children: "\u2026" }, `dots-${i}`) : /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13617
|
-
"button",
|
|
13618
|
-
{
|
|
13619
|
-
onClick: () => setCurPage(p),
|
|
13620
|
-
className: cn(
|
|
13621
|
-
"h-7 min-w-7 px-2 rounded-full text-xs font-medium transition-colors",
|
|
13622
|
-
curPage === p ? "bg-primary text-primary-foreground" : "hover:bg-accent hover:text-accent-foreground"
|
|
13623
|
-
),
|
|
13624
|
-
children: p
|
|
13625
|
-
},
|
|
13626
|
-
p
|
|
13627
|
-
)
|
|
13628
|
-
);
|
|
13629
|
-
})(),
|
|
13630
|
-
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13631
|
-
Button_default,
|
|
13632
|
-
{
|
|
13633
|
-
variant: "ghost",
|
|
13634
|
-
size: "sm",
|
|
13635
|
-
className: "h-7 w-7 p-0 rounded-full",
|
|
13636
|
-
onClick: () => setCurPage(Math.min(Math.ceil(totalItems / curPageSize), curPage + 1)),
|
|
13637
|
-
disabled: curPage === Math.ceil(totalItems / curPageSize),
|
|
13638
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("svg", { className: "h-4 w-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
|
|
13639
|
-
}
|
|
13640
|
-
)
|
|
13641
|
-
] }),
|
|
13642
|
-
pageSizeOptions && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13643
|
-
Combobox,
|
|
13644
|
-
{
|
|
13645
|
-
options: pageSizeOptions.map(String),
|
|
13646
|
-
value: String(curPageSize),
|
|
13647
|
-
onChange: (v) => {
|
|
13648
|
-
setCurPage(1);
|
|
13649
|
-
setCurPageSize(Number(v));
|
|
13650
|
-
},
|
|
13651
|
-
size: "sm",
|
|
13652
|
-
className: "w-20"
|
|
13653
|
-
}
|
|
13654
|
-
)
|
|
13655
|
-
] })
|
|
13715
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13716
|
+
DataTablePagination,
|
|
13717
|
+
{
|
|
13718
|
+
totalItems,
|
|
13719
|
+
curPage,
|
|
13720
|
+
curPageSize,
|
|
13721
|
+
setCurPage,
|
|
13722
|
+
pageSizeOptions,
|
|
13723
|
+
setCurPageSize
|
|
13724
|
+
}
|
|
13725
|
+
)
|
|
13656
13726
|
] });
|
|
13657
13727
|
}
|
|
13658
13728
|
var DataTable_default = DataTable;
|
|
13659
13729
|
|
|
13660
13730
|
// ../../components/ui/Form.tsx
|
|
13661
|
-
var
|
|
13731
|
+
var React52 = __toESM(require("react"), 1);
|
|
13662
13732
|
var import_react_hook_form = require("react-hook-form");
|
|
13663
|
-
var
|
|
13664
|
-
var FormConfigContext =
|
|
13733
|
+
var import_jsx_runtime60 = require("react/jsx-runtime");
|
|
13734
|
+
var FormConfigContext = React52.createContext({ size: "md" });
|
|
13665
13735
|
var FormWrapper = ({
|
|
13666
13736
|
children,
|
|
13667
13737
|
onSubmit,
|
|
@@ -13674,24 +13744,24 @@ var FormWrapper = ({
|
|
|
13674
13744
|
const methods = (0, import_react_hook_form.useForm)({
|
|
13675
13745
|
defaultValues: initialValues
|
|
13676
13746
|
});
|
|
13677
|
-
|
|
13747
|
+
React52.useEffect(() => {
|
|
13678
13748
|
if (initialValues) {
|
|
13679
13749
|
methods.reset(initialValues);
|
|
13680
13750
|
}
|
|
13681
13751
|
}, [JSON.stringify(initialValues)]);
|
|
13682
13752
|
const { validationSchema: _, ...formProps } = props;
|
|
13683
|
-
return /* @__PURE__ */ (0,
|
|
13753
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_react_hook_form.FormProvider, { ...methods, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FormConfigContext.Provider, { value: { size }, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("form", { onSubmit: methods.handleSubmit(onSubmit), className, ...formProps, children }) }) });
|
|
13684
13754
|
};
|
|
13685
13755
|
var Form = FormWrapper;
|
|
13686
|
-
var FormFieldContext =
|
|
13756
|
+
var FormFieldContext = React52.createContext({});
|
|
13687
13757
|
var FormField = ({
|
|
13688
13758
|
...props
|
|
13689
13759
|
}) => {
|
|
13690
|
-
return /* @__PURE__ */ (0,
|
|
13760
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_react_hook_form.Controller, { ...props }) });
|
|
13691
13761
|
};
|
|
13692
13762
|
var useFormField = () => {
|
|
13693
|
-
const fieldContext =
|
|
13694
|
-
const itemContext =
|
|
13763
|
+
const fieldContext = React52.useContext(FormFieldContext);
|
|
13764
|
+
const itemContext = React52.useContext(FormItemContext);
|
|
13695
13765
|
const { getFieldState, formState } = (0, import_react_hook_form.useFormContext)();
|
|
13696
13766
|
if (!fieldContext) {
|
|
13697
13767
|
try {
|
|
@@ -13712,27 +13782,27 @@ var useFormField = () => {
|
|
|
13712
13782
|
...fieldState
|
|
13713
13783
|
};
|
|
13714
13784
|
};
|
|
13715
|
-
var FormItemContext =
|
|
13716
|
-
var FormItem =
|
|
13717
|
-
const id =
|
|
13718
|
-
return /* @__PURE__ */ (0,
|
|
13785
|
+
var FormItemContext = React52.createContext({});
|
|
13786
|
+
var FormItem = React52.forwardRef(({ className, ...props }, ref) => {
|
|
13787
|
+
const id = React52.useId();
|
|
13788
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { ref, className: cn("space-y-2", className), ...props }) });
|
|
13719
13789
|
});
|
|
13720
13790
|
FormItem.displayName = "FormItem";
|
|
13721
|
-
var FormLabel =
|
|
13791
|
+
var FormLabel = React52.forwardRef(
|
|
13722
13792
|
({ className, children, required, ...props }, ref) => {
|
|
13723
13793
|
const { error, formItemId } = useFormField();
|
|
13724
|
-
const config =
|
|
13794
|
+
const config = React52.useContext(FormConfigContext);
|
|
13725
13795
|
const sizeClass = config.size === "sm" ? "text-xs" : config.size === "lg" ? "text-base" : "text-sm";
|
|
13726
|
-
return /* @__PURE__ */ (0,
|
|
13796
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(Label, { ref, className: cn(sizeClass, error && "text-destructive", className), htmlFor: formItemId, ...props, children: [
|
|
13727
13797
|
children,
|
|
13728
|
-
required && /* @__PURE__ */ (0,
|
|
13798
|
+
required && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "text-destructive ml-1", children: "*" })
|
|
13729
13799
|
] });
|
|
13730
13800
|
}
|
|
13731
13801
|
);
|
|
13732
13802
|
FormLabel.displayName = "FormLabel";
|
|
13733
|
-
var FormControl =
|
|
13803
|
+
var FormControl = React52.forwardRef(({ ...props }, ref) => {
|
|
13734
13804
|
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
|
|
13735
|
-
return /* @__PURE__ */ (0,
|
|
13805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
|
|
13736
13806
|
"div",
|
|
13737
13807
|
{
|
|
13738
13808
|
ref,
|
|
@@ -13744,37 +13814,37 @@ var FormControl = React49.forwardRef(({ ...props }, ref) => {
|
|
|
13744
13814
|
);
|
|
13745
13815
|
});
|
|
13746
13816
|
FormControl.displayName = "FormControl";
|
|
13747
|
-
var FormDescription =
|
|
13817
|
+
var FormDescription = React52.forwardRef(({ className, ...props }, ref) => {
|
|
13748
13818
|
const { formDescriptionId } = useFormField();
|
|
13749
|
-
return /* @__PURE__ */ (0,
|
|
13819
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { ref, id: formDescriptionId, className: cn("text-sm text-muted-foreground", className), ...props });
|
|
13750
13820
|
});
|
|
13751
13821
|
FormDescription.displayName = "FormDescription";
|
|
13752
|
-
var FormMessage =
|
|
13822
|
+
var FormMessage = React52.forwardRef(({ className, children, ...props }, ref) => {
|
|
13753
13823
|
const { error, formMessageId } = useFormField();
|
|
13754
13824
|
const body = error ? String(error?.message) : children;
|
|
13755
13825
|
if (!body) {
|
|
13756
13826
|
return null;
|
|
13757
13827
|
}
|
|
13758
|
-
return /* @__PURE__ */ (0,
|
|
13828
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { ref, id: formMessageId, className: cn("text-sm font-medium text-destructive", className), ...props, children: body });
|
|
13759
13829
|
});
|
|
13760
13830
|
FormMessage.displayName = "FormMessage";
|
|
13761
|
-
var FormInput =
|
|
13831
|
+
var FormInput = React52.forwardRef(({ name, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
|
|
13762
13832
|
FormField,
|
|
13763
13833
|
{
|
|
13764
13834
|
name,
|
|
13765
|
-
render: ({ field }) => /* @__PURE__ */ (0,
|
|
13766
|
-
/* @__PURE__ */ (0,
|
|
13767
|
-
/* @__PURE__ */ (0,
|
|
13835
|
+
render: ({ field }) => /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(FormItem, { children: [
|
|
13836
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FormControl, { children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Input_default, { size: props.size ?? size, ...field, ...props }) }),
|
|
13837
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FormMessage, {})
|
|
13768
13838
|
] })
|
|
13769
13839
|
}
|
|
13770
13840
|
) }));
|
|
13771
13841
|
FormInput.displayName = "FormInput";
|
|
13772
|
-
var FormCheckbox =
|
|
13842
|
+
var FormCheckbox = React52.forwardRef(({ name, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
|
|
13773
13843
|
FormField,
|
|
13774
13844
|
{
|
|
13775
13845
|
name,
|
|
13776
|
-
render: ({ field }) => /* @__PURE__ */ (0,
|
|
13777
|
-
/* @__PURE__ */ (0,
|
|
13846
|
+
render: ({ field }) => /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(FormItem, { children: [
|
|
13847
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FormControl, { children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
|
|
13778
13848
|
Checkbox,
|
|
13779
13849
|
{
|
|
13780
13850
|
ref,
|
|
@@ -13788,21 +13858,21 @@ var FormCheckbox = React49.forwardRef(({ name, ...props }, ref) => /* @__PURE__
|
|
|
13788
13858
|
...props
|
|
13789
13859
|
}
|
|
13790
13860
|
) }),
|
|
13791
|
-
/* @__PURE__ */ (0,
|
|
13861
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FormMessage, {})
|
|
13792
13862
|
] })
|
|
13793
13863
|
}
|
|
13794
13864
|
) }));
|
|
13795
13865
|
FormCheckbox.displayName = "FormCheckbox";
|
|
13796
|
-
var FormActions =
|
|
13866
|
+
var FormActions = React52.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { ref, className: cn("flex gap-2 justify-end", className), ...props }));
|
|
13797
13867
|
FormActions.displayName = "FormActions";
|
|
13798
|
-
var FormSubmitButton =
|
|
13799
|
-
({ children, loading: loading2, ...props }, ref) => /* @__PURE__ */ (0,
|
|
13868
|
+
var FormSubmitButton = React52.forwardRef(
|
|
13869
|
+
({ children, loading: loading2, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Button_default, { ref, type: "submit", size: props.size ?? size, disabled: loading2, ...props, children }) })
|
|
13800
13870
|
);
|
|
13801
13871
|
FormSubmitButton.displayName = "FormSubmitButton";
|
|
13802
13872
|
|
|
13803
13873
|
// ../../components/ui/NotificationModal.tsx
|
|
13804
13874
|
var import_lucide_react28 = require("lucide-react");
|
|
13805
|
-
var
|
|
13875
|
+
var import_jsx_runtime61 = require("react/jsx-runtime");
|
|
13806
13876
|
function NotificationModal({ isOpen, onClose, notification, titleText, openLinkText, closeText }) {
|
|
13807
13877
|
const t = useTranslations("Common");
|
|
13808
13878
|
if (!notification) return null;
|
|
@@ -13823,20 +13893,20 @@ function NotificationModal({ isOpen, onClose, notification, titleText, openLinkT
|
|
|
13823
13893
|
onClose();
|
|
13824
13894
|
}
|
|
13825
13895
|
};
|
|
13826
|
-
return /* @__PURE__ */ (0,
|
|
13827
|
-
/* @__PURE__ */ (0,
|
|
13828
|
-
/* @__PURE__ */ (0,
|
|
13829
|
-
/* @__PURE__ */ (0,
|
|
13896
|
+
return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Modal_default, { isOpen, onClose, title: titleText || t("notifications"), size: "md", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "space-y-4", children: [
|
|
13897
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "flex items-center gap-2 pb-2 border-b border-border", children: [
|
|
13898
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: cn("w-2 h-2 rounded-full", !notification.is_read ? "bg-primary" : "bg-border") }),
|
|
13899
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "text-xs text-muted-foreground", children: !notification.is_read ? t("newNotification") : t("readStatus") })
|
|
13830
13900
|
] }),
|
|
13831
|
-
notification.title && /* @__PURE__ */ (0,
|
|
13832
|
-
notification.body && /* @__PURE__ */ (0,
|
|
13833
|
-
/* @__PURE__ */ (0,
|
|
13834
|
-
/* @__PURE__ */ (0,
|
|
13835
|
-
hasLink && /* @__PURE__ */ (0,
|
|
13836
|
-
/* @__PURE__ */ (0,
|
|
13901
|
+
notification.title && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("h3", { className: "text-lg font-semibold text-foreground", children: notification.title }),
|
|
13902
|
+
notification.body && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "text-sm text-muted-foreground whitespace-pre-wrap leading-relaxed", children: notification.body }),
|
|
13903
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "text-xs text-muted-foreground border-t border-border pt-2", children: formatTime3(notification.created_at) }),
|
|
13904
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "flex gap-2 justify-end pt-2", children: [
|
|
13905
|
+
hasLink && /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(Button_default, { variant: "primary", size: "sm", onClick: handleLinkClick, className: "gap-2", children: [
|
|
13906
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(import_lucide_react28.ExternalLink, { className: "w-4 h-4" }),
|
|
13837
13907
|
openLinkText || t("openLink")
|
|
13838
13908
|
] }),
|
|
13839
|
-
/* @__PURE__ */ (0,
|
|
13909
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Button_default, { variant: "ghost", size: "sm", onClick: onClose, children: closeText || t("close") })
|
|
13840
13910
|
] })
|
|
13841
13911
|
] }) });
|
|
13842
13912
|
}
|
|
@@ -13846,9 +13916,9 @@ var NotificationModal_default = NotificationModal;
|
|
|
13846
13916
|
var import_link2 = __toESM(require("next/link"), 1);
|
|
13847
13917
|
var import_navigation = require("next/navigation");
|
|
13848
13918
|
var import_lucide_react29 = require("lucide-react");
|
|
13849
|
-
var
|
|
13919
|
+
var import_jsx_runtime62 = require("react/jsx-runtime");
|
|
13850
13920
|
function MessengerIcon(props) {
|
|
13851
|
-
return /* @__PURE__ */ (0,
|
|
13921
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("svg", { viewBox: "0 0 24 24", width: 24, height: 24, "aria-hidden": "true", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
13852
13922
|
"path",
|
|
13853
13923
|
{
|
|
13854
13924
|
d: "M12 2C6.477 2 2 6.145 2 11.235c0 2.93 1.35 5.542 3.464 7.25v3.515l3.344-1.836c.894.247 1.843.375 2.192.375 5.523 0 10-4.145 10-9.235S17.523 2 12 2zm.994 12.444l-2.563-2.73-5.004 2.73 5.507-5.84 2.626 2.729 4.942-2.729-5.508 5.84z",
|
|
@@ -13857,7 +13927,7 @@ function MessengerIcon(props) {
|
|
|
13857
13927
|
) });
|
|
13858
13928
|
}
|
|
13859
13929
|
function ZaloIcon(props) {
|
|
13860
|
-
return /* @__PURE__ */ (0,
|
|
13930
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("svg", { viewBox: "0 0 48 48", width: 20, height: 20, "aria-hidden": "true", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
13861
13931
|
"path",
|
|
13862
13932
|
{
|
|
13863
13933
|
fill: "white",
|
|
@@ -13866,7 +13936,7 @@ function ZaloIcon(props) {
|
|
|
13866
13936
|
) });
|
|
13867
13937
|
}
|
|
13868
13938
|
function InstagramIcon(props) {
|
|
13869
|
-
return /* @__PURE__ */ (0,
|
|
13939
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("svg", { viewBox: "0 0 24 24", width: 20, height: 20, "aria-hidden": "true", fill: "white", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("path", { d: "M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z" }) });
|
|
13870
13940
|
}
|
|
13871
13941
|
function FloatingContacts({ className }) {
|
|
13872
13942
|
const pathname = (0, import_navigation.usePathname)();
|
|
@@ -13901,8 +13971,8 @@ function FloatingContacts({ className }) {
|
|
|
13901
13971
|
external: true
|
|
13902
13972
|
}
|
|
13903
13973
|
];
|
|
13904
|
-
return /* @__PURE__ */ (0,
|
|
13905
|
-
/* @__PURE__ */ (0,
|
|
13974
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: cn("fixed bottom-6 right-4 z-100000", "flex flex-col items-end gap-3", className), "aria-label": "Quick contacts", children: [
|
|
13975
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
13906
13976
|
import_link2.default,
|
|
13907
13977
|
{
|
|
13908
13978
|
href: `tel:${hotline.replace(/\D/g, "")}`,
|
|
@@ -13913,10 +13983,10 @@ function FloatingContacts({ className }) {
|
|
|
13913
13983
|
"hover:scale-105 active:scale-95 transition-transform",
|
|
13914
13984
|
"bg-[#22c55e]"
|
|
13915
13985
|
),
|
|
13916
|
-
children: /* @__PURE__ */ (0,
|
|
13986
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react29.Phone, { className: "w-6 h-6" })
|
|
13917
13987
|
}
|
|
13918
13988
|
),
|
|
13919
|
-
moreItems.map(({ key, href, label, bg, Icon, external }) => /* @__PURE__ */ (0,
|
|
13989
|
+
moreItems.map(({ key, href, label, bg, Icon, external }) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
13920
13990
|
import_link2.default,
|
|
13921
13991
|
{
|
|
13922
13992
|
href,
|
|
@@ -13928,7 +13998,7 @@ function FloatingContacts({ className }) {
|
|
|
13928
13998
|
"hover:scale-105 active:scale-95 transition-transform",
|
|
13929
13999
|
bg
|
|
13930
14000
|
),
|
|
13931
|
-
children: /* @__PURE__ */ (0,
|
|
14001
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Icon, { className: "w-6 h-6" })
|
|
13932
14002
|
},
|
|
13933
14003
|
key
|
|
13934
14004
|
))
|
|
@@ -13937,7 +14007,7 @@ function FloatingContacts({ className }) {
|
|
|
13937
14007
|
|
|
13938
14008
|
// ../../components/ui/AccessDenied.tsx
|
|
13939
14009
|
var import_lucide_react30 = require("lucide-react");
|
|
13940
|
-
var
|
|
14010
|
+
var import_jsx_runtime63 = require("react/jsx-runtime");
|
|
13941
14011
|
var VARIANT_STYLES = {
|
|
13942
14012
|
destructive: { bg: "bg-destructive/5", border: "border-destructive/20", text: "text-destructive" },
|
|
13943
14013
|
warning: { bg: "bg-warning/5", border: "border-warning/20", text: "text-warning" },
|
|
@@ -13958,32 +14028,32 @@ function AccessDenied({
|
|
|
13958
14028
|
}) {
|
|
13959
14029
|
const styles = VARIANT_STYLES[variant];
|
|
13960
14030
|
const UsedIcon = Icon || DEFAULT_ICONS[variant];
|
|
13961
|
-
return /* @__PURE__ */ (0,
|
|
13962
|
-
/* @__PURE__ */ (0,
|
|
13963
|
-
/* @__PURE__ */ (0,
|
|
13964
|
-
/* @__PURE__ */ (0,
|
|
13965
|
-
/* @__PURE__ */ (0,
|
|
14031
|
+
return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Card_default, { className: cn("p-8 text-center shadow-sm", styles.bg, styles.border, className), children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
|
|
14032
|
+
/* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: cn("p-3 rounded-lg", styles.bg.replace("/5", "/10")), children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(UsedIcon, { className: cn("w-8 h-8", styles.text) }) }),
|
|
14033
|
+
/* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { children: [
|
|
14034
|
+
/* @__PURE__ */ (0, import_jsx_runtime63.jsx)("h3", { className: cn("font-semibold mb-2", styles.text), children: title }),
|
|
14035
|
+
/* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: cn(styles.text.replace("text-", "text-") + "/80", "text-sm"), children: description })
|
|
13966
14036
|
] }),
|
|
13967
|
-
children && /* @__PURE__ */ (0,
|
|
14037
|
+
children && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "mt-2 flex flex-wrap gap-2 justify-center", children })
|
|
13968
14038
|
] }) });
|
|
13969
14039
|
}
|
|
13970
14040
|
|
|
13971
14041
|
// ../../components/ui/ThemeToggleHeadless.tsx
|
|
13972
14042
|
var import_lucide_react31 = require("lucide-react");
|
|
13973
|
-
var
|
|
14043
|
+
var import_react36 = require("react");
|
|
13974
14044
|
var import_react_dom7 = require("react-dom");
|
|
13975
|
-
var
|
|
14045
|
+
var import_jsx_runtime64 = require("react/jsx-runtime");
|
|
13976
14046
|
function ThemeToggleHeadless({
|
|
13977
14047
|
theme,
|
|
13978
14048
|
onChange,
|
|
13979
14049
|
labels,
|
|
13980
14050
|
className
|
|
13981
14051
|
}) {
|
|
13982
|
-
const [isOpen, setIsOpen] = (0,
|
|
13983
|
-
const [mounted, setMounted] = (0,
|
|
13984
|
-
const triggerRef = (0,
|
|
13985
|
-
const [dropdownPosition, setDropdownPosition] = (0,
|
|
13986
|
-
(0,
|
|
14052
|
+
const [isOpen, setIsOpen] = (0, import_react36.useState)(false);
|
|
14053
|
+
const [mounted, setMounted] = (0, import_react36.useState)(false);
|
|
14054
|
+
const triggerRef = (0, import_react36.useRef)(null);
|
|
14055
|
+
const [dropdownPosition, setDropdownPosition] = (0, import_react36.useState)(null);
|
|
14056
|
+
(0, import_react36.useEffect)(() => setMounted(true), []);
|
|
13987
14057
|
const themes = [
|
|
13988
14058
|
{ value: "light", label: labels?.light ?? "Light", icon: import_lucide_react31.Sun },
|
|
13989
14059
|
{ value: "dark", label: labels?.dark ?? "Dark", icon: import_lucide_react31.Moon },
|
|
@@ -14001,8 +14071,8 @@ function ThemeToggleHeadless({
|
|
|
14001
14071
|
const top = rect.bottom + scrollTop + 8;
|
|
14002
14072
|
return { top, left, width };
|
|
14003
14073
|
};
|
|
14004
|
-
return /* @__PURE__ */ (0,
|
|
14005
|
-
/* @__PURE__ */ (0,
|
|
14074
|
+
return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: cn("relative", className), children: [
|
|
14075
|
+
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
|
|
14006
14076
|
Button_default,
|
|
14007
14077
|
{
|
|
14008
14078
|
variant: "ghost",
|
|
@@ -14020,25 +14090,25 @@ function ThemeToggleHeadless({
|
|
|
14020
14090
|
"aria-haspopup": "menu",
|
|
14021
14091
|
"aria-expanded": isOpen,
|
|
14022
14092
|
"aria-label": labels?.heading ?? "Theme",
|
|
14023
|
-
children: /* @__PURE__ */ (0,
|
|
14093
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(CurrentIcon, { className: "h-5 w-5" })
|
|
14024
14094
|
}
|
|
14025
14095
|
),
|
|
14026
|
-
isOpen && /* @__PURE__ */ (0,
|
|
14027
|
-
typeof window !== "undefined" && (0, import_react_dom7.createPortal)(/* @__PURE__ */ (0,
|
|
14096
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(import_jsx_runtime64.Fragment, { children: [
|
|
14097
|
+
typeof window !== "undefined" && (0, import_react_dom7.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: "fixed inset-0 z-9998", onClick: () => setIsOpen(false) }), document.body),
|
|
14028
14098
|
typeof window !== "undefined" && dropdownPosition && (0, import_react_dom7.createPortal)(
|
|
14029
|
-
/* @__PURE__ */ (0,
|
|
14099
|
+
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
|
|
14030
14100
|
"div",
|
|
14031
14101
|
{
|
|
14032
14102
|
className: "z-9999 bg-card border border-border rounded-lg shadow-lg overflow-hidden",
|
|
14033
14103
|
style: { position: "absolute", top: dropdownPosition.top, left: dropdownPosition.left, width: dropdownPosition.width },
|
|
14034
14104
|
onMouseDown: (e) => e.stopPropagation(),
|
|
14035
14105
|
role: "menu",
|
|
14036
|
-
children: /* @__PURE__ */ (0,
|
|
14037
|
-
/* @__PURE__ */ (0,
|
|
14106
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "p-2", children: [
|
|
14107
|
+
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: "px-3 py-2 text-sm font-medium text-muted-foreground border-b border-border mb-2", children: labels?.heading ?? "Theme" }),
|
|
14038
14108
|
themes.map((opt) => {
|
|
14039
14109
|
const Icon = opt.icon;
|
|
14040
14110
|
const active = theme === opt.value;
|
|
14041
|
-
return /* @__PURE__ */ (0,
|
|
14111
|
+
return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
|
|
14042
14112
|
Button_default,
|
|
14043
14113
|
{
|
|
14044
14114
|
variant: "ghost",
|
|
@@ -14054,9 +14124,9 @@ function ThemeToggleHeadless({
|
|
|
14054
14124
|
role: "menuitemradio",
|
|
14055
14125
|
"aria-checked": active,
|
|
14056
14126
|
children: [
|
|
14057
|
-
/* @__PURE__ */ (0,
|
|
14058
|
-
/* @__PURE__ */ (0,
|
|
14059
|
-
active && /* @__PURE__ */ (0,
|
|
14127
|
+
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Icon, { className: "h-4 w-4" }),
|
|
14128
|
+
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "flex-1 text-left", children: opt.label }),
|
|
14129
|
+
active && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: "w-2 h-2 rounded-full bg-primary" })
|
|
14060
14130
|
]
|
|
14061
14131
|
},
|
|
14062
14132
|
opt.value
|
|
@@ -14072,10 +14142,10 @@ function ThemeToggleHeadless({
|
|
|
14072
14142
|
}
|
|
14073
14143
|
|
|
14074
14144
|
// ../../components/ui/LanguageSwitcherHeadless.tsx
|
|
14075
|
-
var
|
|
14145
|
+
var import_react37 = require("react");
|
|
14076
14146
|
var import_react_dom8 = require("react-dom");
|
|
14077
14147
|
var import_lucide_react32 = require("lucide-react");
|
|
14078
|
-
var
|
|
14148
|
+
var import_jsx_runtime65 = require("react/jsx-runtime");
|
|
14079
14149
|
function LanguageSwitcherHeadless({
|
|
14080
14150
|
locales,
|
|
14081
14151
|
currentLocale,
|
|
@@ -14083,9 +14153,9 @@ function LanguageSwitcherHeadless({
|
|
|
14083
14153
|
labels,
|
|
14084
14154
|
className
|
|
14085
14155
|
}) {
|
|
14086
|
-
const [isOpen, setIsOpen] = (0,
|
|
14087
|
-
const [dropdownPosition, setDropdownPosition] = (0,
|
|
14088
|
-
const triggerButtonRef = (0,
|
|
14156
|
+
const [isOpen, setIsOpen] = (0, import_react37.useState)(false);
|
|
14157
|
+
const [dropdownPosition, setDropdownPosition] = (0, import_react37.useState)(null);
|
|
14158
|
+
const triggerButtonRef = (0, import_react37.useRef)(null);
|
|
14089
14159
|
const currentLanguage = locales.find((l) => l.code === currentLocale) || locales[0];
|
|
14090
14160
|
const calculatePosition = () => {
|
|
14091
14161
|
const rect = triggerButtonRef.current?.getBoundingClientRect();
|
|
@@ -14097,8 +14167,8 @@ function LanguageSwitcherHeadless({
|
|
|
14097
14167
|
const top = rect.bottom + scrollTop + 8;
|
|
14098
14168
|
return { top, left, width };
|
|
14099
14169
|
};
|
|
14100
|
-
return /* @__PURE__ */ (0,
|
|
14101
|
-
/* @__PURE__ */ (0,
|
|
14170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: cn("relative", className), children: [
|
|
14171
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
14102
14172
|
Button_default,
|
|
14103
14173
|
{
|
|
14104
14174
|
variant: "ghost",
|
|
@@ -14117,22 +14187,22 @@ function LanguageSwitcherHeadless({
|
|
|
14117
14187
|
"aria-expanded": isOpen,
|
|
14118
14188
|
"aria-label": labels?.heading ?? "Language",
|
|
14119
14189
|
title: labels?.heading ?? "Language",
|
|
14120
|
-
children: /* @__PURE__ */ (0,
|
|
14190
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_lucide_react32.Globe, { className: "h-5 w-5" })
|
|
14121
14191
|
}
|
|
14122
14192
|
),
|
|
14123
|
-
isOpen && /* @__PURE__ */ (0,
|
|
14124
|
-
typeof window !== "undefined" && (0, import_react_dom8.createPortal)(/* @__PURE__ */ (0,
|
|
14193
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(import_jsx_runtime65.Fragment, { children: [
|
|
14194
|
+
typeof window !== "undefined" && (0, import_react_dom8.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: "fixed inset-0 z-9998", onClick: () => setIsOpen(false) }), document.body),
|
|
14125
14195
|
typeof window !== "undefined" && dropdownPosition && (0, import_react_dom8.createPortal)(
|
|
14126
|
-
/* @__PURE__ */ (0,
|
|
14196
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
14127
14197
|
"div",
|
|
14128
14198
|
{
|
|
14129
14199
|
className: "z-9999 bg-card border border-border rounded-lg shadow-lg overflow-hidden",
|
|
14130
14200
|
style: { position: "absolute", top: dropdownPosition.top, left: dropdownPosition.left, width: dropdownPosition.width },
|
|
14131
14201
|
onMouseDown: (e) => e.stopPropagation(),
|
|
14132
14202
|
role: "menu",
|
|
14133
|
-
children: /* @__PURE__ */ (0,
|
|
14134
|
-
/* @__PURE__ */ (0,
|
|
14135
|
-
locales.map((language) => /* @__PURE__ */ (0,
|
|
14203
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: "p-2", children: [
|
|
14204
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: "px-3 py-2 text-sm font-medium text-muted-foreground border-b border-border mb-2", children: labels?.heading ?? "Language" }),
|
|
14205
|
+
locales.map((language) => /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
|
|
14136
14206
|
Button_default,
|
|
14137
14207
|
{
|
|
14138
14208
|
variant: "ghost",
|
|
@@ -14145,9 +14215,9 @@ function LanguageSwitcherHeadless({
|
|
|
14145
14215
|
role: "menuitemradio",
|
|
14146
14216
|
"aria-checked": currentLocale === language.code,
|
|
14147
14217
|
children: [
|
|
14148
|
-
language.flag && /* @__PURE__ */ (0,
|
|
14149
|
-
/* @__PURE__ */ (0,
|
|
14150
|
-
currentLocale === language.code && /* @__PURE__ */ (0,
|
|
14218
|
+
language.flag && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "text-lg", children: language.flag }),
|
|
14219
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "flex-1 text-left", children: language.name }),
|
|
14220
|
+
currentLocale === language.code && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: "w-2 h-2 rounded-full bg-primary" })
|
|
14151
14221
|
]
|
|
14152
14222
|
},
|
|
14153
14223
|
language.code
|
|
@@ -14577,7 +14647,7 @@ var VARIANT_STYLES_ALERT = {
|
|
|
14577
14647
|
};
|
|
14578
14648
|
|
|
14579
14649
|
// src/contexts/TranslationContext.tsx
|
|
14580
|
-
var
|
|
14650
|
+
var React54 = __toESM(require("react"), 1);
|
|
14581
14651
|
|
|
14582
14652
|
// locales/en.json
|
|
14583
14653
|
var en_default = {
|
|
@@ -14880,16 +14950,16 @@ var ja_default = {
|
|
|
14880
14950
|
};
|
|
14881
14951
|
|
|
14882
14952
|
// src/contexts/TranslationContext.tsx
|
|
14883
|
-
var
|
|
14953
|
+
var import_jsx_runtime66 = require("react/jsx-runtime");
|
|
14884
14954
|
var defaultTranslations2 = {
|
|
14885
14955
|
en: en_default,
|
|
14886
14956
|
vi: vi_default,
|
|
14887
14957
|
ko: ko_default,
|
|
14888
14958
|
ja: ja_default
|
|
14889
14959
|
};
|
|
14890
|
-
var TranslationContext2 =
|
|
14960
|
+
var TranslationContext2 = React54.createContext(null);
|
|
14891
14961
|
var TranslationProvider = ({ children, locale = "en", translations }) => {
|
|
14892
|
-
const t =
|
|
14962
|
+
const t = React54.useCallback(
|
|
14893
14963
|
(namespace) => {
|
|
14894
14964
|
return (key) => {
|
|
14895
14965
|
const mergedTranslations = {
|
|
@@ -14914,10 +14984,10 @@ var TranslationProvider = ({ children, locale = "en", translations }) => {
|
|
|
14914
14984
|
},
|
|
14915
14985
|
[locale, translations]
|
|
14916
14986
|
);
|
|
14917
|
-
return /* @__PURE__ */ (0,
|
|
14987
|
+
return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(TranslationContext2.Provider, { value: { locale, t }, children });
|
|
14918
14988
|
};
|
|
14919
14989
|
var useUnderverseTranslations = (namespace) => {
|
|
14920
|
-
const context =
|
|
14990
|
+
const context = React54.useContext(TranslationContext2);
|
|
14921
14991
|
if (!context) {
|
|
14922
14992
|
return (key) => {
|
|
14923
14993
|
const parts = namespace.split(".");
|
|
@@ -14939,13 +15009,13 @@ var useUnderverseTranslations = (namespace) => {
|
|
|
14939
15009
|
return context.t(namespace);
|
|
14940
15010
|
};
|
|
14941
15011
|
var useUnderverseLocale = () => {
|
|
14942
|
-
const context =
|
|
15012
|
+
const context = React54.useContext(TranslationContext2);
|
|
14943
15013
|
return context?.locale || "en";
|
|
14944
15014
|
};
|
|
14945
15015
|
|
|
14946
15016
|
// src/hooks/useSmartTranslations.tsx
|
|
14947
|
-
var
|
|
14948
|
-
var
|
|
15017
|
+
var React55 = __toESM(require("react"), 1);
|
|
15018
|
+
var import_jsx_runtime67 = require("react/jsx-runtime");
|
|
14949
15019
|
var nextIntlHooks = null;
|
|
14950
15020
|
try {
|
|
14951
15021
|
const nextIntl = require("next-intl");
|
|
@@ -14956,12 +15026,12 @@ try {
|
|
|
14956
15026
|
} catch {
|
|
14957
15027
|
nextIntlHooks = null;
|
|
14958
15028
|
}
|
|
14959
|
-
var ForceInternalContext =
|
|
15029
|
+
var ForceInternalContext = React55.createContext(false);
|
|
14960
15030
|
var ForceInternalTranslationsProvider = ({ children }) => {
|
|
14961
|
-
return /* @__PURE__ */ (0,
|
|
15031
|
+
return /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ForceInternalContext.Provider, { value: true, children });
|
|
14962
15032
|
};
|
|
14963
15033
|
function useSmartTranslations(namespace) {
|
|
14964
|
-
const forceInternal =
|
|
15034
|
+
const forceInternal = React55.useContext(ForceInternalContext);
|
|
14965
15035
|
const internalT = useUnderverseTranslations(namespace);
|
|
14966
15036
|
if (forceInternal || !nextIntlHooks?.useTranslations) {
|
|
14967
15037
|
return internalT;
|
|
@@ -14974,7 +15044,7 @@ function useSmartTranslations(namespace) {
|
|
|
14974
15044
|
}
|
|
14975
15045
|
}
|
|
14976
15046
|
function useSmartLocale() {
|
|
14977
|
-
const forceInternal =
|
|
15047
|
+
const forceInternal = React55.useContext(ForceInternalContext);
|
|
14978
15048
|
const internalLocale = useUnderverseLocale();
|
|
14979
15049
|
if (forceInternal || !nextIntlHooks?.useLocale) {
|
|
14980
15050
|
return internalLocale;
|