@underverse-ui/underverse 0.2.72 → 0.2.74
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 +539 -466
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -14
- package/dist/index.d.ts +16 -14
- package/dist/index.js +529 -456
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2129,6 +2129,7 @@ function SmartImage({
|
|
|
2129
2129
|
src,
|
|
2130
2130
|
alt,
|
|
2131
2131
|
className,
|
|
2132
|
+
imageClassName,
|
|
2132
2133
|
ratioClass,
|
|
2133
2134
|
roundedClass = "rounded-2xl md:rounded-3xl",
|
|
2134
2135
|
fill = true,
|
|
@@ -2197,7 +2198,8 @@ function SmartImage({
|
|
|
2197
2198
|
onError: handleError,
|
|
2198
2199
|
priority,
|
|
2199
2200
|
quality,
|
|
2200
|
-
style: { objectFit: fit, objectPosition }
|
|
2201
|
+
style: { objectFit: fit, objectPosition },
|
|
2202
|
+
className: cn("transition-all duration-300", imageClassName)
|
|
2201
2203
|
}
|
|
2202
2204
|
) });
|
|
2203
2205
|
}
|
|
@@ -2221,7 +2223,8 @@ function SmartImage({
|
|
|
2221
2223
|
onError: handleError,
|
|
2222
2224
|
priority,
|
|
2223
2225
|
quality,
|
|
2224
|
-
style: { objectFit: fit, objectPosition, width: "100%", height: "100%" }
|
|
2226
|
+
style: { objectFit: fit, objectPosition, width: "100%", height: "100%" },
|
|
2227
|
+
className: cn("transition-all duration-300", imageClassName)
|
|
2225
2228
|
}
|
|
2226
2229
|
)
|
|
2227
2230
|
}
|
|
@@ -13048,10 +13051,183 @@ TableCell.displayName = "TableCell";
|
|
|
13048
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 }));
|
|
13049
13052
|
TableCaption.displayName = "TableCaption";
|
|
13050
13053
|
|
|
13051
|
-
// ../../components/ui/DataTable.tsx
|
|
13054
|
+
// ../../components/ui/DataTable/DataTable.tsx
|
|
13052
13055
|
var import_lucide_react27 = require("lucide-react");
|
|
13053
|
-
var
|
|
13056
|
+
var import_react35 = __toESM(require("react"), 1);
|
|
13057
|
+
|
|
13058
|
+
// ../../components/ui/DataTable/components/Pagination.tsx
|
|
13054
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);
|
|
13055
13231
|
function useDebounced(value, delay = 300) {
|
|
13056
13232
|
const [debounced, setDebounced] = import_react32.default.useState(value);
|
|
13057
13233
|
import_react32.default.useEffect(() => {
|
|
@@ -13060,40 +13236,12 @@ function useDebounced(value, delay = 300) {
|
|
|
13060
13236
|
}, [value, delay]);
|
|
13061
13237
|
return debounced;
|
|
13062
13238
|
}
|
|
13063
|
-
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
page = 1,
|
|
13070
|
-
pageSize = 20,
|
|
13071
|
-
pageSizeOptions,
|
|
13072
|
-
onQueryChange,
|
|
13073
|
-
caption,
|
|
13074
|
-
toolbar,
|
|
13075
|
-
enableColumnVisibilityToggle = true,
|
|
13076
|
-
enableDensityToggle = true,
|
|
13077
|
-
enableHeaderAlignToggle = false,
|
|
13078
|
-
striped = true,
|
|
13079
|
-
// Mặc định bật màu nền sẽn kẽ cho các dòng
|
|
13080
|
-
columnDividers = false,
|
|
13081
|
-
className,
|
|
13082
|
-
storageKey,
|
|
13083
|
-
stickyHeader = true,
|
|
13084
|
-
maxHeight = 500,
|
|
13085
|
-
labels
|
|
13086
|
-
}) {
|
|
13087
|
-
const t = useTranslations("Common");
|
|
13088
|
-
const [headerAlign, setHeaderAlign] = import_react32.default.useState("left");
|
|
13089
|
-
const [visibleCols, setVisibleCols] = import_react32.default.useState(() => columns.filter((c) => c.visible !== false).map((c) => c.key));
|
|
13090
|
-
const [filters, setFilters] = import_react32.default.useState({});
|
|
13091
|
-
const [sort, setSort] = import_react32.default.useState(null);
|
|
13092
|
-
const [density, setDensity] = import_react32.default.useState("normal");
|
|
13093
|
-
const [curPage, setCurPage] = import_react32.default.useState(page);
|
|
13094
|
-
const hasMounted = import_react32.default.useRef(false);
|
|
13095
|
-
const loadedFromStorage = import_react32.default.useRef(false);
|
|
13096
|
-
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(() => {
|
|
13097
13245
|
if (typeof window === "undefined" || !storageKey) return pageSize;
|
|
13098
13246
|
try {
|
|
13099
13247
|
const saved = localStorage.getItem(`datatable_${storageKey}_pageSize`);
|
|
@@ -13108,7 +13256,11 @@ function DataTable({
|
|
|
13108
13256
|
}
|
|
13109
13257
|
return pageSize;
|
|
13110
13258
|
});
|
|
13111
|
-
|
|
13259
|
+
const hasMounted = import_react33.default.useRef(false);
|
|
13260
|
+
import_react33.default.useEffect(() => {
|
|
13261
|
+
hasMounted.current = true;
|
|
13262
|
+
}, []);
|
|
13263
|
+
import_react33.default.useEffect(() => {
|
|
13112
13264
|
if (typeof window === "undefined" || !storageKey) return;
|
|
13113
13265
|
if (!hasMounted.current) return;
|
|
13114
13266
|
try {
|
|
@@ -13116,49 +13268,33 @@ function DataTable({
|
|
|
13116
13268
|
} catch {
|
|
13117
13269
|
}
|
|
13118
13270
|
}, [curPageSize, storageKey]);
|
|
13119
|
-
|
|
13120
|
-
|
|
13121
|
-
setVisibleCols((prev) => {
|
|
13122
|
-
const uniqueKeys = /* @__PURE__ */ new Set([...prev, ...newColKeys]);
|
|
13123
|
-
return [...uniqueKeys].filter((k) => columns.some((c) => c.key === k));
|
|
13124
|
-
});
|
|
13125
|
-
}, [columns]);
|
|
13126
|
-
const debouncedFilters = useDebounced(filters, 350);
|
|
13127
|
-
import_react32.default.useEffect(() => {
|
|
13128
|
-
setCurPage(page);
|
|
13129
|
-
}, [page]);
|
|
13130
|
-
import_react32.default.useEffect(() => {
|
|
13131
|
-
if (storageKey && loadedFromStorage.current) {
|
|
13132
|
-
return;
|
|
13133
|
-
}
|
|
13271
|
+
import_react33.default.useEffect(() => {
|
|
13272
|
+
if (storageKey && loadedFromStorage.current) return;
|
|
13134
13273
|
setCurPageSize(pageSize);
|
|
13135
13274
|
}, [pageSize, storageKey]);
|
|
13136
|
-
|
|
13137
|
-
|
|
13138
|
-
|
|
13139
|
-
|
|
13140
|
-
|
|
13141
|
-
|
|
13142
|
-
|
|
13143
|
-
|
|
13144
|
-
|
|
13145
|
-
const
|
|
13146
|
-
const
|
|
13147
|
-
|
|
13148
|
-
|
|
13149
|
-
|
|
13150
|
-
|
|
13151
|
-
|
|
13152
|
-
|
|
13153
|
-
}, [visibleColumns]);
|
|
13154
|
-
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(() => {
|
|
13155
13292
|
const positions = {};
|
|
13156
13293
|
let leftOffset = 0;
|
|
13157
13294
|
for (const col of visibleColumns) {
|
|
13158
13295
|
if (col.fixed === "left") {
|
|
13159
13296
|
positions[col.key] = { left: leftOffset };
|
|
13160
|
-
|
|
13161
|
-
leftOffset += colWidth;
|
|
13297
|
+
leftOffset += getColumnWidth(col);
|
|
13162
13298
|
}
|
|
13163
13299
|
}
|
|
13164
13300
|
let rightOffset = 0;
|
|
@@ -13166,30 +13302,105 @@ function DataTable({
|
|
|
13166
13302
|
const col = visibleColumns[i];
|
|
13167
13303
|
if (col.fixed === "right") {
|
|
13168
13304
|
positions[col.key] = { right: rightOffset };
|
|
13169
|
-
|
|
13170
|
-
rightOffset += colWidth;
|
|
13305
|
+
rightOffset += getColumnWidth(col);
|
|
13171
13306
|
}
|
|
13172
13307
|
}
|
|
13173
13308
|
return positions;
|
|
13174
13309
|
}, [visibleColumns]);
|
|
13175
|
-
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) => {
|
|
13176
13322
|
if (!col.fixed) return "";
|
|
13177
13323
|
return cn(
|
|
13178
13324
|
"sticky",
|
|
13179
13325
|
col.fixed === "left" && "left-0 shadow-[2px_0_5px_-2px_rgba(0,0,0,0.15)]",
|
|
13180
13326
|
col.fixed === "right" && "right-0 shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.15)]",
|
|
13181
|
-
|
|
13182
|
-
isHeader ? "z-50 bg-muted!" : "z-10 bg-card!"
|
|
13327
|
+
"z-50 bg-muted!"
|
|
13183
13328
|
);
|
|
13184
|
-
};
|
|
13185
|
-
const
|
|
13186
|
-
if (!col.fixed) return
|
|
13187
|
-
|
|
13188
|
-
|
|
13189
|
-
|
|
13190
|
-
|
|
13191
|
-
|
|
13192
|
-
|
|
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);
|
|
13193
13404
|
const getRowKey = (row, idx) => {
|
|
13194
13405
|
if (!rowKey) return String(idx);
|
|
13195
13406
|
if (typeof rowKey === "function") return String(rowKey(row));
|
|
@@ -13198,11 +13409,9 @@ function DataTable({
|
|
|
13198
13409
|
const renderFilterControl = (col) => {
|
|
13199
13410
|
if (!col.filter) return null;
|
|
13200
13411
|
const k = col.key;
|
|
13201
|
-
const commonProps = {
|
|
13202
|
-
className: "h-8 w-full text-sm"
|
|
13203
|
-
};
|
|
13412
|
+
const commonProps = { className: "h-8 w-full text-sm" };
|
|
13204
13413
|
if (col.filter.type === "text") {
|
|
13205
|
-
return /* @__PURE__ */ (0,
|
|
13414
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13206
13415
|
Input_default,
|
|
13207
13416
|
{
|
|
13208
13417
|
...commonProps,
|
|
@@ -13217,7 +13426,7 @@ function DataTable({
|
|
|
13217
13426
|
}
|
|
13218
13427
|
if (col.filter.type === "select") {
|
|
13219
13428
|
const options = col.filter.options || [];
|
|
13220
|
-
return /* @__PURE__ */ (0,
|
|
13429
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13221
13430
|
Combobox,
|
|
13222
13431
|
{
|
|
13223
13432
|
options: ["", ...options],
|
|
@@ -13233,7 +13442,7 @@ function DataTable({
|
|
|
13233
13442
|
);
|
|
13234
13443
|
}
|
|
13235
13444
|
if (col.filter.type === "date") {
|
|
13236
|
-
return /* @__PURE__ */ (0,
|
|
13445
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13237
13446
|
DatePicker,
|
|
13238
13447
|
{
|
|
13239
13448
|
placeholder: col.filter.placeholder || `Select ${String(col.title)}`,
|
|
@@ -13247,122 +13456,105 @@ function DataTable({
|
|
|
13247
13456
|
}
|
|
13248
13457
|
return null;
|
|
13249
13458
|
};
|
|
13250
|
-
const renderHeader = /* @__PURE__ */ (0,
|
|
13459
|
+
const renderHeader = /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(TableRow, { children: visibleColumns.map((col, colIdx) => {
|
|
13251
13460
|
const prevCol = colIdx > 0 ? visibleColumns[colIdx - 1] : null;
|
|
13252
13461
|
const isAfterFixedLeft = prevCol?.fixed === "left";
|
|
13253
13462
|
const showBorderLeft = columnDividers && colIdx > 0 && !isAfterFixedLeft && !col.fixed;
|
|
13254
|
-
return /* @__PURE__ */ (0,
|
|
13463
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13255
13464
|
TableHead,
|
|
13256
13465
|
{
|
|
13257
13466
|
style: { width: col.width, ...getStickyColumnStyle(col) },
|
|
13258
13467
|
className: cn(
|
|
13259
|
-
// Use column-specific align if defined, otherwise use global headerAlign
|
|
13260
13468
|
(col.align === "right" || !col.align && headerAlign === "right") && "text-right",
|
|
13261
13469
|
(col.align === "center" || !col.align && headerAlign === "center") && "text-center",
|
|
13262
13470
|
showBorderLeft && "border-l border-border/60",
|
|
13263
|
-
|
|
13471
|
+
getStickyHeaderClass(col)
|
|
13264
13472
|
),
|
|
13265
13473
|
children: (() => {
|
|
13266
13474
|
const isRightAlign = col.align === "right" || !col.align && headerAlign === "right";
|
|
13267
13475
|
const isCenterAlign = col.align === "center" || !col.align && headerAlign === "center";
|
|
13268
|
-
const titleContent = /* @__PURE__ */ (0,
|
|
13269
|
-
"
|
|
13270
|
-
|
|
13271
|
-
|
|
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
|
-
opacity: sort?.key === col.key && sort.order === "desc" ? 1 : 0.4
|
|
13316
|
-
}
|
|
13317
|
-
)
|
|
13318
|
-
] })
|
|
13319
|
-
}
|
|
13320
|
-
)
|
|
13321
|
-
]
|
|
13322
|
-
}
|
|
13323
|
-
);
|
|
13324
|
-
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)(
|
|
13325
13523
|
Popover,
|
|
13326
13524
|
{
|
|
13327
|
-
placement:
|
|
13328
|
-
trigger: /* @__PURE__ */ (0,
|
|
13525
|
+
placement: "bottom-start",
|
|
13526
|
+
trigger: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13329
13527
|
"button",
|
|
13330
13528
|
{
|
|
13331
13529
|
className: cn(
|
|
13332
|
-
"p-1.5 rounded-lg
|
|
13333
|
-
"
|
|
13334
|
-
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"
|
|
13335
13532
|
),
|
|
13336
13533
|
"aria-label": "Filter",
|
|
13337
|
-
title:
|
|
13338
|
-
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" })
|
|
13339
13536
|
}
|
|
13340
13537
|
),
|
|
13341
|
-
children: /* @__PURE__ */ (0,
|
|
13342
|
-
/* @__PURE__ */ (0,
|
|
13343
|
-
"
|
|
13344
|
-
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
|
+
)
|
|
13345
13552
|
] }),
|
|
13346
|
-
renderFilterControl(col)
|
|
13347
|
-
filters[col.key] && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13348
|
-
"button",
|
|
13349
|
-
{
|
|
13350
|
-
onClick: () => {
|
|
13351
|
-
setCurPage(1);
|
|
13352
|
-
setFilters((f) => {
|
|
13353
|
-
const newFilters = { ...f };
|
|
13354
|
-
delete newFilters[col.key];
|
|
13355
|
-
return newFilters;
|
|
13356
|
-
});
|
|
13357
|
-
},
|
|
13358
|
-
className: "text-xs text-destructive hover:underline",
|
|
13359
|
-
children: t("clearFilter")
|
|
13360
|
-
}
|
|
13361
|
-
)
|
|
13553
|
+
renderFilterControl(col)
|
|
13362
13554
|
] })
|
|
13363
13555
|
}
|
|
13364
|
-
);
|
|
13365
|
-
return /* @__PURE__ */ (0,
|
|
13556
|
+
) : null;
|
|
13557
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13366
13558
|
"div",
|
|
13367
13559
|
{
|
|
13368
13560
|
className: cn(
|
|
@@ -13371,10 +13563,10 @@ function DataTable({
|
|
|
13371
13563
|
isCenterAlign && "justify-center",
|
|
13372
13564
|
!isRightAlign && !isCenterAlign && "justify-start"
|
|
13373
13565
|
),
|
|
13374
|
-
children: isRightAlign ? /* @__PURE__ */ (0,
|
|
13566
|
+
children: isRightAlign ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(import_jsx_runtime59.Fragment, { children: [
|
|
13375
13567
|
filterContent,
|
|
13376
13568
|
titleContent
|
|
13377
|
-
] }) : /* @__PURE__ */ (0,
|
|
13569
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(import_jsx_runtime59.Fragment, { children: [
|
|
13378
13570
|
titleContent,
|
|
13379
13571
|
filterContent
|
|
13380
13572
|
] })
|
|
@@ -13385,13 +13577,12 @@ function DataTable({
|
|
|
13385
13577
|
col.key
|
|
13386
13578
|
);
|
|
13387
13579
|
}) });
|
|
13388
|
-
const
|
|
13389
|
-
const processedData = import_react32.default.useMemo(() => {
|
|
13580
|
+
const processedData = import_react35.default.useMemo(() => {
|
|
13390
13581
|
if (isServerMode) return data;
|
|
13391
13582
|
let result = [...data];
|
|
13392
13583
|
if (Object.keys(filters).length > 0) {
|
|
13393
|
-
result = result.filter(
|
|
13394
|
-
|
|
13584
|
+
result = result.filter(
|
|
13585
|
+
(row) => Object.entries(filters).every(([key, value]) => {
|
|
13395
13586
|
if (value === void 0 || value === null || value === "") return true;
|
|
13396
13587
|
const col = columns.find((c) => c.key === key);
|
|
13397
13588
|
const rowValue = col?.dataIndex ? row[col.dataIndex] : row[key];
|
|
@@ -13399,8 +13590,8 @@ function DataTable({
|
|
|
13399
13590
|
return new Date(rowValue).toDateString() === value.toDateString();
|
|
13400
13591
|
}
|
|
13401
13592
|
return String(rowValue ?? "").toLowerCase().includes(String(value).toLowerCase());
|
|
13402
|
-
})
|
|
13403
|
-
|
|
13593
|
+
})
|
|
13594
|
+
);
|
|
13404
13595
|
}
|
|
13405
13596
|
if (sort) {
|
|
13406
13597
|
result.sort((a, b) => {
|
|
@@ -13418,78 +13609,30 @@ function DataTable({
|
|
|
13418
13609
|
return result;
|
|
13419
13610
|
}, [data, isServerMode, filters, sort, columns]);
|
|
13420
13611
|
const totalItems = isServerMode ? total : processedData.length;
|
|
13421
|
-
const displayedData = isServerMode ? data :
|
|
13612
|
+
const displayedData = isServerMode ? data : import_react35.default.useMemo(() => {
|
|
13422
13613
|
const start = (curPage - 1) * curPageSize;
|
|
13423
|
-
if (start >= processedData.length && curPage > 1) {
|
|
13424
|
-
}
|
|
13425
13614
|
return processedData.slice(start, start + curPageSize);
|
|
13426
13615
|
}, [processedData, curPage, curPageSize]);
|
|
13427
|
-
return /* @__PURE__ */ (0,
|
|
13428
|
-
/* @__PURE__ */ (0,
|
|
13429
|
-
|
|
13430
|
-
|
|
13431
|
-
|
|
13432
|
-
|
|
13433
|
-
|
|
13434
|
-
|
|
13435
|
-
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
|
|
13441
|
-
|
|
13442
|
-
|
|
13443
|
-
|
|
13444
|
-
|
|
13445
|
-
|
|
13446
|
-
|
|
13447
|
-
{
|
|
13448
|
-
trigger: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
13449
|
-
/* @__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)(
|
|
13450
|
-
"path",
|
|
13451
|
-
{
|
|
13452
|
-
strokeLinecap: "round",
|
|
13453
|
-
strokeLinejoin: "round",
|
|
13454
|
-
strokeWidth: 2,
|
|
13455
|
-
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"
|
|
13456
|
-
}
|
|
13457
|
-
) }),
|
|
13458
|
-
labels?.columns || t("columns")
|
|
13459
|
-
] }),
|
|
13460
|
-
children: columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
|
|
13461
|
-
DropdownMenuItem,
|
|
13462
|
-
{
|
|
13463
|
-
onClick: () => {
|
|
13464
|
-
setVisibleCols((prev) => prev.includes(c.key) ? prev.filter((k) => k !== c.key) : [...prev, c.key]);
|
|
13465
|
-
},
|
|
13466
|
-
children: [
|
|
13467
|
-
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("input", { type: "checkbox", className: "mr-2 rounded-md border-border", readOnly: true, checked: visibleCols.includes(c.key) }),
|
|
13468
|
-
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "truncate", children: c.title })
|
|
13469
|
-
]
|
|
13470
|
-
},
|
|
13471
|
-
c.key
|
|
13472
|
-
))
|
|
13473
|
-
}
|
|
13474
|
-
),
|
|
13475
|
-
enableHeaderAlignToggle && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13476
|
-
DropdownMenu_default,
|
|
13477
|
-
{
|
|
13478
|
-
trigger: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
13479
|
-
/* @__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" }) }),
|
|
13480
|
-
labels?.headerAlign || t("headerAlign")
|
|
13481
|
-
] }),
|
|
13482
|
-
items: [
|
|
13483
|
-
{ label: labels?.alignLeft || t("alignLeft"), onClick: () => setHeaderAlign("left") },
|
|
13484
|
-
{ label: labels?.alignCenter || t("alignCenter"), onClick: () => setHeaderAlign("center") },
|
|
13485
|
-
{ label: labels?.alignRight || t("alignRight"), onClick: () => setHeaderAlign("right") }
|
|
13486
|
-
]
|
|
13487
|
-
}
|
|
13488
|
-
),
|
|
13489
|
-
toolbar
|
|
13490
|
-
] })
|
|
13491
|
-
] }),
|
|
13492
|
-
/* @__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)(
|
|
13493
13636
|
"div",
|
|
13494
13637
|
{
|
|
13495
13638
|
className: cn("relative rounded-2xl md:rounded-3xl border border-border/50", loading2 && "opacity-60 pointer-events-none"),
|
|
@@ -13498,7 +13641,7 @@ function DataTable({
|
|
|
13498
13641
|
overflowY: "auto",
|
|
13499
13642
|
overflowX: "auto"
|
|
13500
13643
|
} : { overflowX: "auto" },
|
|
13501
|
-
children: /* @__PURE__ */ (0,
|
|
13644
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
|
|
13502
13645
|
Table,
|
|
13503
13646
|
{
|
|
13504
13647
|
containerClassName: cn("border-0 md:border-0 rounded-none md:rounded-none shadow-none bg-transparent", "overflow-visible"),
|
|
@@ -13508,11 +13651,11 @@ function DataTable({
|
|
|
13508
13651
|
),
|
|
13509
13652
|
style: { minWidth: totalColumnsWidth > 0 ? `${totalColumnsWidth}px` : void 0 },
|
|
13510
13653
|
children: [
|
|
13511
|
-
/* @__PURE__ */ (0,
|
|
13512
|
-
/* @__PURE__ */ (0,
|
|
13513
|
-
/* @__PURE__ */ (0,
|
|
13514
|
-
/* @__PURE__ */ (0,
|
|
13515
|
-
/* @__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)(
|
|
13516
13659
|
"path",
|
|
13517
13660
|
{
|
|
13518
13661
|
className: "opacity-75",
|
|
@@ -13521,18 +13664,17 @@ function DataTable({
|
|
|
13521
13664
|
}
|
|
13522
13665
|
)
|
|
13523
13666
|
] }),
|
|
13524
|
-
/* @__PURE__ */ (0,
|
|
13667
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "text-sm", children: [
|
|
13525
13668
|
t("loading"),
|
|
13526
13669
|
"\u2026"
|
|
13527
13670
|
] })
|
|
13528
|
-
] }) }) }) : !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) => {
|
|
13529
13672
|
const isLastRow = idx === displayedData.length - 1;
|
|
13530
|
-
return /* @__PURE__ */ (0,
|
|
13673
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13531
13674
|
TableRow,
|
|
13532
13675
|
{
|
|
13533
13676
|
className: cn(densityRowClass),
|
|
13534
13677
|
style: {
|
|
13535
|
-
// content-visibility: auto for rendering performance (skip off-screen rows)
|
|
13536
13678
|
contentVisibility: "auto",
|
|
13537
13679
|
containIntrinsicSize: density === "compact" ? "0 36px" : density === "comfortable" ? "0 56px" : "0 48px"
|
|
13538
13680
|
},
|
|
@@ -13542,7 +13684,7 @@ function DataTable({
|
|
|
13542
13684
|
const prevCol = colIdx > 0 ? visibleColumns[colIdx - 1] : null;
|
|
13543
13685
|
const isAfterFixedLeft = prevCol?.fixed === "left";
|
|
13544
13686
|
const showBorderLeft = columnDividers && colIdx > 0 && !isAfterFixedLeft && !col.fixed;
|
|
13545
|
-
return /* @__PURE__ */ (0,
|
|
13687
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13546
13688
|
TableCell,
|
|
13547
13689
|
{
|
|
13548
13690
|
style: getStickyColumnStyle(col),
|
|
@@ -13553,13 +13695,8 @@ function DataTable({
|
|
|
13553
13695
|
showBorderLeft && "border-l border-border/60",
|
|
13554
13696
|
isLastRow && col === visibleColumns[0] && "rounded-bl-2xl md:rounded-bl-3xl",
|
|
13555
13697
|
isLastRow && col === visibleColumns[visibleColumns.length - 1] && "rounded-br-2xl md:rounded-br-3xl",
|
|
13556
|
-
|
|
13557
|
-
col.fixed
|
|
13558
|
-
"sticky z-10",
|
|
13559
|
-
col.fixed === "left" && "left-0 shadow-[2px_0_5px_-2px_rgba(0,0,0,0.15)]",
|
|
13560
|
-
col.fixed === "right" && "right-0 shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.15)]",
|
|
13561
|
-
isStripedRow ? "bg-muted!" : "bg-card!"
|
|
13562
|
-
) : isStripedRow && "bg-muted/50"
|
|
13698
|
+
getStickyCellClass(col, isStripedRow),
|
|
13699
|
+
!col.fixed && isStripedRow && "bg-muted/50"
|
|
13563
13700
|
),
|
|
13564
13701
|
children: col.render ? col.render(value, row, idx) : String(value ?? "")
|
|
13565
13702
|
},
|
|
@@ -13575,90 +13712,26 @@ function DataTable({
|
|
|
13575
13712
|
)
|
|
13576
13713
|
}
|
|
13577
13714
|
),
|
|
13578
|
-
|
|
13579
|
-
|
|
13580
|
-
|
|
13581
|
-
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
|
|
13587
|
-
|
|
13588
|
-
|
|
13589
|
-
{
|
|
13590
|
-
variant: "ghost",
|
|
13591
|
-
size: "sm",
|
|
13592
|
-
className: "h-7 w-7 p-0 rounded-full",
|
|
13593
|
-
onClick: () => setCurPage(Math.max(1, curPage - 1)),
|
|
13594
|
-
disabled: curPage === 1,
|
|
13595
|
-
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" }) })
|
|
13596
|
-
}
|
|
13597
|
-
),
|
|
13598
|
-
(() => {
|
|
13599
|
-
const totalPages = Math.ceil(totalItems / curPageSize);
|
|
13600
|
-
const pages = [];
|
|
13601
|
-
if (totalPages <= 5) {
|
|
13602
|
-
for (let i = 1; i <= totalPages; i++) pages.push(i);
|
|
13603
|
-
} else {
|
|
13604
|
-
pages.push(1);
|
|
13605
|
-
if (curPage > 3) pages.push("...");
|
|
13606
|
-
const start = Math.max(2, curPage - 1);
|
|
13607
|
-
const end = Math.min(totalPages - 1, curPage + 1);
|
|
13608
|
-
for (let i = start; i <= end; i++) pages.push(i);
|
|
13609
|
-
if (curPage < totalPages - 2) pages.push("...");
|
|
13610
|
-
pages.push(totalPages);
|
|
13611
|
-
}
|
|
13612
|
-
return pages.map(
|
|
13613
|
-
(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)(
|
|
13614
|
-
"button",
|
|
13615
|
-
{
|
|
13616
|
-
onClick: () => setCurPage(p),
|
|
13617
|
-
className: cn(
|
|
13618
|
-
"h-7 min-w-7 px-2 rounded-full text-xs font-medium transition-colors",
|
|
13619
|
-
curPage === p ? "bg-primary text-primary-foreground" : "hover:bg-accent hover:text-accent-foreground"
|
|
13620
|
-
),
|
|
13621
|
-
children: p
|
|
13622
|
-
},
|
|
13623
|
-
p
|
|
13624
|
-
)
|
|
13625
|
-
);
|
|
13626
|
-
})(),
|
|
13627
|
-
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13628
|
-
Button_default,
|
|
13629
|
-
{
|
|
13630
|
-
variant: "ghost",
|
|
13631
|
-
size: "sm",
|
|
13632
|
-
className: "h-7 w-7 p-0 rounded-full",
|
|
13633
|
-
onClick: () => setCurPage(Math.min(Math.ceil(totalItems / curPageSize), curPage + 1)),
|
|
13634
|
-
disabled: curPage === Math.ceil(totalItems / curPageSize),
|
|
13635
|
-
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" }) })
|
|
13636
|
-
}
|
|
13637
|
-
)
|
|
13638
|
-
] }),
|
|
13639
|
-
pageSizeOptions && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13640
|
-
Combobox,
|
|
13641
|
-
{
|
|
13642
|
-
options: pageSizeOptions.map(String),
|
|
13643
|
-
value: String(curPageSize),
|
|
13644
|
-
onChange: (v) => {
|
|
13645
|
-
setCurPage(1);
|
|
13646
|
-
setCurPageSize(Number(v));
|
|
13647
|
-
},
|
|
13648
|
-
size: "sm",
|
|
13649
|
-
className: "w-20"
|
|
13650
|
-
}
|
|
13651
|
-
)
|
|
13652
|
-
] })
|
|
13715
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
13716
|
+
DataTablePagination,
|
|
13717
|
+
{
|
|
13718
|
+
totalItems,
|
|
13719
|
+
curPage,
|
|
13720
|
+
curPageSize,
|
|
13721
|
+
setCurPage,
|
|
13722
|
+
pageSizeOptions,
|
|
13723
|
+
setCurPageSize
|
|
13724
|
+
}
|
|
13725
|
+
)
|
|
13653
13726
|
] });
|
|
13654
13727
|
}
|
|
13655
13728
|
var DataTable_default = DataTable;
|
|
13656
13729
|
|
|
13657
13730
|
// ../../components/ui/Form.tsx
|
|
13658
|
-
var
|
|
13731
|
+
var React52 = __toESM(require("react"), 1);
|
|
13659
13732
|
var import_react_hook_form = require("react-hook-form");
|
|
13660
|
-
var
|
|
13661
|
-
var FormConfigContext =
|
|
13733
|
+
var import_jsx_runtime60 = require("react/jsx-runtime");
|
|
13734
|
+
var FormConfigContext = React52.createContext({ size: "md" });
|
|
13662
13735
|
var FormWrapper = ({
|
|
13663
13736
|
children,
|
|
13664
13737
|
onSubmit,
|
|
@@ -13671,24 +13744,24 @@ var FormWrapper = ({
|
|
|
13671
13744
|
const methods = (0, import_react_hook_form.useForm)({
|
|
13672
13745
|
defaultValues: initialValues
|
|
13673
13746
|
});
|
|
13674
|
-
|
|
13747
|
+
React52.useEffect(() => {
|
|
13675
13748
|
if (initialValues) {
|
|
13676
13749
|
methods.reset(initialValues);
|
|
13677
13750
|
}
|
|
13678
13751
|
}, [JSON.stringify(initialValues)]);
|
|
13679
13752
|
const { validationSchema: _, ...formProps } = props;
|
|
13680
|
-
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 }) }) });
|
|
13681
13754
|
};
|
|
13682
13755
|
var Form = FormWrapper;
|
|
13683
|
-
var FormFieldContext =
|
|
13756
|
+
var FormFieldContext = React52.createContext({});
|
|
13684
13757
|
var FormField = ({
|
|
13685
13758
|
...props
|
|
13686
13759
|
}) => {
|
|
13687
|
-
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 }) });
|
|
13688
13761
|
};
|
|
13689
13762
|
var useFormField = () => {
|
|
13690
|
-
const fieldContext =
|
|
13691
|
-
const itemContext =
|
|
13763
|
+
const fieldContext = React52.useContext(FormFieldContext);
|
|
13764
|
+
const itemContext = React52.useContext(FormItemContext);
|
|
13692
13765
|
const { getFieldState, formState } = (0, import_react_hook_form.useFormContext)();
|
|
13693
13766
|
if (!fieldContext) {
|
|
13694
13767
|
try {
|
|
@@ -13709,27 +13782,27 @@ var useFormField = () => {
|
|
|
13709
13782
|
...fieldState
|
|
13710
13783
|
};
|
|
13711
13784
|
};
|
|
13712
|
-
var FormItemContext =
|
|
13713
|
-
var FormItem =
|
|
13714
|
-
const id =
|
|
13715
|
-
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 }) });
|
|
13716
13789
|
});
|
|
13717
13790
|
FormItem.displayName = "FormItem";
|
|
13718
|
-
var FormLabel =
|
|
13791
|
+
var FormLabel = React52.forwardRef(
|
|
13719
13792
|
({ className, children, required, ...props }, ref) => {
|
|
13720
13793
|
const { error, formItemId } = useFormField();
|
|
13721
|
-
const config =
|
|
13794
|
+
const config = React52.useContext(FormConfigContext);
|
|
13722
13795
|
const sizeClass = config.size === "sm" ? "text-xs" : config.size === "lg" ? "text-base" : "text-sm";
|
|
13723
|
-
return /* @__PURE__ */ (0,
|
|
13796
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(Label, { ref, className: cn(sizeClass, error && "text-destructive", className), htmlFor: formItemId, ...props, children: [
|
|
13724
13797
|
children,
|
|
13725
|
-
required && /* @__PURE__ */ (0,
|
|
13798
|
+
required && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "text-destructive ml-1", children: "*" })
|
|
13726
13799
|
] });
|
|
13727
13800
|
}
|
|
13728
13801
|
);
|
|
13729
13802
|
FormLabel.displayName = "FormLabel";
|
|
13730
|
-
var FormControl =
|
|
13803
|
+
var FormControl = React52.forwardRef(({ ...props }, ref) => {
|
|
13731
13804
|
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
|
|
13732
|
-
return /* @__PURE__ */ (0,
|
|
13805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
|
|
13733
13806
|
"div",
|
|
13734
13807
|
{
|
|
13735
13808
|
ref,
|
|
@@ -13741,37 +13814,37 @@ var FormControl = React49.forwardRef(({ ...props }, ref) => {
|
|
|
13741
13814
|
);
|
|
13742
13815
|
});
|
|
13743
13816
|
FormControl.displayName = "FormControl";
|
|
13744
|
-
var FormDescription =
|
|
13817
|
+
var FormDescription = React52.forwardRef(({ className, ...props }, ref) => {
|
|
13745
13818
|
const { formDescriptionId } = useFormField();
|
|
13746
|
-
return /* @__PURE__ */ (0,
|
|
13819
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { ref, id: formDescriptionId, className: cn("text-sm text-muted-foreground", className), ...props });
|
|
13747
13820
|
});
|
|
13748
13821
|
FormDescription.displayName = "FormDescription";
|
|
13749
|
-
var FormMessage =
|
|
13822
|
+
var FormMessage = React52.forwardRef(({ className, children, ...props }, ref) => {
|
|
13750
13823
|
const { error, formMessageId } = useFormField();
|
|
13751
13824
|
const body = error ? String(error?.message) : children;
|
|
13752
13825
|
if (!body) {
|
|
13753
13826
|
return null;
|
|
13754
13827
|
}
|
|
13755
|
-
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 });
|
|
13756
13829
|
});
|
|
13757
13830
|
FormMessage.displayName = "FormMessage";
|
|
13758
|
-
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)(
|
|
13759
13832
|
FormField,
|
|
13760
13833
|
{
|
|
13761
13834
|
name,
|
|
13762
|
-
render: ({ field }) => /* @__PURE__ */ (0,
|
|
13763
|
-
/* @__PURE__ */ (0,
|
|
13764
|
-
/* @__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, {})
|
|
13765
13838
|
] })
|
|
13766
13839
|
}
|
|
13767
13840
|
) }));
|
|
13768
13841
|
FormInput.displayName = "FormInput";
|
|
13769
|
-
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)(
|
|
13770
13843
|
FormField,
|
|
13771
13844
|
{
|
|
13772
13845
|
name,
|
|
13773
|
-
render: ({ field }) => /* @__PURE__ */ (0,
|
|
13774
|
-
/* @__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)(
|
|
13775
13848
|
Checkbox,
|
|
13776
13849
|
{
|
|
13777
13850
|
ref,
|
|
@@ -13785,21 +13858,21 @@ var FormCheckbox = React49.forwardRef(({ name, ...props }, ref) => /* @__PURE__
|
|
|
13785
13858
|
...props
|
|
13786
13859
|
}
|
|
13787
13860
|
) }),
|
|
13788
|
-
/* @__PURE__ */ (0,
|
|
13861
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FormMessage, {})
|
|
13789
13862
|
] })
|
|
13790
13863
|
}
|
|
13791
13864
|
) }));
|
|
13792
13865
|
FormCheckbox.displayName = "FormCheckbox";
|
|
13793
|
-
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 }));
|
|
13794
13867
|
FormActions.displayName = "FormActions";
|
|
13795
|
-
var FormSubmitButton =
|
|
13796
|
-
({ 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 }) })
|
|
13797
13870
|
);
|
|
13798
13871
|
FormSubmitButton.displayName = "FormSubmitButton";
|
|
13799
13872
|
|
|
13800
13873
|
// ../../components/ui/NotificationModal.tsx
|
|
13801
13874
|
var import_lucide_react28 = require("lucide-react");
|
|
13802
|
-
var
|
|
13875
|
+
var import_jsx_runtime61 = require("react/jsx-runtime");
|
|
13803
13876
|
function NotificationModal({ isOpen, onClose, notification, titleText, openLinkText, closeText }) {
|
|
13804
13877
|
const t = useTranslations("Common");
|
|
13805
13878
|
if (!notification) return null;
|
|
@@ -13820,20 +13893,20 @@ function NotificationModal({ isOpen, onClose, notification, titleText, openLinkT
|
|
|
13820
13893
|
onClose();
|
|
13821
13894
|
}
|
|
13822
13895
|
};
|
|
13823
|
-
return /* @__PURE__ */ (0,
|
|
13824
|
-
/* @__PURE__ */ (0,
|
|
13825
|
-
/* @__PURE__ */ (0,
|
|
13826
|
-
/* @__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") })
|
|
13827
13900
|
] }),
|
|
13828
|
-
notification.title && /* @__PURE__ */ (0,
|
|
13829
|
-
notification.body && /* @__PURE__ */ (0,
|
|
13830
|
-
/* @__PURE__ */ (0,
|
|
13831
|
-
/* @__PURE__ */ (0,
|
|
13832
|
-
hasLink && /* @__PURE__ */ (0,
|
|
13833
|
-
/* @__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" }),
|
|
13834
13907
|
openLinkText || t("openLink")
|
|
13835
13908
|
] }),
|
|
13836
|
-
/* @__PURE__ */ (0,
|
|
13909
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Button_default, { variant: "ghost", size: "sm", onClick: onClose, children: closeText || t("close") })
|
|
13837
13910
|
] })
|
|
13838
13911
|
] }) });
|
|
13839
13912
|
}
|
|
@@ -13843,9 +13916,9 @@ var NotificationModal_default = NotificationModal;
|
|
|
13843
13916
|
var import_link2 = __toESM(require("next/link"), 1);
|
|
13844
13917
|
var import_navigation = require("next/navigation");
|
|
13845
13918
|
var import_lucide_react29 = require("lucide-react");
|
|
13846
|
-
var
|
|
13919
|
+
var import_jsx_runtime62 = require("react/jsx-runtime");
|
|
13847
13920
|
function MessengerIcon(props) {
|
|
13848
|
-
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)(
|
|
13849
13922
|
"path",
|
|
13850
13923
|
{
|
|
13851
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",
|
|
@@ -13854,7 +13927,7 @@ function MessengerIcon(props) {
|
|
|
13854
13927
|
) });
|
|
13855
13928
|
}
|
|
13856
13929
|
function ZaloIcon(props) {
|
|
13857
|
-
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)(
|
|
13858
13931
|
"path",
|
|
13859
13932
|
{
|
|
13860
13933
|
fill: "white",
|
|
@@ -13863,7 +13936,7 @@ function ZaloIcon(props) {
|
|
|
13863
13936
|
) });
|
|
13864
13937
|
}
|
|
13865
13938
|
function InstagramIcon(props) {
|
|
13866
|
-
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" }) });
|
|
13867
13940
|
}
|
|
13868
13941
|
function FloatingContacts({ className }) {
|
|
13869
13942
|
const pathname = (0, import_navigation.usePathname)();
|
|
@@ -13898,8 +13971,8 @@ function FloatingContacts({ className }) {
|
|
|
13898
13971
|
external: true
|
|
13899
13972
|
}
|
|
13900
13973
|
];
|
|
13901
|
-
return /* @__PURE__ */ (0,
|
|
13902
|
-
/* @__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)(
|
|
13903
13976
|
import_link2.default,
|
|
13904
13977
|
{
|
|
13905
13978
|
href: `tel:${hotline.replace(/\D/g, "")}`,
|
|
@@ -13910,10 +13983,10 @@ function FloatingContacts({ className }) {
|
|
|
13910
13983
|
"hover:scale-105 active:scale-95 transition-transform",
|
|
13911
13984
|
"bg-[#22c55e]"
|
|
13912
13985
|
),
|
|
13913
|
-
children: /* @__PURE__ */ (0,
|
|
13986
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react29.Phone, { className: "w-6 h-6" })
|
|
13914
13987
|
}
|
|
13915
13988
|
),
|
|
13916
|
-
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)(
|
|
13917
13990
|
import_link2.default,
|
|
13918
13991
|
{
|
|
13919
13992
|
href,
|
|
@@ -13925,7 +13998,7 @@ function FloatingContacts({ className }) {
|
|
|
13925
13998
|
"hover:scale-105 active:scale-95 transition-transform",
|
|
13926
13999
|
bg
|
|
13927
14000
|
),
|
|
13928
|
-
children: /* @__PURE__ */ (0,
|
|
14001
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Icon, { className: "w-6 h-6" })
|
|
13929
14002
|
},
|
|
13930
14003
|
key
|
|
13931
14004
|
))
|
|
@@ -13934,7 +14007,7 @@ function FloatingContacts({ className }) {
|
|
|
13934
14007
|
|
|
13935
14008
|
// ../../components/ui/AccessDenied.tsx
|
|
13936
14009
|
var import_lucide_react30 = require("lucide-react");
|
|
13937
|
-
var
|
|
14010
|
+
var import_jsx_runtime63 = require("react/jsx-runtime");
|
|
13938
14011
|
var VARIANT_STYLES = {
|
|
13939
14012
|
destructive: { bg: "bg-destructive/5", border: "border-destructive/20", text: "text-destructive" },
|
|
13940
14013
|
warning: { bg: "bg-warning/5", border: "border-warning/20", text: "text-warning" },
|
|
@@ -13955,32 +14028,32 @@ function AccessDenied({
|
|
|
13955
14028
|
}) {
|
|
13956
14029
|
const styles = VARIANT_STYLES[variant];
|
|
13957
14030
|
const UsedIcon = Icon || DEFAULT_ICONS[variant];
|
|
13958
|
-
return /* @__PURE__ */ (0,
|
|
13959
|
-
/* @__PURE__ */ (0,
|
|
13960
|
-
/* @__PURE__ */ (0,
|
|
13961
|
-
/* @__PURE__ */ (0,
|
|
13962
|
-
/* @__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 })
|
|
13963
14036
|
] }),
|
|
13964
|
-
children && /* @__PURE__ */ (0,
|
|
14037
|
+
children && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "mt-2 flex flex-wrap gap-2 justify-center", children })
|
|
13965
14038
|
] }) });
|
|
13966
14039
|
}
|
|
13967
14040
|
|
|
13968
14041
|
// ../../components/ui/ThemeToggleHeadless.tsx
|
|
13969
14042
|
var import_lucide_react31 = require("lucide-react");
|
|
13970
|
-
var
|
|
14043
|
+
var import_react36 = require("react");
|
|
13971
14044
|
var import_react_dom7 = require("react-dom");
|
|
13972
|
-
var
|
|
14045
|
+
var import_jsx_runtime64 = require("react/jsx-runtime");
|
|
13973
14046
|
function ThemeToggleHeadless({
|
|
13974
14047
|
theme,
|
|
13975
14048
|
onChange,
|
|
13976
14049
|
labels,
|
|
13977
14050
|
className
|
|
13978
14051
|
}) {
|
|
13979
|
-
const [isOpen, setIsOpen] = (0,
|
|
13980
|
-
const [mounted, setMounted] = (0,
|
|
13981
|
-
const triggerRef = (0,
|
|
13982
|
-
const [dropdownPosition, setDropdownPosition] = (0,
|
|
13983
|
-
(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), []);
|
|
13984
14057
|
const themes = [
|
|
13985
14058
|
{ value: "light", label: labels?.light ?? "Light", icon: import_lucide_react31.Sun },
|
|
13986
14059
|
{ value: "dark", label: labels?.dark ?? "Dark", icon: import_lucide_react31.Moon },
|
|
@@ -13998,8 +14071,8 @@ function ThemeToggleHeadless({
|
|
|
13998
14071
|
const top = rect.bottom + scrollTop + 8;
|
|
13999
14072
|
return { top, left, width };
|
|
14000
14073
|
};
|
|
14001
|
-
return /* @__PURE__ */ (0,
|
|
14002
|
-
/* @__PURE__ */ (0,
|
|
14074
|
+
return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: cn("relative", className), children: [
|
|
14075
|
+
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
|
|
14003
14076
|
Button_default,
|
|
14004
14077
|
{
|
|
14005
14078
|
variant: "ghost",
|
|
@@ -14017,25 +14090,25 @@ function ThemeToggleHeadless({
|
|
|
14017
14090
|
"aria-haspopup": "menu",
|
|
14018
14091
|
"aria-expanded": isOpen,
|
|
14019
14092
|
"aria-label": labels?.heading ?? "Theme",
|
|
14020
|
-
children: /* @__PURE__ */ (0,
|
|
14093
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(CurrentIcon, { className: "h-5 w-5" })
|
|
14021
14094
|
}
|
|
14022
14095
|
),
|
|
14023
|
-
isOpen && /* @__PURE__ */ (0,
|
|
14024
|
-
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),
|
|
14025
14098
|
typeof window !== "undefined" && dropdownPosition && (0, import_react_dom7.createPortal)(
|
|
14026
|
-
/* @__PURE__ */ (0,
|
|
14099
|
+
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
|
|
14027
14100
|
"div",
|
|
14028
14101
|
{
|
|
14029
14102
|
className: "z-9999 bg-card border border-border rounded-lg shadow-lg overflow-hidden",
|
|
14030
14103
|
style: { position: "absolute", top: dropdownPosition.top, left: dropdownPosition.left, width: dropdownPosition.width },
|
|
14031
14104
|
onMouseDown: (e) => e.stopPropagation(),
|
|
14032
14105
|
role: "menu",
|
|
14033
|
-
children: /* @__PURE__ */ (0,
|
|
14034
|
-
/* @__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" }),
|
|
14035
14108
|
themes.map((opt) => {
|
|
14036
14109
|
const Icon = opt.icon;
|
|
14037
14110
|
const active = theme === opt.value;
|
|
14038
|
-
return /* @__PURE__ */ (0,
|
|
14111
|
+
return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
|
|
14039
14112
|
Button_default,
|
|
14040
14113
|
{
|
|
14041
14114
|
variant: "ghost",
|
|
@@ -14051,9 +14124,9 @@ function ThemeToggleHeadless({
|
|
|
14051
14124
|
role: "menuitemradio",
|
|
14052
14125
|
"aria-checked": active,
|
|
14053
14126
|
children: [
|
|
14054
|
-
/* @__PURE__ */ (0,
|
|
14055
|
-
/* @__PURE__ */ (0,
|
|
14056
|
-
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" })
|
|
14057
14130
|
]
|
|
14058
14131
|
},
|
|
14059
14132
|
opt.value
|
|
@@ -14069,10 +14142,10 @@ function ThemeToggleHeadless({
|
|
|
14069
14142
|
}
|
|
14070
14143
|
|
|
14071
14144
|
// ../../components/ui/LanguageSwitcherHeadless.tsx
|
|
14072
|
-
var
|
|
14145
|
+
var import_react37 = require("react");
|
|
14073
14146
|
var import_react_dom8 = require("react-dom");
|
|
14074
14147
|
var import_lucide_react32 = require("lucide-react");
|
|
14075
|
-
var
|
|
14148
|
+
var import_jsx_runtime65 = require("react/jsx-runtime");
|
|
14076
14149
|
function LanguageSwitcherHeadless({
|
|
14077
14150
|
locales,
|
|
14078
14151
|
currentLocale,
|
|
@@ -14080,9 +14153,9 @@ function LanguageSwitcherHeadless({
|
|
|
14080
14153
|
labels,
|
|
14081
14154
|
className
|
|
14082
14155
|
}) {
|
|
14083
|
-
const [isOpen, setIsOpen] = (0,
|
|
14084
|
-
const [dropdownPosition, setDropdownPosition] = (0,
|
|
14085
|
-
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);
|
|
14086
14159
|
const currentLanguage = locales.find((l) => l.code === currentLocale) || locales[0];
|
|
14087
14160
|
const calculatePosition = () => {
|
|
14088
14161
|
const rect = triggerButtonRef.current?.getBoundingClientRect();
|
|
@@ -14094,8 +14167,8 @@ function LanguageSwitcherHeadless({
|
|
|
14094
14167
|
const top = rect.bottom + scrollTop + 8;
|
|
14095
14168
|
return { top, left, width };
|
|
14096
14169
|
};
|
|
14097
|
-
return /* @__PURE__ */ (0,
|
|
14098
|
-
/* @__PURE__ */ (0,
|
|
14170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: cn("relative", className), children: [
|
|
14171
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
14099
14172
|
Button_default,
|
|
14100
14173
|
{
|
|
14101
14174
|
variant: "ghost",
|
|
@@ -14114,22 +14187,22 @@ function LanguageSwitcherHeadless({
|
|
|
14114
14187
|
"aria-expanded": isOpen,
|
|
14115
14188
|
"aria-label": labels?.heading ?? "Language",
|
|
14116
14189
|
title: labels?.heading ?? "Language",
|
|
14117
|
-
children: /* @__PURE__ */ (0,
|
|
14190
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_lucide_react32.Globe, { className: "h-5 w-5" })
|
|
14118
14191
|
}
|
|
14119
14192
|
),
|
|
14120
|
-
isOpen && /* @__PURE__ */ (0,
|
|
14121
|
-
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),
|
|
14122
14195
|
typeof window !== "undefined" && dropdownPosition && (0, import_react_dom8.createPortal)(
|
|
14123
|
-
/* @__PURE__ */ (0,
|
|
14196
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
14124
14197
|
"div",
|
|
14125
14198
|
{
|
|
14126
14199
|
className: "z-9999 bg-card border border-border rounded-lg shadow-lg overflow-hidden",
|
|
14127
14200
|
style: { position: "absolute", top: dropdownPosition.top, left: dropdownPosition.left, width: dropdownPosition.width },
|
|
14128
14201
|
onMouseDown: (e) => e.stopPropagation(),
|
|
14129
14202
|
role: "menu",
|
|
14130
|
-
children: /* @__PURE__ */ (0,
|
|
14131
|
-
/* @__PURE__ */ (0,
|
|
14132
|
-
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)(
|
|
14133
14206
|
Button_default,
|
|
14134
14207
|
{
|
|
14135
14208
|
variant: "ghost",
|
|
@@ -14142,9 +14215,9 @@ function LanguageSwitcherHeadless({
|
|
|
14142
14215
|
role: "menuitemradio",
|
|
14143
14216
|
"aria-checked": currentLocale === language.code,
|
|
14144
14217
|
children: [
|
|
14145
|
-
language.flag && /* @__PURE__ */ (0,
|
|
14146
|
-
/* @__PURE__ */ (0,
|
|
14147
|
-
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" })
|
|
14148
14221
|
]
|
|
14149
14222
|
},
|
|
14150
14223
|
language.code
|
|
@@ -14574,7 +14647,7 @@ var VARIANT_STYLES_ALERT = {
|
|
|
14574
14647
|
};
|
|
14575
14648
|
|
|
14576
14649
|
// src/contexts/TranslationContext.tsx
|
|
14577
|
-
var
|
|
14650
|
+
var React54 = __toESM(require("react"), 1);
|
|
14578
14651
|
|
|
14579
14652
|
// locales/en.json
|
|
14580
14653
|
var en_default = {
|
|
@@ -14877,16 +14950,16 @@ var ja_default = {
|
|
|
14877
14950
|
};
|
|
14878
14951
|
|
|
14879
14952
|
// src/contexts/TranslationContext.tsx
|
|
14880
|
-
var
|
|
14953
|
+
var import_jsx_runtime66 = require("react/jsx-runtime");
|
|
14881
14954
|
var defaultTranslations2 = {
|
|
14882
14955
|
en: en_default,
|
|
14883
14956
|
vi: vi_default,
|
|
14884
14957
|
ko: ko_default,
|
|
14885
14958
|
ja: ja_default
|
|
14886
14959
|
};
|
|
14887
|
-
var TranslationContext2 =
|
|
14960
|
+
var TranslationContext2 = React54.createContext(null);
|
|
14888
14961
|
var TranslationProvider = ({ children, locale = "en", translations }) => {
|
|
14889
|
-
const t =
|
|
14962
|
+
const t = React54.useCallback(
|
|
14890
14963
|
(namespace) => {
|
|
14891
14964
|
return (key) => {
|
|
14892
14965
|
const mergedTranslations = {
|
|
@@ -14911,10 +14984,10 @@ var TranslationProvider = ({ children, locale = "en", translations }) => {
|
|
|
14911
14984
|
},
|
|
14912
14985
|
[locale, translations]
|
|
14913
14986
|
);
|
|
14914
|
-
return /* @__PURE__ */ (0,
|
|
14987
|
+
return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(TranslationContext2.Provider, { value: { locale, t }, children });
|
|
14915
14988
|
};
|
|
14916
14989
|
var useUnderverseTranslations = (namespace) => {
|
|
14917
|
-
const context =
|
|
14990
|
+
const context = React54.useContext(TranslationContext2);
|
|
14918
14991
|
if (!context) {
|
|
14919
14992
|
return (key) => {
|
|
14920
14993
|
const parts = namespace.split(".");
|
|
@@ -14936,13 +15009,13 @@ var useUnderverseTranslations = (namespace) => {
|
|
|
14936
15009
|
return context.t(namespace);
|
|
14937
15010
|
};
|
|
14938
15011
|
var useUnderverseLocale = () => {
|
|
14939
|
-
const context =
|
|
15012
|
+
const context = React54.useContext(TranslationContext2);
|
|
14940
15013
|
return context?.locale || "en";
|
|
14941
15014
|
};
|
|
14942
15015
|
|
|
14943
15016
|
// src/hooks/useSmartTranslations.tsx
|
|
14944
|
-
var
|
|
14945
|
-
var
|
|
15017
|
+
var React55 = __toESM(require("react"), 1);
|
|
15018
|
+
var import_jsx_runtime67 = require("react/jsx-runtime");
|
|
14946
15019
|
var nextIntlHooks = null;
|
|
14947
15020
|
try {
|
|
14948
15021
|
const nextIntl = require("next-intl");
|
|
@@ -14953,12 +15026,12 @@ try {
|
|
|
14953
15026
|
} catch {
|
|
14954
15027
|
nextIntlHooks = null;
|
|
14955
15028
|
}
|
|
14956
|
-
var ForceInternalContext =
|
|
15029
|
+
var ForceInternalContext = React55.createContext(false);
|
|
14957
15030
|
var ForceInternalTranslationsProvider = ({ children }) => {
|
|
14958
|
-
return /* @__PURE__ */ (0,
|
|
15031
|
+
return /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ForceInternalContext.Provider, { value: true, children });
|
|
14959
15032
|
};
|
|
14960
15033
|
function useSmartTranslations(namespace) {
|
|
14961
|
-
const forceInternal =
|
|
15034
|
+
const forceInternal = React55.useContext(ForceInternalContext);
|
|
14962
15035
|
const internalT = useUnderverseTranslations(namespace);
|
|
14963
15036
|
if (forceInternal || !nextIntlHooks?.useTranslations) {
|
|
14964
15037
|
return internalT;
|
|
@@ -14971,7 +15044,7 @@ function useSmartTranslations(namespace) {
|
|
|
14971
15044
|
}
|
|
14972
15045
|
}
|
|
14973
15046
|
function useSmartLocale() {
|
|
14974
|
-
const forceInternal =
|
|
15047
|
+
const forceInternal = React55.useContext(ForceInternalContext);
|
|
14975
15048
|
const internalLocale = useUnderverseLocale();
|
|
14976
15049
|
if (forceInternal || !nextIntlHooks?.useLocale) {
|
|
14977
15050
|
return internalLocale;
|