@shwfed/nuxt 0.10.2 → 0.10.4
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/button.d.vue.ts +77 -0
- package/dist/runtime/components/button.vue +39 -0
- package/dist/runtime/components/button.vue.d.ts +77 -0
- package/dist/runtime/components/fields.d.vue.ts +2 -2
- package/dist/runtime/components/fields.vue.d.ts +2 -2
- package/dist/runtime/components/ui/button-configurator/ButtonConfiguratorDialog.d.vue.ts +79 -0
- package/dist/runtime/components/ui/button-configurator/ButtonConfiguratorDialog.vue +977 -0
- package/dist/runtime/components/ui/button-configurator/ButtonConfiguratorDialog.vue.d.ts +79 -0
- package/dist/runtime/components/ui/button-configurator/menu.d.ts +47 -0
- package/dist/runtime/components/ui/button-configurator/menu.js +373 -0
- package/dist/runtime/components/ui/buttons/Buttons.d.vue.ts +77 -0
- package/dist/runtime/components/ui/buttons/Buttons.vue +238 -0
- package/dist/runtime/components/ui/buttons/Buttons.vue.d.ts +77 -0
- package/dist/runtime/components/ui/buttons/schema.d.ts +281 -0
- package/dist/runtime/components/ui/buttons/schema.js +50 -0
- package/dist/runtime/components/ui/command/CommandInput.vue +1 -1
- package/dist/runtime/components/ui/fields/Fields.d.vue.ts +4 -4
- package/dist/runtime/components/ui/fields/Fields.vue +306 -134
- package/dist/runtime/components/ui/fields/Fields.vue.d.ts +4 -4
- package/dist/runtime/components/ui/fields/schema.d.ts +3 -3
- package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.d.vue.ts +2 -2
- package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.vue.d.ts +2 -2
- package/dist/runtime/components/ui/table/Table.vue +10 -9
- package/package.json +1 -1
|
@@ -0,0 +1,977 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useSortable } from "@vueuse/integrations/useSortable";
|
|
3
|
+
import { Icon } from "@iconify/vue";
|
|
4
|
+
import { computed, nextTick, ref, watch } from "vue";
|
|
5
|
+
import { useI18n } from "vue-i18n";
|
|
6
|
+
import { cn } from "../../../utils/cn";
|
|
7
|
+
import { Button } from "../button";
|
|
8
|
+
import { ButtonConfigC } from "../buttons/schema";
|
|
9
|
+
import { Checkbox } from "../checkbox";
|
|
10
|
+
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../dialog";
|
|
11
|
+
import { IconPicker } from "../icon-picker";
|
|
12
|
+
import { Input } from "../input";
|
|
13
|
+
import Locale from "../locale/Locale.vue";
|
|
14
|
+
import { NativeSelect, NativeSelectOption } from "../native-select";
|
|
15
|
+
import {
|
|
16
|
+
buildButtonConfiguratorTree,
|
|
17
|
+
createButtonConfiguratorButtonNode,
|
|
18
|
+
createButtonConfiguratorDropdownNode,
|
|
19
|
+
createButtonConfiguratorGroupNode,
|
|
20
|
+
flattenButtonConfiguratorTree,
|
|
21
|
+
getButtonConfiguratorNode,
|
|
22
|
+
insertButtonConfiguratorChildNode,
|
|
23
|
+
insertButtonConfiguratorRootNode,
|
|
24
|
+
materializeButtonConfiguratorTree,
|
|
25
|
+
moveButtonConfiguratorNodeToParent,
|
|
26
|
+
moveButtonConfiguratorSibling,
|
|
27
|
+
removeButtonConfiguratorSubtree,
|
|
28
|
+
updateButtonConfiguratorNode
|
|
29
|
+
} from "./menu";
|
|
30
|
+
defineOptions({
|
|
31
|
+
inheritAttrs: false
|
|
32
|
+
});
|
|
33
|
+
const props = defineProps({
|
|
34
|
+
config: { type: null, required: true }
|
|
35
|
+
});
|
|
36
|
+
const emit = defineEmits(["confirm"]);
|
|
37
|
+
const open = defineModel("open", { type: Boolean, ...{
|
|
38
|
+
default: false
|
|
39
|
+
} });
|
|
40
|
+
const { t } = useI18n();
|
|
41
|
+
const search = ref("");
|
|
42
|
+
const draftGap = ref(props.config.gap ?? 12);
|
|
43
|
+
const selectedItemId = ref("general");
|
|
44
|
+
const draftTree = ref(buildButtonConfiguratorTree(props.config.groups));
|
|
45
|
+
const sortableListRef = ref(null);
|
|
46
|
+
const sortableItemIds = ref([]);
|
|
47
|
+
const sortable = useSortable(sortableListRef, sortableItemIds);
|
|
48
|
+
function handleSortableUpdate(event) {
|
|
49
|
+
if (event.oldIndex === void 0 || event.newIndex === void 0 || event.oldIndex === event.newIndex) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
draftTree.value = moveButtonConfiguratorSibling(
|
|
53
|
+
draftTree.value,
|
|
54
|
+
selectedItemId.value === "general" ? void 0 : selectedItemId.value,
|
|
55
|
+
event.oldIndex,
|
|
56
|
+
event.newIndex
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
function configureSortable() {
|
|
60
|
+
sortable.option("handle", '[data-slot="button-configurator-drag-handle"]');
|
|
61
|
+
sortable.option("animation", 150);
|
|
62
|
+
sortable.option("onUpdate", handleSortableUpdate);
|
|
63
|
+
}
|
|
64
|
+
async function refreshSortable() {
|
|
65
|
+
sortable.stop();
|
|
66
|
+
if (!open.value || selectedContainerItemIds.value.length === 0) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
await nextTick();
|
|
70
|
+
sortable.start();
|
|
71
|
+
configureSortable();
|
|
72
|
+
}
|
|
73
|
+
const normalizedSearch = computed(() => search.value.trim().toLocaleLowerCase());
|
|
74
|
+
const generalItem = computed(() => ({
|
|
75
|
+
id: "general",
|
|
76
|
+
label: t("general")
|
|
77
|
+
}));
|
|
78
|
+
const selectedNode = computed(() => {
|
|
79
|
+
if (selectedItemId.value === "general") {
|
|
80
|
+
return void 0;
|
|
81
|
+
}
|
|
82
|
+
return getButtonConfiguratorNode(draftTree.value, selectedItemId.value);
|
|
83
|
+
});
|
|
84
|
+
const selectedGroup = computed(() => selectedNode.value?.item.type === "group" ? selectedNode.value.item : void 0);
|
|
85
|
+
const selectedButton = computed(() => selectedNode.value?.item.type === "button" ? selectedNode.value.item : void 0);
|
|
86
|
+
const selectedDropdown = computed(() => selectedNode.value?.item.type === "dropdown" ? selectedNode.value.item : void 0);
|
|
87
|
+
const selectedNodeItemId = computed(() => selectedNode.value?.itemId ?? "");
|
|
88
|
+
const selectedParentNodeId = computed(() => {
|
|
89
|
+
const parentItemId = selectedNode.value?.parentItemId;
|
|
90
|
+
if (!parentItemId) {
|
|
91
|
+
return "";
|
|
92
|
+
}
|
|
93
|
+
return getButtonConfiguratorNode(draftTree.value, parentItemId)?.item.id ?? "";
|
|
94
|
+
});
|
|
95
|
+
const selectedButtonIsInGroup = computed(() => {
|
|
96
|
+
const parentItemId = selectedNode.value?.parentItemId;
|
|
97
|
+
if (!parentItemId) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return getButtonConfiguratorNode(draftTree.value, parentItemId)?.item.type === "group";
|
|
101
|
+
});
|
|
102
|
+
const canAddGroup = computed(() => selectedItemId.value === "general");
|
|
103
|
+
const canAddGroupButton = computed(() => selectedNode.value?.item.type === "group");
|
|
104
|
+
const canAddGroupDropdown = computed(() => selectedNode.value?.item.type === "group");
|
|
105
|
+
const canAddDropdownChildButton = computed(() => selectedNode.value?.item.type === "dropdown");
|
|
106
|
+
const flattenedItems = computed(() => flattenButtonConfiguratorTree(draftTree.value).map((item) => ({
|
|
107
|
+
itemId: item.itemId,
|
|
108
|
+
depth: item.depth,
|
|
109
|
+
label: getNodeLabel(item.item),
|
|
110
|
+
type: item.item.type,
|
|
111
|
+
id: item.item.id
|
|
112
|
+
})));
|
|
113
|
+
const filteredItems = computed(() => {
|
|
114
|
+
if (!normalizedSearch.value) {
|
|
115
|
+
return flattenedItems.value;
|
|
116
|
+
}
|
|
117
|
+
return flattenedItems.value.filter((item) => {
|
|
118
|
+
const haystack = `${item.label} ${item.id}`.toLocaleLowerCase();
|
|
119
|
+
return haystack.includes(normalizedSearch.value);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
const selectedItemLabel = computed(() => {
|
|
123
|
+
if (!selectedNode.value) {
|
|
124
|
+
return generalItem.value.label;
|
|
125
|
+
}
|
|
126
|
+
return getNodeLabel(selectedNode.value.item);
|
|
127
|
+
});
|
|
128
|
+
const selectedContainerItemIds = computed(() => {
|
|
129
|
+
if (selectedItemId.value === "general") {
|
|
130
|
+
return draftTree.value.rootItemIds;
|
|
131
|
+
}
|
|
132
|
+
if (!selectedNode.value) {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
if (selectedNode.value.item.type === "button") {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
return selectedNode.value.childItemIds;
|
|
139
|
+
});
|
|
140
|
+
const childItemsTitle = computed(() => {
|
|
141
|
+
if (selectedItemId.value === "general") {
|
|
142
|
+
return t("groups");
|
|
143
|
+
}
|
|
144
|
+
if (selectedGroup.value) {
|
|
145
|
+
return t("group-items");
|
|
146
|
+
}
|
|
147
|
+
return t("children");
|
|
148
|
+
});
|
|
149
|
+
const childItems = computed(() => selectedContainerItemIds.value.flatMap((itemId) => {
|
|
150
|
+
const node = getButtonConfiguratorNode(draftTree.value, itemId);
|
|
151
|
+
if (!node) {
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
return [{
|
|
155
|
+
itemId: node.itemId,
|
|
156
|
+
label: getNodeLabel(node.item),
|
|
157
|
+
type: node.item.type,
|
|
158
|
+
id: node.item.id
|
|
159
|
+
}];
|
|
160
|
+
}));
|
|
161
|
+
const buttonParentOptions = computed(() => draftTree.value.nodes.flatMap((node) => {
|
|
162
|
+
if (node.item.type === "group") {
|
|
163
|
+
return [{
|
|
164
|
+
id: node.item.id,
|
|
165
|
+
itemId: node.itemId,
|
|
166
|
+
label: getNodeLabel(node.item),
|
|
167
|
+
type: "group"
|
|
168
|
+
}];
|
|
169
|
+
}
|
|
170
|
+
if (node.item.type === "dropdown") {
|
|
171
|
+
return [{
|
|
172
|
+
id: node.item.id,
|
|
173
|
+
itemId: node.itemId,
|
|
174
|
+
label: getNodeLabel(node.item),
|
|
175
|
+
type: "dropdown"
|
|
176
|
+
}];
|
|
177
|
+
}
|
|
178
|
+
return [];
|
|
179
|
+
}));
|
|
180
|
+
const dropdownParentOptions = computed(() => draftTree.value.nodes.flatMap((node) => node.item.type === "group" ? [{
|
|
181
|
+
id: node.item.id,
|
|
182
|
+
itemId: node.itemId,
|
|
183
|
+
label: getNodeLabel(node.item)
|
|
184
|
+
}] : []));
|
|
185
|
+
watch(() => props.config, (config) => {
|
|
186
|
+
applyDraftConfig(config);
|
|
187
|
+
}, { immediate: true });
|
|
188
|
+
watch([selectedContainerItemIds, selectedItemId], () => {
|
|
189
|
+
sortableItemIds.value = selectedContainerItemIds.value.slice();
|
|
190
|
+
sortable.option("disabled", selectedContainerItemIds.value.length === 0);
|
|
191
|
+
});
|
|
192
|
+
watch([open, selectedItemId, selectedContainerItemIds], async () => {
|
|
193
|
+
await refreshSortable();
|
|
194
|
+
}, { immediate: true });
|
|
195
|
+
watch(filteredItems, (items) => {
|
|
196
|
+
if (selectedItemId.value === "general") {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (items.some((item) => item.itemId === selectedItemId.value)) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
selectedItemId.value = items[0]?.itemId ?? "general";
|
|
203
|
+
}, { immediate: true });
|
|
204
|
+
function getZhText(value) {
|
|
205
|
+
if (!value) {
|
|
206
|
+
return void 0;
|
|
207
|
+
}
|
|
208
|
+
const zhValue = value.find((item) => item.locale === "zh");
|
|
209
|
+
if (!zhValue) {
|
|
210
|
+
return void 0;
|
|
211
|
+
}
|
|
212
|
+
const message = zhValue.message.trim();
|
|
213
|
+
return message.length > 0 ? message : void 0;
|
|
214
|
+
}
|
|
215
|
+
function isCopyableNode(node) {
|
|
216
|
+
if (!node) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
return node.item.type === "button" || node.item.type === "dropdown";
|
|
220
|
+
}
|
|
221
|
+
function getNodeLabel(item) {
|
|
222
|
+
if (item.type === "group") {
|
|
223
|
+
return t("group-label");
|
|
224
|
+
}
|
|
225
|
+
return getZhText(item.title) ?? t(item.type === "button" ? "untitled-button" : "untitled-dropdown");
|
|
226
|
+
}
|
|
227
|
+
function applyDraftConfig(config) {
|
|
228
|
+
draftGap.value = config.gap ?? 12;
|
|
229
|
+
draftTree.value = buildButtonConfiguratorTree(config.groups);
|
|
230
|
+
selectedItemId.value = "general";
|
|
231
|
+
sortableItemIds.value = draftTree.value.rootItemIds.slice();
|
|
232
|
+
}
|
|
233
|
+
function selectGeneral() {
|
|
234
|
+
selectedItemId.value = "general";
|
|
235
|
+
}
|
|
236
|
+
function selectItem(itemId) {
|
|
237
|
+
selectedItemId.value = itemId;
|
|
238
|
+
}
|
|
239
|
+
function addGroup() {
|
|
240
|
+
const node = createButtonConfiguratorGroupNode();
|
|
241
|
+
draftTree.value = insertButtonConfiguratorRootNode(draftTree.value, node);
|
|
242
|
+
selectedItemId.value = node.itemId;
|
|
243
|
+
}
|
|
244
|
+
function addButton() {
|
|
245
|
+
const node = createButtonConfiguratorButtonNode();
|
|
246
|
+
if (selectedNode.value?.item.type === "group" || selectedNode.value?.item.type === "dropdown") {
|
|
247
|
+
draftTree.value = insertButtonConfiguratorChildNode(draftTree.value, selectedNode.value.itemId, node);
|
|
248
|
+
selectedItemId.value = node.itemId;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function addDropdown() {
|
|
252
|
+
const node = createButtonConfiguratorDropdownNode();
|
|
253
|
+
if (selectedNode.value?.item.type === "group") {
|
|
254
|
+
draftTree.value = insertButtonConfiguratorChildNode(draftTree.value, selectedNode.value.itemId, node);
|
|
255
|
+
selectedItemId.value = node.itemId;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function deleteItem(itemId) {
|
|
259
|
+
draftTree.value = removeButtonConfiguratorSubtree(draftTree.value, itemId);
|
|
260
|
+
if (selectedItemId.value === itemId) {
|
|
261
|
+
selectedItemId.value = "general";
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function updateGap(value) {
|
|
265
|
+
const parsed = Number(value);
|
|
266
|
+
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
267
|
+
draftGap.value = parsed;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function updateSelectedTitle(value) {
|
|
271
|
+
const node = selectedNode.value;
|
|
272
|
+
if (!node) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
draftTree.value = updateButtonConfiguratorNode(draftTree.value, node.itemId, (item) => {
|
|
276
|
+
if (item.type === "group") {
|
|
277
|
+
return item;
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
...item,
|
|
281
|
+
title: value
|
|
282
|
+
};
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
function updateSelectedIcon(value) {
|
|
286
|
+
const node = selectedNode.value;
|
|
287
|
+
if (!node) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
draftTree.value = updateButtonConfiguratorNode(draftTree.value, node.itemId, (item) => {
|
|
291
|
+
if (item.type === "group") {
|
|
292
|
+
return item;
|
|
293
|
+
}
|
|
294
|
+
if (item.type === "button") {
|
|
295
|
+
const nextItem2 = {
|
|
296
|
+
type: "button",
|
|
297
|
+
id: item.id,
|
|
298
|
+
title: item.title
|
|
299
|
+
};
|
|
300
|
+
if (item.variant) {
|
|
301
|
+
nextItem2.variant = item.variant;
|
|
302
|
+
}
|
|
303
|
+
if (item.hideTitle) {
|
|
304
|
+
nextItem2.hideTitle = item.hideTitle;
|
|
305
|
+
}
|
|
306
|
+
if (value) {
|
|
307
|
+
nextItem2.icon = value;
|
|
308
|
+
}
|
|
309
|
+
return nextItem2;
|
|
310
|
+
}
|
|
311
|
+
const nextItem = {
|
|
312
|
+
type: "dropdown",
|
|
313
|
+
id: item.id,
|
|
314
|
+
title: item.title
|
|
315
|
+
};
|
|
316
|
+
if (value) {
|
|
317
|
+
nextItem.icon = value;
|
|
318
|
+
}
|
|
319
|
+
return nextItem;
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
function updateSelectedVariant(value) {
|
|
323
|
+
const node = selectedNode.value;
|
|
324
|
+
if (!node || node.item.type !== "button" || typeof value !== "string") {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
draftTree.value = updateButtonConfiguratorNode(draftTree.value, node.itemId, (item) => {
|
|
328
|
+
if (item.type !== "button") {
|
|
329
|
+
return item;
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
...item,
|
|
333
|
+
variant: value === "default" || value === "primary" || value === "destructive" || value === "ghost" ? value : void 0
|
|
334
|
+
};
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
function updateSelectedHideTitle(value) {
|
|
338
|
+
const node = selectedNode.value;
|
|
339
|
+
if (!node || node.item.type !== "button" || !selectedButtonIsInGroup.value || typeof value !== "boolean") {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
draftTree.value = updateButtonConfiguratorNode(draftTree.value, node.itemId, (item) => {
|
|
343
|
+
if (item.type !== "button") {
|
|
344
|
+
return item;
|
|
345
|
+
}
|
|
346
|
+
if (!value) {
|
|
347
|
+
return {
|
|
348
|
+
type: "button",
|
|
349
|
+
id: item.id,
|
|
350
|
+
title: item.title,
|
|
351
|
+
icon: item.icon,
|
|
352
|
+
variant: item.variant
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
...item,
|
|
357
|
+
hideTitle: true
|
|
358
|
+
};
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
function moveSelectedButtonParent(value) {
|
|
362
|
+
const node = selectedNode.value;
|
|
363
|
+
if (!node || node.item.type !== "button" || typeof value !== "string") {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const targetParent = buttonParentOptions.value.find((option) => option.id === value);
|
|
367
|
+
if (!targetParent) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
draftTree.value = moveButtonConfiguratorNodeToParent(draftTree.value, node.itemId, targetParent.itemId);
|
|
371
|
+
}
|
|
372
|
+
function moveSelectedDropdownParent(value) {
|
|
373
|
+
const node = selectedNode.value;
|
|
374
|
+
if (!node || node.item.type !== "dropdown" || typeof value !== "string") {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
const targetParent = dropdownParentOptions.value.find((option) => option.id === value);
|
|
378
|
+
if (!targetParent) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
draftTree.value = moveButtonConfiguratorNodeToParent(draftTree.value, node.itemId, targetParent.itemId);
|
|
382
|
+
}
|
|
383
|
+
function handleSelectedVariantUpdate(value) {
|
|
384
|
+
if (typeof value === "string") {
|
|
385
|
+
updateSelectedVariant(value);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
function handleSelectedButtonParentUpdate(value) {
|
|
389
|
+
if (typeof value === "string") {
|
|
390
|
+
moveSelectedButtonParent(value);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function handleSelectedDropdownParentUpdate(value) {
|
|
394
|
+
if (typeof value === "string") {
|
|
395
|
+
moveSelectedDropdownParent(value);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
async function copySelectedId() {
|
|
399
|
+
const node = selectedNode.value;
|
|
400
|
+
if (!node || !isCopyableNode(node)) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
try {
|
|
404
|
+
await navigator.clipboard.writeText(node.item.id);
|
|
405
|
+
} catch {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function confirmChanges() {
|
|
410
|
+
const result = ButtonConfigC.safeParse({
|
|
411
|
+
gap: draftGap.value,
|
|
412
|
+
groups: materializeButtonConfiguratorTree(draftTree.value)
|
|
413
|
+
});
|
|
414
|
+
if (!result.success) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
emit("confirm", result.data);
|
|
418
|
+
open.value = false;
|
|
419
|
+
}
|
|
420
|
+
</script>
|
|
421
|
+
|
|
422
|
+
<template>
|
|
423
|
+
<Dialog
|
|
424
|
+
:open="open"
|
|
425
|
+
@update:open="open = $event"
|
|
426
|
+
>
|
|
427
|
+
<DialogContent class="flex h-[min(40rem,calc(100vh-4rem))] w-[calc(100%-2rem)] max-w-[calc(100%-2rem)] flex-col overflow-hidden p-0 sm:w-[72rem] sm:max-w-[72rem]">
|
|
428
|
+
<DialogHeader class="gap-1 border-b border-zinc-200 px-6 py-5">
|
|
429
|
+
<DialogTitle class="text-xl font-semibold text-zinc-800">
|
|
430
|
+
{{ t("configure-buttons") }}
|
|
431
|
+
</DialogTitle>
|
|
432
|
+
<DialogDescription class="text-sm text-zinc-500">
|
|
433
|
+
{{ t("configure-buttons-description") }}
|
|
434
|
+
</DialogDescription>
|
|
435
|
+
</DialogHeader>
|
|
436
|
+
|
|
437
|
+
<div class="grid min-h-0 flex-1 grid-cols-[18rem_minmax(0,1fr)]">
|
|
438
|
+
<section class="flex min-h-0 flex-col border-r border-zinc-200 px-4 py-4">
|
|
439
|
+
<Input
|
|
440
|
+
v-model="search"
|
|
441
|
+
data-slot="button-configurator-search"
|
|
442
|
+
:placeholder="t('search')"
|
|
443
|
+
/>
|
|
444
|
+
|
|
445
|
+
<div class="mt-4 flex min-h-0 flex-1 flex-col overflow-hidden">
|
|
446
|
+
<div class="flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto pr-1">
|
|
447
|
+
<button
|
|
448
|
+
type="button"
|
|
449
|
+
data-slot="button-configurator-item"
|
|
450
|
+
data-item-id="general"
|
|
451
|
+
:data-selected="selectedItemId === 'general' ? 'true' : 'false'"
|
|
452
|
+
:class="cn(
|
|
453
|
+
'flex w-full items-center rounded-md border p-1 text-left transition-colors',
|
|
454
|
+
selectedItemId === 'general' ? 'border-(--primary)/25 bg-[color-mix(in_srgb,var(--primary)_10%,white)]' : 'border-transparent hover:border-zinc-200 hover:bg-zinc-50'
|
|
455
|
+
)"
|
|
456
|
+
@click="selectGeneral"
|
|
457
|
+
>
|
|
458
|
+
<span class="truncate px-2 py-2 text-sm font-medium text-zinc-800">
|
|
459
|
+
{{ generalItem.label }}
|
|
460
|
+
</span>
|
|
461
|
+
</button>
|
|
462
|
+
|
|
463
|
+
<div
|
|
464
|
+
v-for="item in filteredItems"
|
|
465
|
+
:key="item.itemId"
|
|
466
|
+
data-slot="button-configurator-item"
|
|
467
|
+
:data-item-id="item.itemId"
|
|
468
|
+
:data-node-id="item.id"
|
|
469
|
+
:data-selected="selectedItemId === item.itemId ? 'true' : 'false'"
|
|
470
|
+
:class="cn(
|
|
471
|
+
'flex w-full items-center gap-2 rounded-md border p-1 text-left transition-colors',
|
|
472
|
+
selectedItemId === item.itemId ? 'border-(--primary)/25 bg-[color-mix(in_srgb,var(--primary)_10%,white)]' : 'border-transparent hover:border-zinc-200 hover:bg-zinc-50'
|
|
473
|
+
)"
|
|
474
|
+
:style="{ paddingInlineStart: `${item.depth * 14 + 8}px` }"
|
|
475
|
+
>
|
|
476
|
+
<button
|
|
477
|
+
type="button"
|
|
478
|
+
data-slot="button-configurator-item-select"
|
|
479
|
+
class="min-w-0 flex-1 text-left"
|
|
480
|
+
@click="selectItem(item.itemId)"
|
|
481
|
+
>
|
|
482
|
+
<span
|
|
483
|
+
data-slot="button-configurator-item-label"
|
|
484
|
+
class="block truncate px-2 py-2 text-sm font-medium text-zinc-800"
|
|
485
|
+
>
|
|
486
|
+
{{ item.label }}
|
|
487
|
+
</span>
|
|
488
|
+
</button>
|
|
489
|
+
|
|
490
|
+
<button
|
|
491
|
+
type="button"
|
|
492
|
+
data-slot="button-configurator-item-delete"
|
|
493
|
+
class="flex size-8 shrink-0 items-center justify-center rounded-sm text-zinc-400 transition-colors hover:bg-red-50 hover:text-red-600"
|
|
494
|
+
@click.stop="deleteItem(item.itemId)"
|
|
495
|
+
>
|
|
496
|
+
<Icon icon="fluent:delete-20-regular" />
|
|
497
|
+
</button>
|
|
498
|
+
</div>
|
|
499
|
+
|
|
500
|
+
<p
|
|
501
|
+
v-if="filteredItems.length === 0 && normalizedSearch"
|
|
502
|
+
data-slot="button-configurator-empty"
|
|
503
|
+
class="px-2 pt-2 text-xs text-zinc-400"
|
|
504
|
+
>
|
|
505
|
+
{{ t("no-matches") }}
|
|
506
|
+
</p>
|
|
507
|
+
</div>
|
|
508
|
+
</div>
|
|
509
|
+
</section>
|
|
510
|
+
|
|
511
|
+
<section class="flex min-h-0 flex-col overflow-y-auto px-6 py-6">
|
|
512
|
+
<div class="flex items-center gap-2">
|
|
513
|
+
<h3
|
|
514
|
+
data-slot="button-configurator-detail-title"
|
|
515
|
+
class="text-lg font-semibold text-zinc-800"
|
|
516
|
+
>
|
|
517
|
+
{{ selectedItemLabel }}
|
|
518
|
+
</h3>
|
|
519
|
+
<Button
|
|
520
|
+
v-if="isCopyableNode(selectedNode)"
|
|
521
|
+
type="button"
|
|
522
|
+
variant="ghost"
|
|
523
|
+
size="sm"
|
|
524
|
+
data-slot="button-configurator-copy-id"
|
|
525
|
+
class="size-7 p-0 text-zinc-400 hover:text-zinc-700"
|
|
526
|
+
:title="selectedNode?.item.id"
|
|
527
|
+
@click="void copySelectedId()"
|
|
528
|
+
>
|
|
529
|
+
<Icon icon="fluent:copy-20-regular" />
|
|
530
|
+
</Button>
|
|
531
|
+
</div>
|
|
532
|
+
|
|
533
|
+
<p class="mt-2 text-sm text-zinc-500">
|
|
534
|
+
{{ selectedItemId === "general" ? t("general-description") : t("detail-description") }}
|
|
535
|
+
</p>
|
|
536
|
+
|
|
537
|
+
<div class="mt-6 flex flex-wrap gap-2">
|
|
538
|
+
<Button
|
|
539
|
+
v-if="canAddGroup"
|
|
540
|
+
type="button"
|
|
541
|
+
data-slot="button-configurator-add-group"
|
|
542
|
+
@click="addGroup"
|
|
543
|
+
>
|
|
544
|
+
<Icon icon="fluent:add-20-regular" />
|
|
545
|
+
{{ t("add-group") }}
|
|
546
|
+
</Button>
|
|
547
|
+
|
|
548
|
+
<Button
|
|
549
|
+
v-if="canAddGroupButton || canAddDropdownChildButton"
|
|
550
|
+
type="button"
|
|
551
|
+
data-slot="button-configurator-add-button"
|
|
552
|
+
@click="addButton"
|
|
553
|
+
>
|
|
554
|
+
<Icon icon="fluent:add-20-regular" />
|
|
555
|
+
{{ t("add-button") }}
|
|
556
|
+
</Button>
|
|
557
|
+
|
|
558
|
+
<Button
|
|
559
|
+
v-if="canAddGroupDropdown"
|
|
560
|
+
type="button"
|
|
561
|
+
data-slot="button-configurator-add-dropdown"
|
|
562
|
+
@click="addDropdown"
|
|
563
|
+
>
|
|
564
|
+
<Icon icon="fluent:add-20-regular" />
|
|
565
|
+
{{ t("add-dropdown") }}
|
|
566
|
+
</Button>
|
|
567
|
+
</div>
|
|
568
|
+
|
|
569
|
+
<section
|
|
570
|
+
v-if="selectedItemId === 'general'"
|
|
571
|
+
data-slot="button-configurator-general"
|
|
572
|
+
class="mt-6 grid gap-4"
|
|
573
|
+
>
|
|
574
|
+
<label class="flex flex-col gap-2">
|
|
575
|
+
<span class="text-xs font-medium text-zinc-500">{{ t("group-gap") }}</span>
|
|
576
|
+
<Input
|
|
577
|
+
data-slot="button-configurator-gap"
|
|
578
|
+
type="number"
|
|
579
|
+
min="0"
|
|
580
|
+
:model-value="`${draftGap}`"
|
|
581
|
+
@update:model-value="updateGap"
|
|
582
|
+
/>
|
|
583
|
+
</label>
|
|
584
|
+
</section>
|
|
585
|
+
|
|
586
|
+
<section
|
|
587
|
+
v-else-if="selectedGroup"
|
|
588
|
+
data-slot="button-configurator-group"
|
|
589
|
+
class="mt-6 grid gap-4"
|
|
590
|
+
>
|
|
591
|
+
<Button
|
|
592
|
+
type="button"
|
|
593
|
+
variant="ghost"
|
|
594
|
+
data-slot="button-configurator-delete-selected"
|
|
595
|
+
class="justify-start text-red-600 hover:bg-red-50 hover:text-red-700"
|
|
596
|
+
@click="deleteItem(selectedNodeItemId)"
|
|
597
|
+
>
|
|
598
|
+
<Icon icon="fluent:delete-20-regular" />
|
|
599
|
+
{{ t("delete-group") }}
|
|
600
|
+
</Button>
|
|
601
|
+
</section>
|
|
602
|
+
|
|
603
|
+
<section
|
|
604
|
+
v-else-if="selectedButton"
|
|
605
|
+
data-slot="button-configurator-button"
|
|
606
|
+
class="mt-6 grid gap-4"
|
|
607
|
+
>
|
|
608
|
+
<label class="flex flex-col gap-2">
|
|
609
|
+
<span class="text-xs font-medium text-zinc-500">{{ t("button-title") }}</span>
|
|
610
|
+
<Locale
|
|
611
|
+
data-slot="button-configurator-button-title"
|
|
612
|
+
:model-value="selectedButton.title"
|
|
613
|
+
@update:model-value="updateSelectedTitle"
|
|
614
|
+
/>
|
|
615
|
+
</label>
|
|
616
|
+
|
|
617
|
+
<label class="flex flex-col gap-2">
|
|
618
|
+
<span class="text-xs font-medium text-zinc-500">{{ t("button-icon") }}</span>
|
|
619
|
+
<IconPicker
|
|
620
|
+
data-slot="button-configurator-button-icon"
|
|
621
|
+
:model-value="selectedButton.icon"
|
|
622
|
+
@update:model-value="updateSelectedIcon"
|
|
623
|
+
/>
|
|
624
|
+
</label>
|
|
625
|
+
|
|
626
|
+
<label class="flex flex-col gap-2">
|
|
627
|
+
<span class="text-xs font-medium text-zinc-500">{{ t("button-variant") }}</span>
|
|
628
|
+
<NativeSelect
|
|
629
|
+
data-slot="button-configurator-button-variant"
|
|
630
|
+
:model-value="selectedButton.variant ?? ''"
|
|
631
|
+
@update:model-value="handleSelectedVariantUpdate"
|
|
632
|
+
>
|
|
633
|
+
<NativeSelectOption value="">
|
|
634
|
+
{{ t("button-variant-default") }}
|
|
635
|
+
</NativeSelectOption>
|
|
636
|
+
<NativeSelectOption value="default">
|
|
637
|
+
{{ t("button-variant-default-option") }}
|
|
638
|
+
</NativeSelectOption>
|
|
639
|
+
<NativeSelectOption value="primary">
|
|
640
|
+
{{ t("button-variant-primary") }}
|
|
641
|
+
</NativeSelectOption>
|
|
642
|
+
<NativeSelectOption value="destructive">
|
|
643
|
+
{{ t("button-variant-destructive") }}
|
|
644
|
+
</NativeSelectOption>
|
|
645
|
+
<NativeSelectOption value="ghost">
|
|
646
|
+
{{ t("button-variant-ghost") }}
|
|
647
|
+
</NativeSelectOption>
|
|
648
|
+
</NativeSelect>
|
|
649
|
+
</label>
|
|
650
|
+
|
|
651
|
+
<label class="flex flex-col gap-2">
|
|
652
|
+
<span class="text-xs font-medium text-zinc-500">{{ t("button-parent") }}</span>
|
|
653
|
+
<NativeSelect
|
|
654
|
+
data-slot="button-configurator-button-parent"
|
|
655
|
+
:model-value="selectedParentNodeId"
|
|
656
|
+
@update:model-value="handleSelectedButtonParentUpdate"
|
|
657
|
+
>
|
|
658
|
+
<NativeSelectOption
|
|
659
|
+
v-for="option in buttonParentOptions"
|
|
660
|
+
:key="option.itemId"
|
|
661
|
+
:value="option.id"
|
|
662
|
+
>
|
|
663
|
+
{{ option.type === "group" ? `${t("group-label")} \xB7 ${option.label}` : `${t("dropdown-label")} \xB7 ${option.label}` }}
|
|
664
|
+
</NativeSelectOption>
|
|
665
|
+
</NativeSelect>
|
|
666
|
+
</label>
|
|
667
|
+
|
|
668
|
+
<label
|
|
669
|
+
v-if="selectedButtonIsInGroup"
|
|
670
|
+
class="flex items-center gap-3 rounded-md border border-zinc-200 px-3 py-2"
|
|
671
|
+
>
|
|
672
|
+
<Checkbox
|
|
673
|
+
data-slot="button-configurator-button-hide-title"
|
|
674
|
+
:model-value="selectedButton.hideTitle ?? false"
|
|
675
|
+
@update:model-value="updateSelectedHideTitle"
|
|
676
|
+
/>
|
|
677
|
+
<span class="text-sm text-zinc-700">{{ t("button-hide-title") }}</span>
|
|
678
|
+
</label>
|
|
679
|
+
|
|
680
|
+
<Button
|
|
681
|
+
type="button"
|
|
682
|
+
variant="ghost"
|
|
683
|
+
data-slot="button-configurator-delete-selected"
|
|
684
|
+
class="justify-start text-red-600 hover:bg-red-50 hover:text-red-700"
|
|
685
|
+
@click="deleteItem(selectedNodeItemId)"
|
|
686
|
+
>
|
|
687
|
+
<Icon icon="fluent:delete-20-regular" />
|
|
688
|
+
{{ t("delete-button") }}
|
|
689
|
+
</Button>
|
|
690
|
+
</section>
|
|
691
|
+
|
|
692
|
+
<section
|
|
693
|
+
v-else-if="selectedDropdown"
|
|
694
|
+
data-slot="button-configurator-dropdown"
|
|
695
|
+
class="mt-6 grid gap-4"
|
|
696
|
+
>
|
|
697
|
+
<label class="flex flex-col gap-2">
|
|
698
|
+
<span class="text-xs font-medium text-zinc-500">{{ t("dropdown-title") }}</span>
|
|
699
|
+
<Locale
|
|
700
|
+
data-slot="button-configurator-dropdown-title"
|
|
701
|
+
:model-value="selectedDropdown.title"
|
|
702
|
+
@update:model-value="updateSelectedTitle"
|
|
703
|
+
/>
|
|
704
|
+
</label>
|
|
705
|
+
|
|
706
|
+
<label class="flex flex-col gap-2">
|
|
707
|
+
<span class="text-xs font-medium text-zinc-500">{{ t("dropdown-icon") }}</span>
|
|
708
|
+
<IconPicker
|
|
709
|
+
data-slot="button-configurator-dropdown-icon"
|
|
710
|
+
:model-value="selectedDropdown.icon"
|
|
711
|
+
@update:model-value="updateSelectedIcon"
|
|
712
|
+
/>
|
|
713
|
+
</label>
|
|
714
|
+
|
|
715
|
+
<label class="flex flex-col gap-2">
|
|
716
|
+
<span class="text-xs font-medium text-zinc-500">{{ t("dropdown-parent") }}</span>
|
|
717
|
+
<NativeSelect
|
|
718
|
+
data-slot="button-configurator-dropdown-parent"
|
|
719
|
+
:model-value="selectedParentNodeId"
|
|
720
|
+
@update:model-value="handleSelectedDropdownParentUpdate"
|
|
721
|
+
>
|
|
722
|
+
<NativeSelectOption
|
|
723
|
+
v-for="option in dropdownParentOptions"
|
|
724
|
+
:key="option.itemId"
|
|
725
|
+
:value="option.id"
|
|
726
|
+
>
|
|
727
|
+
{{ `${t("group-label")} \xB7 ${option.label}` }}
|
|
728
|
+
</NativeSelectOption>
|
|
729
|
+
</NativeSelect>
|
|
730
|
+
</label>
|
|
731
|
+
|
|
732
|
+
<Button
|
|
733
|
+
type="button"
|
|
734
|
+
variant="ghost"
|
|
735
|
+
data-slot="button-configurator-delete-selected"
|
|
736
|
+
class="justify-start text-red-600 hover:bg-red-50 hover:text-red-700"
|
|
737
|
+
@click="deleteItem(selectedNodeItemId)"
|
|
738
|
+
>
|
|
739
|
+
<Icon icon="fluent:delete-20-regular" />
|
|
740
|
+
{{ t("delete-dropdown") }}
|
|
741
|
+
</Button>
|
|
742
|
+
</section>
|
|
743
|
+
|
|
744
|
+
<section
|
|
745
|
+
v-if="childItems.length > 0"
|
|
746
|
+
class="mt-6 flex min-h-0 flex-1 flex-col"
|
|
747
|
+
>
|
|
748
|
+
<div class="mb-2 flex items-center justify-between">
|
|
749
|
+
<span class="text-xs font-medium text-zinc-500">{{ childItemsTitle }}</span>
|
|
750
|
+
</div>
|
|
751
|
+
|
|
752
|
+
<div
|
|
753
|
+
ref="sortableListRef"
|
|
754
|
+
data-slot="button-configurator-child-list"
|
|
755
|
+
class="flex flex-col gap-1"
|
|
756
|
+
>
|
|
757
|
+
<div
|
|
758
|
+
v-for="item in childItems"
|
|
759
|
+
:key="item.itemId"
|
|
760
|
+
data-slot="button-configurator-child-item"
|
|
761
|
+
:data-item-id="item.itemId"
|
|
762
|
+
:data-node-id="item.id"
|
|
763
|
+
class="flex items-center gap-2 rounded-md border border-zinc-200 p-1"
|
|
764
|
+
>
|
|
765
|
+
<button
|
|
766
|
+
type="button"
|
|
767
|
+
data-slot="button-configurator-drag-handle"
|
|
768
|
+
class="flex size-8 shrink-0 cursor-grab items-center justify-center rounded-sm text-zinc-400 active:cursor-grabbing"
|
|
769
|
+
>
|
|
770
|
+
<Icon icon="fluent:re-order-dots-vertical-20-regular" />
|
|
771
|
+
</button>
|
|
772
|
+
|
|
773
|
+
<button
|
|
774
|
+
type="button"
|
|
775
|
+
data-slot="button-configurator-child-select"
|
|
776
|
+
class="min-w-0 flex-1 px-2 py-2 text-left"
|
|
777
|
+
@click="selectItem(item.itemId)"
|
|
778
|
+
>
|
|
779
|
+
<span class="block truncate text-sm font-medium text-zinc-800">
|
|
780
|
+
{{ item.label }}
|
|
781
|
+
</span>
|
|
782
|
+
</button>
|
|
783
|
+
|
|
784
|
+
<button
|
|
785
|
+
type="button"
|
|
786
|
+
data-slot="button-configurator-child-delete"
|
|
787
|
+
class="flex size-8 shrink-0 items-center justify-center rounded-sm text-zinc-400 transition-colors hover:bg-red-50 hover:text-red-600"
|
|
788
|
+
@click="deleteItem(item.itemId)"
|
|
789
|
+
>
|
|
790
|
+
<Icon icon="fluent:delete-20-regular" />
|
|
791
|
+
</button>
|
|
792
|
+
</div>
|
|
793
|
+
</div>
|
|
794
|
+
</section>
|
|
795
|
+
</section>
|
|
796
|
+
</div>
|
|
797
|
+
|
|
798
|
+
<DialogFooter class="border-t border-zinc-200 px-6 py-4">
|
|
799
|
+
<Button
|
|
800
|
+
type="button"
|
|
801
|
+
variant="default"
|
|
802
|
+
data-slot="button-configurator-cancel"
|
|
803
|
+
@click="open = false"
|
|
804
|
+
>
|
|
805
|
+
<Icon icon="fluent:dismiss-20-regular" />
|
|
806
|
+
{{ t("cancel") }}
|
|
807
|
+
</Button>
|
|
808
|
+
<Button
|
|
809
|
+
type="button"
|
|
810
|
+
variant="primary"
|
|
811
|
+
data-slot="button-configurator-confirm"
|
|
812
|
+
@click="confirmChanges"
|
|
813
|
+
>
|
|
814
|
+
<Icon icon="fluent:checkmark-20-regular" />
|
|
815
|
+
{{ t("confirm") }}
|
|
816
|
+
</Button>
|
|
817
|
+
</DialogFooter>
|
|
818
|
+
</DialogContent>
|
|
819
|
+
</Dialog>
|
|
820
|
+
</template>
|
|
821
|
+
|
|
822
|
+
<i18n lang="json">
|
|
823
|
+
{
|
|
824
|
+
"zh": {
|
|
825
|
+
"configure-buttons": "配置按钮",
|
|
826
|
+
"configure-buttons-description": "管理多个按钮组、组间距和下拉按钮结构。",
|
|
827
|
+
"general": "总览",
|
|
828
|
+
"general-description": "在这里管理按钮组和按钮组之间的间距。",
|
|
829
|
+
"detail-description": "编辑当前选中节点,或调整它的子项顺序。",
|
|
830
|
+
"search": "搜索按钮",
|
|
831
|
+
"no-matches": "没有匹配的按钮。",
|
|
832
|
+
"group-label": "按钮组",
|
|
833
|
+
"groups": "按钮组",
|
|
834
|
+
"group-items": "组内按钮",
|
|
835
|
+
"dropdown-label": "下拉按钮",
|
|
836
|
+
"untitled-button": "未命名按钮",
|
|
837
|
+
"untitled-dropdown": "未命名下拉按钮",
|
|
838
|
+
"add-group": "新增按钮组",
|
|
839
|
+
"add-button": "新增按钮",
|
|
840
|
+
"add-dropdown": "新增下拉按钮",
|
|
841
|
+
"group-gap": "按钮组间距",
|
|
842
|
+
"button-title": "按钮名称",
|
|
843
|
+
"button-icon": "按钮图标",
|
|
844
|
+
"button-variant": "按钮变体",
|
|
845
|
+
"button-variant-default": "默认",
|
|
846
|
+
"button-variant-default-option": "默认按钮",
|
|
847
|
+
"button-variant-primary": "主按钮",
|
|
848
|
+
"button-variant-destructive": "危险按钮",
|
|
849
|
+
"button-variant-ghost": "幽灵按钮",
|
|
850
|
+
"button-parent": "所属容器",
|
|
851
|
+
"button-hide-title": "隐藏文字,仅显示图标",
|
|
852
|
+
"dropdown-title": "下拉名称",
|
|
853
|
+
"dropdown-icon": "下拉图标",
|
|
854
|
+
"dropdown-parent": "所属按钮组",
|
|
855
|
+
"children": "子项",
|
|
856
|
+
"delete-group": "删除按钮组",
|
|
857
|
+
"delete-button": "删除按钮",
|
|
858
|
+
"delete-dropdown": "删除下拉按钮",
|
|
859
|
+
"cancel": "取消",
|
|
860
|
+
"confirm": "确认"
|
|
861
|
+
},
|
|
862
|
+
"en": {
|
|
863
|
+
"configure-buttons": "Configure buttons",
|
|
864
|
+
"configure-buttons-description": "Manage button groups, group gaps, and dropdown structure.",
|
|
865
|
+
"general": "General",
|
|
866
|
+
"general-description": "Manage button groups and the gap between them.",
|
|
867
|
+
"detail-description": "Edit the selected node and reorder its children.",
|
|
868
|
+
"search": "Search buttons",
|
|
869
|
+
"no-matches": "No matching buttons.",
|
|
870
|
+
"group-label": "Group",
|
|
871
|
+
"groups": "Groups",
|
|
872
|
+
"group-items": "Group items",
|
|
873
|
+
"dropdown-label": "Dropdown",
|
|
874
|
+
"untitled-button": "Untitled button",
|
|
875
|
+
"untitled-dropdown": "Untitled dropdown",
|
|
876
|
+
"add-group": "Add group",
|
|
877
|
+
"add-button": "Add button",
|
|
878
|
+
"add-dropdown": "Add dropdown",
|
|
879
|
+
"group-gap": "Group gap",
|
|
880
|
+
"button-title": "Button title",
|
|
881
|
+
"button-icon": "Button icon",
|
|
882
|
+
"button-variant": "Button variant",
|
|
883
|
+
"button-variant-default": "Default",
|
|
884
|
+
"button-variant-default-option": "Default",
|
|
885
|
+
"button-variant-primary": "Primary",
|
|
886
|
+
"button-variant-destructive": "Destructive",
|
|
887
|
+
"button-variant-ghost": "Ghost",
|
|
888
|
+
"button-parent": "Parent container",
|
|
889
|
+
"button-hide-title": "Hide text and show icon only",
|
|
890
|
+
"dropdown-title": "Dropdown title",
|
|
891
|
+
"dropdown-icon": "Dropdown icon",
|
|
892
|
+
"dropdown-parent": "Parent group",
|
|
893
|
+
"children": "Children",
|
|
894
|
+
"delete-group": "Delete group",
|
|
895
|
+
"delete-button": "Delete button",
|
|
896
|
+
"delete-dropdown": "Delete dropdown",
|
|
897
|
+
"cancel": "Cancel",
|
|
898
|
+
"confirm": "Confirm"
|
|
899
|
+
},
|
|
900
|
+
"ja": {
|
|
901
|
+
"configure-buttons": "ボタン設定",
|
|
902
|
+
"configure-buttons-description": "複数のボタングループとドロップダウン構造を管理します。",
|
|
903
|
+
"general": "全体",
|
|
904
|
+
"general-description": "ボタングループとその間隔を管理します。",
|
|
905
|
+
"detail-description": "選択中ノードを編集し、子項目を並び替えます。",
|
|
906
|
+
"search": "ボタンを検索",
|
|
907
|
+
"no-matches": "一致するボタンがありません。",
|
|
908
|
+
"group-label": "グループ",
|
|
909
|
+
"groups": "グループ",
|
|
910
|
+
"group-items": "グループ内項目",
|
|
911
|
+
"dropdown-label": "ドロップダウン",
|
|
912
|
+
"untitled-button": "未命名ボタン",
|
|
913
|
+
"untitled-dropdown": "未命名ドロップダウン",
|
|
914
|
+
"add-group": "グループを追加",
|
|
915
|
+
"add-button": "ボタンを追加",
|
|
916
|
+
"add-dropdown": "ドロップダウンを追加",
|
|
917
|
+
"group-gap": "グループ間隔",
|
|
918
|
+
"button-title": "ボタン名",
|
|
919
|
+
"button-icon": "ボタンアイコン",
|
|
920
|
+
"button-variant": "ボタンバリアント",
|
|
921
|
+
"button-variant-default": "デフォルト",
|
|
922
|
+
"button-variant-default-option": "通常",
|
|
923
|
+
"button-variant-primary": "プライマリ",
|
|
924
|
+
"button-variant-destructive": "危険",
|
|
925
|
+
"button-variant-ghost": "ゴースト",
|
|
926
|
+
"button-parent": "親コンテナ",
|
|
927
|
+
"button-hide-title": "テキストを隠してアイコンのみ表示",
|
|
928
|
+
"dropdown-title": "ドロップダウン名",
|
|
929
|
+
"dropdown-icon": "ドロップダウンアイコン",
|
|
930
|
+
"dropdown-parent": "親グループ",
|
|
931
|
+
"children": "子項目",
|
|
932
|
+
"delete-group": "グループを削除",
|
|
933
|
+
"delete-button": "ボタンを削除",
|
|
934
|
+
"delete-dropdown": "ドロップダウンを削除",
|
|
935
|
+
"cancel": "キャンセル",
|
|
936
|
+
"confirm": "確認"
|
|
937
|
+
},
|
|
938
|
+
"ko": {
|
|
939
|
+
"configure-buttons": "버튼 설정",
|
|
940
|
+
"configure-buttons-description": "여러 버튼 그룹과 드롭다운 구조를 관리합니다.",
|
|
941
|
+
"general": "전체",
|
|
942
|
+
"general-description": "버튼 그룹과 그룹 간 간격을 관리합니다.",
|
|
943
|
+
"detail-description": "선택한 노드를 편집하고 하위 항목 순서를 조정합니다.",
|
|
944
|
+
"search": "버튼 검색",
|
|
945
|
+
"no-matches": "일치하는 버튼이 없습니다.",
|
|
946
|
+
"group-label": "그룹",
|
|
947
|
+
"groups": "그룹",
|
|
948
|
+
"group-items": "그룹 항목",
|
|
949
|
+
"dropdown-label": "드롭다운",
|
|
950
|
+
"untitled-button": "이름 없는 버튼",
|
|
951
|
+
"untitled-dropdown": "이름 없는 드롭다운",
|
|
952
|
+
"add-group": "그룹 추가",
|
|
953
|
+
"add-button": "버튼 추가",
|
|
954
|
+
"add-dropdown": "드롭다운 추가",
|
|
955
|
+
"group-gap": "그룹 간격",
|
|
956
|
+
"button-title": "버튼 이름",
|
|
957
|
+
"button-icon": "버튼 아이콘",
|
|
958
|
+
"button-variant": "버튼 변형",
|
|
959
|
+
"button-variant-default": "기본값",
|
|
960
|
+
"button-variant-default-option": "기본",
|
|
961
|
+
"button-variant-primary": "주 버튼",
|
|
962
|
+
"button-variant-destructive": "위험",
|
|
963
|
+
"button-variant-ghost": "고스트",
|
|
964
|
+
"button-parent": "부모 컨테이너",
|
|
965
|
+
"button-hide-title": "텍스트를 숨기고 아이콘만 표시",
|
|
966
|
+
"dropdown-title": "드롭다운 이름",
|
|
967
|
+
"dropdown-icon": "드롭다운 아이콘",
|
|
968
|
+
"dropdown-parent": "부모 그룹",
|
|
969
|
+
"children": "하위 항목",
|
|
970
|
+
"delete-group": "그룹 삭제",
|
|
971
|
+
"delete-button": "버튼 삭제",
|
|
972
|
+
"delete-dropdown": "드롭다운 삭제",
|
|
973
|
+
"cancel": "취소",
|
|
974
|
+
"confirm": "확인"
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
</i18n>
|