@shwfed/nuxt 0.7.9 → 0.7.10
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/module.json +1 -1
- package/dist/runtime/components/app.d.vue.ts +7 -56
- package/dist/runtime/components/app.vue +17 -404
- package/dist/runtime/components/app.vue.d.ts +7 -56
- package/dist/runtime/components/fields.d.vue.ts +154 -132
- package/dist/runtime/components/fields.vue +30 -295
- package/dist/runtime/components/fields.vue.d.ts +154 -132
- package/dist/runtime/components/table.d.vue.ts +63 -59
- package/dist/runtime/components/table.vue +52 -617
- package/dist/runtime/components/table.vue.d.ts +63 -59
- package/dist/runtime/components/ui/app/App.d.vue.ts +86 -0
- package/dist/runtime/components/ui/app/App.vue +414 -0
- package/dist/runtime/components/ui/app/App.vue.d.ts +86 -0
- package/dist/runtime/components/ui/checkbox/Checkbox.vue +6 -2
- package/dist/runtime/components/ui/expression-editor/ExpressionEditor.d.vue.ts +30 -0
- package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue +87 -0
- package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue.d.ts +30 -0
- package/dist/runtime/components/ui/expression-editor/index.d.ts +1 -0
- package/dist/runtime/components/ui/expression-editor/index.js +1 -0
- package/dist/runtime/components/ui/field/FieldContent.vue +1 -1
- package/dist/runtime/components/ui/field/FieldError.vue +2 -2
- package/dist/runtime/components/ui/fields/Fields.d.vue.ts +376 -0
- package/dist/runtime/components/ui/fields/Fields.vue +441 -0
- package/dist/runtime/components/ui/fields/Fields.vue.d.ts +376 -0
- package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.d.vue.ts +163 -0
- package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.vue +363 -0
- package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.vue.d.ts +163 -0
- package/dist/runtime/components/ui/input/Input.d.vue.ts +1 -0
- package/dist/runtime/components/ui/input/Input.vue +2 -0
- package/dist/runtime/components/ui/input/Input.vue.d.ts +1 -0
- package/dist/runtime/components/ui/input-group/InputGroupAddon.vue +4 -1
- package/dist/runtime/components/ui/input-group/InputGroupCombobox.d.vue.ts +8 -3
- package/dist/runtime/components/ui/input-group/InputGroupCombobox.vue +8 -3
- package/dist/runtime/components/ui/input-group/InputGroupCombobox.vue.d.ts +8 -3
- package/dist/runtime/components/ui/input-group/InputGroupComboboxInput.d.vue.ts +8 -1
- package/dist/runtime/components/ui/input-group/InputGroupComboboxInput.vue +10 -1
- package/dist/runtime/components/ui/input-group/InputGroupComboboxInput.vue.d.ts +8 -1
- package/dist/runtime/components/ui/input-group/InputGroupNumberField.d.vue.ts +5 -2
- package/dist/runtime/components/ui/input-group/InputGroupNumberField.vue +9 -3
- package/dist/runtime/components/ui/input-group/InputGroupNumberField.vue.d.ts +5 -2
- package/dist/runtime/components/ui/input-group/index.js +1 -1
- package/dist/runtime/components/ui/locale/Locale.d.vue.ts +20 -0
- package/dist/runtime/components/ui/locale/Locale.vue +291 -0
- package/dist/runtime/components/ui/locale/Locale.vue.d.ts +20 -0
- package/dist/runtime/components/ui/locale/index.d.ts +1 -0
- package/dist/runtime/components/ui/locale/index.js +1 -0
- package/dist/runtime/components/ui/native-select/NativeSelectOption.d.vue.ts +1 -0
- package/dist/runtime/components/ui/native-select/NativeSelectOption.vue +4 -1
- package/dist/runtime/components/ui/native-select/NativeSelectOption.vue.d.ts +1 -0
- package/dist/runtime/components/ui/number-field/NumberFieldInput.vue +1 -1
- package/dist/runtime/components/ui/switch/Switch.vue +1 -1
- package/dist/runtime/components/ui/table/Table.d.vue.ts +81 -0
- package/dist/runtime/components/ui/table/Table.vue +792 -0
- package/dist/runtime/components/ui/table/Table.vue.d.ts +81 -0
- package/dist/runtime/components/ui/table/schema.d.ts +48 -0
- package/dist/runtime/components/ui/table/schema.js +126 -0
- package/dist/runtime/components/ui/table-configurator/TableConfiguratorDialog.d.vue.ts +62 -0
- package/dist/runtime/components/ui/table-configurator/TableConfiguratorDialog.vue +2233 -0
- package/dist/runtime/components/ui/table-configurator/TableConfiguratorDialog.vue.d.ts +62 -0
- package/dist/runtime/components/ui/table-configurator/menu.d.ts +37 -0
- package/dist/runtime/components/ui/table-configurator/menu.js +227 -0
- package/dist/runtime/components/ui/tabs/Tabs.d.vue.ts +24 -0
- package/dist/runtime/components/ui/tabs/Tabs.vue +30 -0
- package/dist/runtime/components/ui/tabs/Tabs.vue.d.ts +24 -0
- package/dist/runtime/components/ui/tabs/TabsContent.d.vue.ts +18 -0
- package/dist/runtime/components/ui/tabs/TabsContent.vue +23 -0
- package/dist/runtime/components/ui/tabs/TabsContent.vue.d.ts +18 -0
- package/dist/runtime/components/ui/tabs/TabsList.d.vue.ts +18 -0
- package/dist/runtime/components/ui/tabs/TabsList.vue +25 -0
- package/dist/runtime/components/ui/tabs/TabsList.vue.d.ts +18 -0
- package/dist/runtime/components/ui/tabs/TabsTrigger.d.vue.ts +18 -0
- package/dist/runtime/components/ui/tabs/TabsTrigger.vue +27 -0
- package/dist/runtime/components/ui/tabs/TabsTrigger.vue.d.ts +18 -0
- package/dist/runtime/components/ui/tabs/index.d.ts +4 -0
- package/dist/runtime/components/ui/tabs/index.js +4 -0
- package/dist/runtime/components/ui/textarea/Textarea.d.vue.ts +1 -0
- package/dist/runtime/components/ui/textarea/Textarea.vue +3 -1
- package/dist/runtime/components/ui/textarea/Textarea.vue.d.ts +1 -0
- package/dist/runtime/components/ui/toggle/Toggle.d.vue.ts +34 -0
- package/dist/runtime/components/ui/toggle/Toggle.vue +32 -0
- package/dist/runtime/components/ui/toggle/Toggle.vue.d.ts +34 -0
- package/dist/runtime/components/ui/toggle/index.d.ts +7 -0
- package/dist/runtime/components/ui/toggle/index.js +22 -0
- package/dist/runtime/composables/useTableRenderers.d.ts +2 -1
- package/dist/runtime/composables/useTableRenderers.js +2 -1
- package/dist/runtime/style.css +1 -1
- package/dist/runtime/table-renderers/builtins.js +213 -98
- package/dist/runtime/table-renderers/registry.d.ts +1 -0
- package/dist/runtime/table-renderers/registry.js +3 -0
- package/dist/runtime/utils/coders.d.ts +27 -2
- package/dist/runtime/utils/coders.js +27 -2
- package/package.json +3 -1
- /package/dist/runtime/components/{logo.d.vue.ts → ui/logo/Logo.d.vue.ts} +0 -0
- /package/dist/runtime/components/{logo.vue → ui/logo/Logo.vue} +0 -0
- /package/dist/runtime/components/{logo.vue.d.ts → ui/logo/Logo.vue.d.ts} +0 -0
|
@@ -0,0 +1,792 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useNuxtApp } from "#app";
|
|
3
|
+
import { useCheating } from "#imports";
|
|
4
|
+
import { Icon } from "@iconify/vue";
|
|
5
|
+
import {
|
|
6
|
+
FlexRender,
|
|
7
|
+
getCoreRowModel,
|
|
8
|
+
getExpandedRowModel,
|
|
9
|
+
getPaginationRowModel,
|
|
10
|
+
useVueTable
|
|
11
|
+
} from "@tanstack/vue-table";
|
|
12
|
+
import { useVirtualizer } from "@tanstack/vue-virtual";
|
|
13
|
+
import { computedAsync } from "@vueuse/core";
|
|
14
|
+
import { getProperty } from "dot-prop";
|
|
15
|
+
import { Effect } from "effect";
|
|
16
|
+
import { Pagination } from "reka-ui/namespaced";
|
|
17
|
+
import { computed, ref, watchEffect } from "vue";
|
|
18
|
+
import { useI18n } from "vue-i18n";
|
|
19
|
+
import { useTableRenderers } from "../../../composables/useTableRenderers";
|
|
20
|
+
import { getLocalizedText, TableConfigC } from "./schema";
|
|
21
|
+
import { Button } from "../button";
|
|
22
|
+
import { NumberField, NumberFieldInput } from "../number-field";
|
|
23
|
+
import { Skeleton } from "../skeleton";
|
|
24
|
+
import TableConfiguratorDialog from "../table-configurator/TableConfiguratorDialog.vue";
|
|
25
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip";
|
|
26
|
+
const props = defineProps({
|
|
27
|
+
config: { type: null, required: true },
|
|
28
|
+
data: { type: Array, required: true },
|
|
29
|
+
rowCount: { type: Number, required: false }
|
|
30
|
+
});
|
|
31
|
+
const emit = defineEmits(["update:config"]);
|
|
32
|
+
const resolvedConfig = computedAsync(async () => TableConfigC.parse(await props.config.pipe(Effect.runPromise)));
|
|
33
|
+
const { t, locale } = useI18n();
|
|
34
|
+
const slots = defineSlots();
|
|
35
|
+
const { $dsl } = useNuxtApp();
|
|
36
|
+
const isCheating = useCheating();
|
|
37
|
+
const { resolveTableRenderer } = useTableRenderers();
|
|
38
|
+
const containerRef = ref(null);
|
|
39
|
+
const appliedInitialStateConfig = ref();
|
|
40
|
+
function genColumnId(column) {
|
|
41
|
+
if (typeof column.accessor === "string") {
|
|
42
|
+
return column.accessor;
|
|
43
|
+
} else if (column.accessor) {
|
|
44
|
+
return column.accessor.read;
|
|
45
|
+
} else if (column.id) {
|
|
46
|
+
return column.id;
|
|
47
|
+
}
|
|
48
|
+
return crypto.randomUUID();
|
|
49
|
+
}
|
|
50
|
+
function getColumnTitle(column) {
|
|
51
|
+
return getLocalizedText(column.title, locale.value) ?? genColumnId(column);
|
|
52
|
+
}
|
|
53
|
+
function getColumnTooltip(column) {
|
|
54
|
+
return getLocalizedText(column.tooltip, locale.value);
|
|
55
|
+
}
|
|
56
|
+
function translate(column) {
|
|
57
|
+
if (Array.isArray(column.columns) && column.columns.length > 0) {
|
|
58
|
+
return {
|
|
59
|
+
id: column.id ?? genColumnId(column),
|
|
60
|
+
header: getColumnTitle(column),
|
|
61
|
+
columns: column.columns?.map((column2) => translate(column2)) ?? [],
|
|
62
|
+
enableSorting: column.enableSorting ?? false,
|
|
63
|
+
enableMultiSort: column.enableMultiSorting,
|
|
64
|
+
enablePinning: column.enablePinning,
|
|
65
|
+
size: column.size,
|
|
66
|
+
meta: {
|
|
67
|
+
tooltip: getColumnTooltip(column),
|
|
68
|
+
grow: column.grow ?? false,
|
|
69
|
+
accessor: column.accessor
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const renderer = resolveTableRenderer(typeof column.renderer === "string" ? column.renderer : column.renderer?.id ? column.renderer.id : "table.renderer.text");
|
|
74
|
+
const options = renderer.parseOptions(column.renderer && typeof column.renderer === "object" && "props" in column.renderer ? column.renderer.props : null);
|
|
75
|
+
return {
|
|
76
|
+
id: column.id ?? genColumnId(column),
|
|
77
|
+
header: (ctx) => renderer.header?.({ ctx, options }) ?? getColumnTitle(column),
|
|
78
|
+
cell: (ctx) => {
|
|
79
|
+
const slot = slots[ctx.column.id];
|
|
80
|
+
if (slot) {
|
|
81
|
+
return slot({ cell: ctx });
|
|
82
|
+
}
|
|
83
|
+
return renderer.cell({ ctx, options });
|
|
84
|
+
},
|
|
85
|
+
accessorFn: (row, index) => {
|
|
86
|
+
const key = column.accessor;
|
|
87
|
+
if (typeof key === "string") {
|
|
88
|
+
return getProperty(row, key);
|
|
89
|
+
} else if (key !== void 0) {
|
|
90
|
+
try {
|
|
91
|
+
return $dsl.evaluate`${key.read}`({
|
|
92
|
+
row,
|
|
93
|
+
index: BigInt(index)
|
|
94
|
+
});
|
|
95
|
+
} catch (e) {
|
|
96
|
+
console.error(e);
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return void 0;
|
|
101
|
+
},
|
|
102
|
+
enableSorting: column.enableSorting ?? false,
|
|
103
|
+
enableMultiSort: column.enableMultiSorting,
|
|
104
|
+
enablePinning: column.enablePinning,
|
|
105
|
+
size: column.size,
|
|
106
|
+
columns: column.columns?.map((column2) => translate(column2)) ?? [],
|
|
107
|
+
meta: {
|
|
108
|
+
tooltip: getColumnTooltip(column),
|
|
109
|
+
grow: column.grow ?? false,
|
|
110
|
+
accessor: column.accessor
|
|
111
|
+
},
|
|
112
|
+
...renderer.columnDefOverrides
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const columns = computed(() => resolvedConfig.value?.columns.map((column) => translate(column)) ?? []);
|
|
116
|
+
const data = computed(() => props.data);
|
|
117
|
+
const isManualPagination = computed(() => props.rowCount !== void 0);
|
|
118
|
+
const totalItems = computed(() => props.rowCount ?? data.value.length);
|
|
119
|
+
const paginationLeft = computed(() => resolvedConfig.value?.paginationLeft ?? "");
|
|
120
|
+
const paginationRight = computed(() => resolvedConfig.value?.paginationRight ?? "");
|
|
121
|
+
const isConfiguratorOpen = ref(false);
|
|
122
|
+
function handleConfiguratorConfirm(nextConfig) {
|
|
123
|
+
emit("update:config", nextConfig);
|
|
124
|
+
}
|
|
125
|
+
function getRowId(originalRow, index, parent) {
|
|
126
|
+
const expression = resolvedConfig.value?.getRowId;
|
|
127
|
+
if (!expression) {
|
|
128
|
+
return parent ? `${parent.index}.${index}` : `${index}`;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const key = $dsl.evaluate`${expression}`(
|
|
132
|
+
{
|
|
133
|
+
row: originalRow,
|
|
134
|
+
index,
|
|
135
|
+
parent: parent ? {
|
|
136
|
+
id: parent.id,
|
|
137
|
+
index: BigInt(parent.index),
|
|
138
|
+
original: parent.original
|
|
139
|
+
} : null
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
if (typeof key === "string") {
|
|
143
|
+
return key;
|
|
144
|
+
}
|
|
145
|
+
} catch (e) {
|
|
146
|
+
console.error(e);
|
|
147
|
+
}
|
|
148
|
+
return parent ? `${parent.index}.${index}` : `${index}`;
|
|
149
|
+
}
|
|
150
|
+
function getSubRows(row, index) {
|
|
151
|
+
const expression = resolvedConfig.value?.getSubRows;
|
|
152
|
+
if (!expression) {
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
const value = $dsl.evaluate`${expression}`({
|
|
157
|
+
row,
|
|
158
|
+
index
|
|
159
|
+
});
|
|
160
|
+
return Array.isArray(value) ? value : void 0;
|
|
161
|
+
} catch (e) {
|
|
162
|
+
console.error(e);
|
|
163
|
+
return void 0;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function enableRowSelection(row) {
|
|
167
|
+
const expression = resolvedConfig.value?.enableRowSelection;
|
|
168
|
+
if (!expression) {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
return Boolean($dsl.evaluate`${expression}`({
|
|
173
|
+
row: row.original,
|
|
174
|
+
index: BigInt(row.index),
|
|
175
|
+
id: row.id
|
|
176
|
+
}));
|
|
177
|
+
} catch (e) {
|
|
178
|
+
console.error(e);
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function enableMultiRowSelection(row) {
|
|
183
|
+
const expression = resolvedConfig.value?.enableMultiRowSelection;
|
|
184
|
+
if (!expression) {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
return Boolean($dsl.evaluate`${expression}`({
|
|
189
|
+
row: row.original,
|
|
190
|
+
index: BigInt(row.index),
|
|
191
|
+
id: row.id
|
|
192
|
+
}));
|
|
193
|
+
} catch (e) {
|
|
194
|
+
console.error(e);
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const columnResizeMode = "onChange";
|
|
199
|
+
const baseTableOptions = {
|
|
200
|
+
get columns() {
|
|
201
|
+
return columns.value;
|
|
202
|
+
},
|
|
203
|
+
data,
|
|
204
|
+
getCoreRowModel: getCoreRowModel(),
|
|
205
|
+
getExpandedRowModel: getExpandedRowModel(),
|
|
206
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
207
|
+
get manualPagination() {
|
|
208
|
+
return isManualPagination.value;
|
|
209
|
+
},
|
|
210
|
+
get rowCount() {
|
|
211
|
+
return props.rowCount;
|
|
212
|
+
},
|
|
213
|
+
get getRowId() {
|
|
214
|
+
return resolvedConfig.value?.getRowId ? getRowId : void 0;
|
|
215
|
+
},
|
|
216
|
+
getSubRows,
|
|
217
|
+
enableRowSelection,
|
|
218
|
+
get enableMultiRowSelection() {
|
|
219
|
+
return resolvedConfig.value?.enableMultiRowSelection ? enableMultiRowSelection : void 0;
|
|
220
|
+
},
|
|
221
|
+
columnResizeMode
|
|
222
|
+
};
|
|
223
|
+
function getConfigOption(property) {
|
|
224
|
+
const configOptions = resolvedConfig.value?.props;
|
|
225
|
+
if (!configOptions) {
|
|
226
|
+
return void 0;
|
|
227
|
+
}
|
|
228
|
+
return Reflect.get(configOptions, property);
|
|
229
|
+
}
|
|
230
|
+
const tableOptions = new Proxy(baseTableOptions, {
|
|
231
|
+
get(target, property, receiver) {
|
|
232
|
+
const baseValue = Reflect.get(target, property, receiver);
|
|
233
|
+
if (baseValue !== void 0) {
|
|
234
|
+
return baseValue;
|
|
235
|
+
}
|
|
236
|
+
return getConfigOption(property);
|
|
237
|
+
},
|
|
238
|
+
has(target, property) {
|
|
239
|
+
const configOptions = resolvedConfig.value?.props;
|
|
240
|
+
return Reflect.has(target, property) || (configOptions ? Reflect.has(configOptions, property) : false);
|
|
241
|
+
},
|
|
242
|
+
ownKeys(target) {
|
|
243
|
+
const keys = [...Reflect.ownKeys(target)];
|
|
244
|
+
const configOptions = resolvedConfig.value?.props;
|
|
245
|
+
if (configOptions) {
|
|
246
|
+
keys.push(...Reflect.ownKeys(configOptions));
|
|
247
|
+
}
|
|
248
|
+
return Array.from(new Set(keys));
|
|
249
|
+
},
|
|
250
|
+
getOwnPropertyDescriptor(target, property) {
|
|
251
|
+
const configOptions = resolvedConfig.value?.props;
|
|
252
|
+
if (!Reflect.has(target, property) && !(configOptions && Reflect.has(configOptions, property))) {
|
|
253
|
+
return void 0;
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
configurable: true,
|
|
257
|
+
enumerable: true,
|
|
258
|
+
get() {
|
|
259
|
+
const baseValue = Reflect.get(target, property);
|
|
260
|
+
if (baseValue !== void 0) {
|
|
261
|
+
return baseValue;
|
|
262
|
+
}
|
|
263
|
+
return getConfigOption(property);
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
const tableApi = useVueTable(tableOptions);
|
|
269
|
+
watchEffect(() => {
|
|
270
|
+
const config = resolvedConfig.value;
|
|
271
|
+
if (!config || appliedInitialStateConfig.value === config) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const initialState = config.props?.initialState;
|
|
275
|
+
if (initialState) {
|
|
276
|
+
tableApi.initialState = mergeInitialState(tableApi.initialState, initialState);
|
|
277
|
+
tableApi.reset();
|
|
278
|
+
}
|
|
279
|
+
appliedInitialStateConfig.value = config;
|
|
280
|
+
});
|
|
281
|
+
defineExpose(tableApi);
|
|
282
|
+
const rowVirtualizer = useVirtualizer(
|
|
283
|
+
computed(() => ({
|
|
284
|
+
count: tableApi.getRowModel().rows.length,
|
|
285
|
+
estimateSize: () => 35,
|
|
286
|
+
getScrollElement: () => containerRef.value,
|
|
287
|
+
overscan: 30
|
|
288
|
+
}))
|
|
289
|
+
);
|
|
290
|
+
const rowTotalSize = computed(() => rowVirtualizer.value.getTotalSize());
|
|
291
|
+
const rowWindow = computed(() => rowVirtualizer.value.getVirtualItems());
|
|
292
|
+
function measureRow(el) {
|
|
293
|
+
if (!el || !(el instanceof Element))
|
|
294
|
+
return;
|
|
295
|
+
rowVirtualizer.value.measureElement(el);
|
|
296
|
+
}
|
|
297
|
+
const rows = computed(() => tableApi.getRowModel().rows);
|
|
298
|
+
const maxPage = computed(() => Math.max(tableApi.getPageCount(), 1));
|
|
299
|
+
function isStyleRecord(x) {
|
|
300
|
+
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
301
|
+
}
|
|
302
|
+
function getCellStyles(ctx) {
|
|
303
|
+
const expression = resolvedConfig.value?.cellStyles;
|
|
304
|
+
if (!expression)
|
|
305
|
+
return {};
|
|
306
|
+
try {
|
|
307
|
+
const result = $dsl.evaluate`${expression}`({
|
|
308
|
+
row: ctx.row.original,
|
|
309
|
+
index: BigInt(ctx.row.index),
|
|
310
|
+
id: ctx.column.id,
|
|
311
|
+
selected: ctx.row.getIsSelected(),
|
|
312
|
+
pinned: ctx.column.getIsPinned()
|
|
313
|
+
});
|
|
314
|
+
return isStyleRecord(result) ? result : {};
|
|
315
|
+
} catch (e) {
|
|
316
|
+
console.error(e);
|
|
317
|
+
return {};
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function shouldHaveRightBorder(column) {
|
|
321
|
+
switch (column.getIsPinned()) {
|
|
322
|
+
case "left":
|
|
323
|
+
return true;
|
|
324
|
+
case "right":
|
|
325
|
+
return false;
|
|
326
|
+
case false:
|
|
327
|
+
return !column.getIsLastColumn("center");
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function shouldHaveLeftBorder(column) {
|
|
331
|
+
switch (column.getIsPinned()) {
|
|
332
|
+
case "left":
|
|
333
|
+
return false;
|
|
334
|
+
case "right":
|
|
335
|
+
return true;
|
|
336
|
+
case false:
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function pinnedStyle(column) {
|
|
341
|
+
const pinned = column.getIsPinned();
|
|
342
|
+
if (!pinned)
|
|
343
|
+
return {};
|
|
344
|
+
const style = {
|
|
345
|
+
[pinned]: pinned === "left" ? `${column.getStart("left")}px` : `${column.getAfter("right")}px`
|
|
346
|
+
};
|
|
347
|
+
if (column.getIsLastColumn("left"))
|
|
348
|
+
style.boxShadow = "5px 5px 5px #00000005";
|
|
349
|
+
if (column.getIsFirstColumn("right"))
|
|
350
|
+
style.boxShadow = "-5px 5px 5px #00000005";
|
|
351
|
+
return style;
|
|
352
|
+
}
|
|
353
|
+
const SORT_ICONS = {
|
|
354
|
+
unsorted: "fluent:arrow-sort-16-regular",
|
|
355
|
+
asc: "fluent:arrow-sort-up-16-regular",
|
|
356
|
+
desc: "fluent:arrow-sort-down-16-regular"
|
|
357
|
+
};
|
|
358
|
+
function getSortIcon(column) {
|
|
359
|
+
const sortDir = column.getIsSorted();
|
|
360
|
+
const iconKey = sortDir === false ? "unsorted" : sortDir;
|
|
361
|
+
return SORT_ICONS[iconKey];
|
|
362
|
+
}
|
|
363
|
+
function mergeInitialState(current, initialState) {
|
|
364
|
+
return {
|
|
365
|
+
...current,
|
|
366
|
+
columnVisibility: initialState.columnVisibility ?? current.columnVisibility,
|
|
367
|
+
columnOrder: initialState.columnOrder ?? current.columnOrder,
|
|
368
|
+
columnPinning: initialState.columnPinning ? { ...current.columnPinning, ...initialState.columnPinning } : current.columnPinning,
|
|
369
|
+
rowPinning: initialState.rowPinning ? { ...current.rowPinning, ...initialState.rowPinning } : current.rowPinning,
|
|
370
|
+
columnFilters: initialState.columnFilters ?? current.columnFilters,
|
|
371
|
+
globalFilter: initialState.globalFilter ?? current.globalFilter,
|
|
372
|
+
sorting: initialState.sorting ?? current.sorting,
|
|
373
|
+
expanded: initialState.expanded ?? current.expanded,
|
|
374
|
+
grouping: initialState.grouping ?? current.grouping,
|
|
375
|
+
columnSizing: initialState.columnSizing ?? current.columnSizing,
|
|
376
|
+
columnSizingInfo: initialState.columnSizingInfo ?? current.columnSizingInfo,
|
|
377
|
+
pagination: initialState.pagination ? { ...current.pagination, ...initialState.pagination } : current.pagination,
|
|
378
|
+
rowSelection: initialState.rowSelection ?? current.rowSelection
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
function getSortLabel(column) {
|
|
382
|
+
const direction = column.getIsSorted();
|
|
383
|
+
if (direction === "asc") {
|
|
384
|
+
return t("table-sort-asc");
|
|
385
|
+
}
|
|
386
|
+
if (direction === "desc") {
|
|
387
|
+
return t("table-sort-desc");
|
|
388
|
+
}
|
|
389
|
+
return t("table-sort-unsorted");
|
|
390
|
+
}
|
|
391
|
+
</script>
|
|
392
|
+
|
|
393
|
+
<script>
|
|
394
|
+
export { AccessorC, ColumnC, RenderC, TableConfigC } from "./schema";
|
|
395
|
+
</script>
|
|
396
|
+
|
|
397
|
+
<template>
|
|
398
|
+
<div
|
|
399
|
+
class="relative flex h-full flex-col"
|
|
400
|
+
>
|
|
401
|
+
<Button
|
|
402
|
+
v-if="isCheating"
|
|
403
|
+
data-slot="table-configurator-trigger"
|
|
404
|
+
variant="ghost"
|
|
405
|
+
size="sm"
|
|
406
|
+
type="button"
|
|
407
|
+
class="absolute right-3 top-3 z-20 bg-white/90 shadow-xs backdrop-blur-sm hover:bg-white"
|
|
408
|
+
@click="isConfiguratorOpen = true"
|
|
409
|
+
>
|
|
410
|
+
<Icon icon="fluent:settings-20-regular" />
|
|
411
|
+
</Button>
|
|
412
|
+
|
|
413
|
+
<TableConfiguratorDialog
|
|
414
|
+
v-if="resolvedConfig"
|
|
415
|
+
v-model:open="isConfiguratorOpen"
|
|
416
|
+
:config="resolvedConfig"
|
|
417
|
+
@confirm="handleConfiguratorConfirm"
|
|
418
|
+
/>
|
|
419
|
+
|
|
420
|
+
<div
|
|
421
|
+
class="relative flex min-h-0 flex-1 flex-col"
|
|
422
|
+
>
|
|
423
|
+
<Skeleton
|
|
424
|
+
v-if="resolvedConfig === void 0"
|
|
425
|
+
class="absolute inset-0 z-10 w-full h-full"
|
|
426
|
+
/>
|
|
427
|
+
|
|
428
|
+
<div
|
|
429
|
+
:class="[
|
|
430
|
+
'flex min-h-0 flex-1 flex-col',
|
|
431
|
+
resolvedConfig === void 0 && 'opacity-0'
|
|
432
|
+
]"
|
|
433
|
+
>
|
|
434
|
+
<div
|
|
435
|
+
ref="containerRef"
|
|
436
|
+
class="overflow-scroll overscroll-none flex-1 border border-zinc-200 rounded relative"
|
|
437
|
+
>
|
|
438
|
+
<div :style="{ height: `${rowTotalSize}px` }">
|
|
439
|
+
<table class="grid">
|
|
440
|
+
<thead class="grid sticky top-0 z-10 select-none">
|
|
441
|
+
<tr
|
|
442
|
+
v-for="group in tableApi.getHeaderGroups()"
|
|
443
|
+
:key="group.id"
|
|
444
|
+
class="flex w-full border-b border-zinc-200"
|
|
445
|
+
>
|
|
446
|
+
<th
|
|
447
|
+
v-for="header in group.headers"
|
|
448
|
+
:key="header.id"
|
|
449
|
+
:colspan="header.colSpan"
|
|
450
|
+
:class="[
|
|
451
|
+
header.column.columnDef.meta?.grow && 'flex-1',
|
|
452
|
+
'flex items-center gap-2 border-zinc-300 py-2 text-zinc-600',
|
|
453
|
+
'text-xs flex items-center justify-center relative',
|
|
454
|
+
'bg-[color-mix(in_srgb,var(--primary)_10%,white)] group',
|
|
455
|
+
header.column.getIsPinned() && 'sticky z-15',
|
|
456
|
+
shouldHaveRightBorder(header.column) && 'border-r',
|
|
457
|
+
shouldHaveLeftBorder(header.column) && 'border-l'
|
|
458
|
+
]"
|
|
459
|
+
:style="{
|
|
460
|
+
width: `${header.getSize()}px`,
|
|
461
|
+
...pinnedStyle(header.column)
|
|
462
|
+
}"
|
|
463
|
+
>
|
|
464
|
+
<FlexRender
|
|
465
|
+
v-if="!header.isPlaceholder"
|
|
466
|
+
:render="header.column.columnDef.header"
|
|
467
|
+
:props="header.getContext()"
|
|
468
|
+
/>
|
|
469
|
+
|
|
470
|
+
<Tooltip
|
|
471
|
+
v-if="!header.isPlaceholder && header.column.columnDef.meta?.tooltip"
|
|
472
|
+
:delay-duration="180"
|
|
473
|
+
>
|
|
474
|
+
<TooltipTrigger as-child>
|
|
475
|
+
<Icon icon="fluent:info-20-regular" />
|
|
476
|
+
</TooltipTrigger>
|
|
477
|
+
<TooltipContent
|
|
478
|
+
align="center"
|
|
479
|
+
side="top"
|
|
480
|
+
>
|
|
481
|
+
<span v-html="$md.inline`${header.column.columnDef.meta?.tooltip}`()" />
|
|
482
|
+
</TooltipContent>
|
|
483
|
+
</Tooltip>
|
|
484
|
+
|
|
485
|
+
<Tooltip
|
|
486
|
+
v-if="!header.isPlaceholder && isCheating && header.column.columnDef.meta?.accessor"
|
|
487
|
+
:delay-duration="180"
|
|
488
|
+
>
|
|
489
|
+
<TooltipTrigger as-child>
|
|
490
|
+
<Icon icon="fluent:code-20-regular" />
|
|
491
|
+
</TooltipTrigger>
|
|
492
|
+
<TooltipContent
|
|
493
|
+
align="center"
|
|
494
|
+
side="top"
|
|
495
|
+
>
|
|
496
|
+
<template v-if="typeof header.column.columnDef.meta?.accessor === 'string'">
|
|
497
|
+
<span class="font-mono">{{ header.column.columnDef.meta?.accessor }}</span>
|
|
498
|
+
</template>
|
|
499
|
+
<template v-else>
|
|
500
|
+
<span class="font-mono">{{ JSON.stringify(header.column.columnDef.meta?.accessor) }}</span>
|
|
501
|
+
</template>
|
|
502
|
+
</TooltipContent>
|
|
503
|
+
</Tooltip>
|
|
504
|
+
|
|
505
|
+
<Tooltip
|
|
506
|
+
v-if="!header.isPlaceholder && header.column.getCanSort()"
|
|
507
|
+
:delay-duration="800"
|
|
508
|
+
>
|
|
509
|
+
<TooltipTrigger as-child>
|
|
510
|
+
<Button
|
|
511
|
+
variant="ghost"
|
|
512
|
+
size="xs"
|
|
513
|
+
:class="[
|
|
514
|
+
'absolute hover:bg-transparent right-1 top-1/2 -translate-y-1/2 transform-3d transition-opacity duration-180',
|
|
515
|
+
!header.column.getIsSorted() ? 'opacity-30 hover:opacity-60' : 'text-(--primary)/80 hover:text-(--primary)'
|
|
516
|
+
]"
|
|
517
|
+
as-child
|
|
518
|
+
>
|
|
519
|
+
<button
|
|
520
|
+
type="button"
|
|
521
|
+
@click="header.column.getToggleSortingHandler()?.($event)"
|
|
522
|
+
>
|
|
523
|
+
<Icon :icon="getSortIcon(header.column)" />
|
|
524
|
+
</button>
|
|
525
|
+
</Button>
|
|
526
|
+
</TooltipTrigger>
|
|
527
|
+
<TooltipContent>
|
|
528
|
+
{{ getSortLabel(header.column) }}
|
|
529
|
+
</TooltipContent>
|
|
530
|
+
</Tooltip>
|
|
531
|
+
|
|
532
|
+
<div
|
|
533
|
+
v-if="!header.isPlaceholder && header.column.getCanResize() && (!header.column.getIsLastColumn('right') || !tableApi.getIsSomeColumnsPinned('right') && !header.column.getIsLastColumn('center'))"
|
|
534
|
+
:class="[
|
|
535
|
+
'group',
|
|
536
|
+
'absolute',
|
|
537
|
+
'top-0',
|
|
538
|
+
'bottom-0',
|
|
539
|
+
'right-0',
|
|
540
|
+
'px-2',
|
|
541
|
+
'translate-x-2',
|
|
542
|
+
'z-5',
|
|
543
|
+
'opacity-0',
|
|
544
|
+
'duration-150',
|
|
545
|
+
'transition-opacity',
|
|
546
|
+
'ease-out',
|
|
547
|
+
'hover:opacity-100',
|
|
548
|
+
'cursor-col-resize'
|
|
549
|
+
]"
|
|
550
|
+
@mousedown="header.getResizeHandler()($event)"
|
|
551
|
+
>
|
|
552
|
+
<div :class="['w-2pt', 'h-full', 'translate-x-1pt', 'transform-3d', 'bg-[color-mix(in_srgb,var(--primary)_80%,white)]']" />
|
|
553
|
+
</div>
|
|
554
|
+
</th>
|
|
555
|
+
</tr>
|
|
556
|
+
</thead>
|
|
557
|
+
|
|
558
|
+
<tbody
|
|
559
|
+
class="grid relative"
|
|
560
|
+
:style="{ height: `${rowTotalSize}px` }"
|
|
561
|
+
>
|
|
562
|
+
<tr
|
|
563
|
+
v-for="r in rowWindow"
|
|
564
|
+
:key="rows[r.index]?.id ?? r.index"
|
|
565
|
+
:ref="measureRow"
|
|
566
|
+
class="flex absolute w-full not-last:border-b border-zinc-300"
|
|
567
|
+
:data-index="rows[r.index]?.index"
|
|
568
|
+
:style="{ transform: `translate3d(0, ${r.start}px, 0)` }"
|
|
569
|
+
>
|
|
570
|
+
<td
|
|
571
|
+
v-for="cell in rows[r.index]?.getVisibleCells() ?? []"
|
|
572
|
+
:key="cell.id"
|
|
573
|
+
:class="[
|
|
574
|
+
'border-zinc-300',
|
|
575
|
+
cell.column.columnDef.meta?.grow && 'flex-1',
|
|
576
|
+
cell.column.getIsPinned() && 'sticky z-15',
|
|
577
|
+
shouldHaveRightBorder(cell.column) && 'border-r',
|
|
578
|
+
shouldHaveLeftBorder(cell.column) && 'border-l'
|
|
579
|
+
]"
|
|
580
|
+
:style="{
|
|
581
|
+
width: `${cell.column.getSize()}px`,
|
|
582
|
+
...pinnedStyle(cell.column),
|
|
583
|
+
...getCellStyles(cell.getContext())
|
|
584
|
+
}"
|
|
585
|
+
>
|
|
586
|
+
<FlexRender
|
|
587
|
+
:render="cell.column.columnDef.cell"
|
|
588
|
+
:props="cell.getContext()"
|
|
589
|
+
/>
|
|
590
|
+
</td>
|
|
591
|
+
</tr>
|
|
592
|
+
</tbody>
|
|
593
|
+
|
|
594
|
+
<tfoot class="hidden has-data-footer:grid sticky bottom-0 z-10 select-none border-t border-zinc-200">
|
|
595
|
+
<tr
|
|
596
|
+
v-for="group in tableApi.getFooterGroups()"
|
|
597
|
+
:key="group.id"
|
|
598
|
+
class="flex w-full border-zinc-200"
|
|
599
|
+
>
|
|
600
|
+
<th
|
|
601
|
+
v-for="header in group.headers"
|
|
602
|
+
:key="header.id"
|
|
603
|
+
:colSpan="header.colSpan"
|
|
604
|
+
:class="[
|
|
605
|
+
header.column.columnDef.meta?.grow && 'flex-1',
|
|
606
|
+
'flex items-center gap-2 border-zinc-300 text-zinc-600 p-0',
|
|
607
|
+
'text-xs flex items-center justify-center relative',
|
|
608
|
+
'bg-[color-mix(in_srgb,var(--primary)_10%,white)] group',
|
|
609
|
+
header.column.getIsPinned() && 'sticky z-15',
|
|
610
|
+
shouldHaveRightBorder(header.column) && 'border-r',
|
|
611
|
+
shouldHaveLeftBorder(header.column) && 'border-l'
|
|
612
|
+
]"
|
|
613
|
+
:style="{
|
|
614
|
+
width: `${header.getSize()}px`,
|
|
615
|
+
...pinnedStyle(header.column)
|
|
616
|
+
}"
|
|
617
|
+
>
|
|
618
|
+
<FlexRender
|
|
619
|
+
v-if="!header.isPlaceholder"
|
|
620
|
+
:render="header.column.columnDef.footer"
|
|
621
|
+
:props="header.getContext()"
|
|
622
|
+
/>
|
|
623
|
+
</th>
|
|
624
|
+
</tr>
|
|
625
|
+
</tfoot>
|
|
626
|
+
</table>
|
|
627
|
+
</div>
|
|
628
|
+
</div>
|
|
629
|
+
|
|
630
|
+
<div class="flex items-center justify-between w-full py-2 gap-2 text-sm text-zinc-600">
|
|
631
|
+
<div
|
|
632
|
+
:class="[
|
|
633
|
+
'relative p-1 flex-1 prose prose-zinc text-xs'
|
|
634
|
+
]"
|
|
635
|
+
>
|
|
636
|
+
<span
|
|
637
|
+
v-html="$md.inline`${paginationLeft}`({
|
|
638
|
+
selected: tableApi.getSelectedRowModel().rows.map((row) => row.original)
|
|
639
|
+
})"
|
|
640
|
+
/>
|
|
641
|
+
|
|
642
|
+
</div>
|
|
643
|
+
<div class="flex items-center gap-4">
|
|
644
|
+
<i18n-t
|
|
645
|
+
keypath="total"
|
|
646
|
+
tag="span"
|
|
647
|
+
class="text-xs"
|
|
648
|
+
>
|
|
649
|
+
<template #count>
|
|
650
|
+
<strong>{{ totalItems }}</strong>
|
|
651
|
+
</template>
|
|
652
|
+
</i18n-t>
|
|
653
|
+
<Pagination.Root
|
|
654
|
+
show-edges
|
|
655
|
+
:total="totalItems"
|
|
656
|
+
:items-per-page="tableApi.getState().pagination.pageSize"
|
|
657
|
+
:page="tableApi.getState().pagination.pageIndex + 1"
|
|
658
|
+
@update:page="(page2) => tableApi.setPageIndex(page2 - 1)"
|
|
659
|
+
>
|
|
660
|
+
<Pagination.List
|
|
661
|
+
v-slot="{ items }"
|
|
662
|
+
class="flex items-center gap-1"
|
|
663
|
+
>
|
|
664
|
+
<Pagination.First
|
|
665
|
+
:class="[
|
|
666
|
+
'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
|
|
667
|
+
'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
|
|
668
|
+
]"
|
|
669
|
+
>
|
|
670
|
+
<Icon
|
|
671
|
+
icon="radix-icons:double-arrow-left"
|
|
672
|
+
class="w-4 h-4"
|
|
673
|
+
/>
|
|
674
|
+
</Pagination.First>
|
|
675
|
+
<Pagination.Prev
|
|
676
|
+
:class="[
|
|
677
|
+
'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
|
|
678
|
+
'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
|
|
679
|
+
]"
|
|
680
|
+
>
|
|
681
|
+
<Icon
|
|
682
|
+
icon="radix-icons:chevron-left"
|
|
683
|
+
class="w-4 h-4"
|
|
684
|
+
/>
|
|
685
|
+
</Pagination.Prev>
|
|
686
|
+
|
|
687
|
+
<template
|
|
688
|
+
v-for="(page, index) in items"
|
|
689
|
+
:key="page.type === 'page' ? `${page.type}-${page.value}` : `${page.type}-${index}`"
|
|
690
|
+
>
|
|
691
|
+
<Pagination.ListItem
|
|
692
|
+
v-if="page.type === 'page'"
|
|
693
|
+
:class="[
|
|
694
|
+
'w-7 h-7 flex items-center justify-center rounded text-xs bg-transparent',
|
|
695
|
+
'data-selected:text-(--primary) hover:bg-zinc-100 transition cursor-pointer'
|
|
696
|
+
]"
|
|
697
|
+
:value="page.value"
|
|
698
|
+
>
|
|
699
|
+
{{ page.value }}
|
|
700
|
+
</Pagination.ListItem>
|
|
701
|
+
<Pagination.Ellipsis
|
|
702
|
+
v-else
|
|
703
|
+
class="w-7 h-7 flex items-center justify-center text-zinc-400"
|
|
704
|
+
>
|
|
705
|
+
…
|
|
706
|
+
</Pagination.Ellipsis>
|
|
707
|
+
</template>
|
|
708
|
+
|
|
709
|
+
<Pagination.Next
|
|
710
|
+
:class="[
|
|
711
|
+
'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
|
|
712
|
+
'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
|
|
713
|
+
]"
|
|
714
|
+
>
|
|
715
|
+
<Icon
|
|
716
|
+
icon="radix-icons:chevron-right"
|
|
717
|
+
class="w-4 h-4"
|
|
718
|
+
/>
|
|
719
|
+
</Pagination.Next>
|
|
720
|
+
<Pagination.Last
|
|
721
|
+
:class="[
|
|
722
|
+
'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
|
|
723
|
+
'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
|
|
724
|
+
]"
|
|
725
|
+
>
|
|
726
|
+
<Icon
|
|
727
|
+
icon="radix-icons:double-arrow-right"
|
|
728
|
+
class="w-4 h-4"
|
|
729
|
+
/>
|
|
730
|
+
</Pagination.Last>
|
|
731
|
+
</Pagination.List>
|
|
732
|
+
</Pagination.Root>
|
|
733
|
+
<i18n-t
|
|
734
|
+
keypath="goto"
|
|
735
|
+
tag="div"
|
|
736
|
+
class="text-xs flex items-center gap-2"
|
|
737
|
+
>
|
|
738
|
+
<template #page>
|
|
739
|
+
<NumberField
|
|
740
|
+
:model-value="tableApi.getState().pagination.pageIndex + 1"
|
|
741
|
+
:min="1"
|
|
742
|
+
:max="maxPage"
|
|
743
|
+
@update:model-value="(value) => tableApi.setPageIndex(value - 1)"
|
|
744
|
+
>
|
|
745
|
+
<NumberFieldInput class="h-6 w-16 text-xs" />
|
|
746
|
+
</NumberField>
|
|
747
|
+
</template>
|
|
748
|
+
</i18n-t>
|
|
749
|
+
</div>
|
|
750
|
+
<div
|
|
751
|
+
:class="[
|
|
752
|
+
'relative p-1 flex-1 prose prose-zinc text-xs'
|
|
753
|
+
]"
|
|
754
|
+
>
|
|
755
|
+
<span
|
|
756
|
+
v-html="$md.inline`${paginationRight}`({
|
|
757
|
+
selected: tableApi.getSelectedRowModel().rows.map((row) => row.original)
|
|
758
|
+
})"
|
|
759
|
+
/>
|
|
760
|
+
|
|
761
|
+
</div>
|
|
762
|
+
</div>
|
|
763
|
+
</div>
|
|
764
|
+
</div>
|
|
765
|
+
</div>
|
|
766
|
+
</template>
|
|
767
|
+
|
|
768
|
+
<i18n lang="json">
|
|
769
|
+
{
|
|
770
|
+
"zh": {
|
|
771
|
+
"total": "共 {count} 条",
|
|
772
|
+
"goto": "前往 {page} 页",
|
|
773
|
+
"table-sort-asc": "升序",
|
|
774
|
+
"table-sort-desc": "降序",
|
|
775
|
+
"table-sort-unsorted": "未排序"
|
|
776
|
+
},
|
|
777
|
+
"ja": {
|
|
778
|
+
"total": "合計 {count} 件",
|
|
779
|
+
"goto": "ページ {page} に移動",
|
|
780
|
+
"table-sort-asc": "昇順",
|
|
781
|
+
"table-sort-desc": "降順",
|
|
782
|
+
"table-sort-unsorted": "未排序"
|
|
783
|
+
},
|
|
784
|
+
"en": {
|
|
785
|
+
"total": "Total {count} items",
|
|
786
|
+
"goto": "Go to page {page}",
|
|
787
|
+
"table-sort-asc": "Ascending",
|
|
788
|
+
"table-sort-desc": "Descending",
|
|
789
|
+
"table-sort-unsorted": "Unsorted"
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
</i18n>
|