pukaad-ui-lib 1.136.0 → 1.138.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/runtime/components/drawer/drawer-post-blog.d.vue.ts +5 -2
- package/dist/runtime/components/drawer/drawer-post-blog.vue +96 -8
- package/dist/runtime/components/drawer/drawer-post-blog.vue.d.ts +5 -2
- package/dist/runtime/components/input/input-autocomplete.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-autocomplete.vue.d.ts +1 -1
- package/dist/runtime/components/input/input-tag.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-tag.vue +109 -44
- package/dist/runtime/components/input/input-tag.vue.d.ts +1 -1
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export interface DrawerPostBlogItem {
|
|
2
2
|
title: string;
|
|
3
3
|
content: object[];
|
|
4
|
-
tags:
|
|
4
|
+
tags: any[];
|
|
5
5
|
disableComment: boolean;
|
|
6
|
-
coverImage:
|
|
6
|
+
coverImage: {
|
|
7
|
+
file?: File;
|
|
8
|
+
url: string;
|
|
9
|
+
}[];
|
|
7
10
|
}
|
|
8
11
|
export interface DrawerPostBlogProps {
|
|
9
12
|
item?: DrawerPostBlogItem;
|
|
@@ -58,8 +58,13 @@
|
|
|
58
58
|
<div class="flex justify-end gap-[16px] items-center">
|
|
59
59
|
<Button variant="outline" @click="onClose">ยกเลิก</Button>
|
|
60
60
|
<Button @click="onSaveDraft"> บันทึกแบบร่าง </Button>
|
|
61
|
-
<Button
|
|
62
|
-
|
|
61
|
+
<Button
|
|
62
|
+
type="submit"
|
|
63
|
+
color="primary"
|
|
64
|
+
:disabled="!meta.valid || isLoading"
|
|
65
|
+
>
|
|
66
|
+
<span v-if="isLoading">กำลังบันทึก...</span>
|
|
67
|
+
<span v-else>เผยแพร่</span>
|
|
63
68
|
</Button>
|
|
64
69
|
</div>
|
|
65
70
|
</template>
|
|
@@ -68,8 +73,10 @@
|
|
|
68
73
|
|
|
69
74
|
<script setup>
|
|
70
75
|
import { ref, watch, computed } from "vue";
|
|
71
|
-
import { useNuxtApp } from "nuxt/app";
|
|
72
|
-
|
|
76
|
+
import { useNuxtApp, useRuntimeConfig, useCookie } from "nuxt/app";
|
|
77
|
+
import { useApi } from "../../composables/useApi";
|
|
78
|
+
const { $alert, $toast } = useNuxtApp();
|
|
79
|
+
const api = useApi();
|
|
73
80
|
const emit = defineEmits(["submit", "saveDraft"]);
|
|
74
81
|
const props = defineProps({
|
|
75
82
|
item: { type: Object, required: false, default: () => ({
|
|
@@ -81,6 +88,7 @@ const props = defineProps({
|
|
|
81
88
|
}) }
|
|
82
89
|
});
|
|
83
90
|
const form = ref(JSON.parse(JSON.stringify(props.item)));
|
|
91
|
+
const isLoading = ref(false);
|
|
84
92
|
const isOpen = defineModel({ type: Boolean, ...{
|
|
85
93
|
default: false
|
|
86
94
|
} });
|
|
@@ -115,9 +123,89 @@ const onSaveDraft = () => {
|
|
|
115
123
|
emit("saveDraft", form.value);
|
|
116
124
|
console.log("onSaveDraft", form.value);
|
|
117
125
|
};
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
126
|
+
const uploadImage = async (file) => {
|
|
127
|
+
try {
|
|
128
|
+
const config = useRuntimeConfig();
|
|
129
|
+
const baseURL = config.public.BASE_URL_API;
|
|
130
|
+
const res = await $fetch(`${baseURL}/storage/presigned-urls`, {
|
|
131
|
+
method: "POST",
|
|
132
|
+
headers: {
|
|
133
|
+
"Content-Type": "application/json"
|
|
134
|
+
// Note: We might need Auth token here if the endpoint requires it,
|
|
135
|
+
// but user instruction said "ห้าม ส่ง Authorization Header ไปยัง S3"
|
|
136
|
+
// It didn't say forbid Auth to /storage/presigned-urls.
|
|
137
|
+
// Let's try adding token manually if useApi was doing it.
|
|
138
|
+
},
|
|
139
|
+
body: JSON.stringify({
|
|
140
|
+
file_name: [file.name],
|
|
141
|
+
state: "blog"
|
|
142
|
+
}),
|
|
143
|
+
onRequest({ options }) {
|
|
144
|
+
const { APP_TYPE } = config.public;
|
|
145
|
+
const secId = useCookie(
|
|
146
|
+
APP_TYPE === "OFFICE" ? "OFFICE_SEC_ID" : "SEC_ID"
|
|
147
|
+
);
|
|
148
|
+
if (secId.value) {
|
|
149
|
+
options.headers = new Headers(options.headers);
|
|
150
|
+
options.headers.set("Authorization", `Bearer ${secId.value}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
if (res.code !== 200 || !res.data?.items?.[0]) {
|
|
155
|
+
throw new Error(res.message || "Failed to generate upload URL");
|
|
156
|
+
}
|
|
157
|
+
const item = res.data.items[0];
|
|
158
|
+
console.log("Uploading to S3:", item.upload_url);
|
|
159
|
+
await fetch(item.upload_url, {
|
|
160
|
+
method: "PUT",
|
|
161
|
+
body: file,
|
|
162
|
+
headers: {
|
|
163
|
+
"Content-Type": file.type
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
return item.public_url;
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error("Upload failed:", error);
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const onSubmit = async () => {
|
|
173
|
+
isLoading.value = true;
|
|
174
|
+
try {
|
|
175
|
+
let coverImageUrl = "";
|
|
176
|
+
if (form.value.coverImage && form.value.coverImage.length > 0) {
|
|
177
|
+
const fileItem = form.value.coverImage[0];
|
|
178
|
+
if (fileItem && fileItem.file) {
|
|
179
|
+
console.log("File found:", fileItem.file);
|
|
180
|
+
console.log("File name:", fileItem.file.name);
|
|
181
|
+
coverImageUrl = await uploadImage(fileItem.file);
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
console.log("No cover image selected");
|
|
185
|
+
}
|
|
186
|
+
const payload = {
|
|
187
|
+
title: form.value.title,
|
|
188
|
+
content: JSON.stringify(form.value.content),
|
|
189
|
+
tags: form.value.tags.map((t) => t.name || t),
|
|
190
|
+
cover_image_url: coverImageUrl
|
|
191
|
+
};
|
|
192
|
+
console.log("Submitting blog payload:", payload);
|
|
193
|
+
const res = await api("/blogs", {
|
|
194
|
+
method: "POST",
|
|
195
|
+
body: payload
|
|
196
|
+
});
|
|
197
|
+
if (res.code === "SUCCESS_CREATED") {
|
|
198
|
+
$toast.success("\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E1A\u0E17\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08");
|
|
199
|
+
emit("submit", form.value);
|
|
200
|
+
isOpen.value = false;
|
|
201
|
+
} else {
|
|
202
|
+
throw new Error(res.message || "Failed to create blog");
|
|
203
|
+
}
|
|
204
|
+
} catch (error) {
|
|
205
|
+
$toast.error(error.message || "\u0E40\u0E01\u0E34\u0E14\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E43\u0E19\u0E01\u0E32\u0E23\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E1A\u0E17\u0E04\u0E27\u0E32\u0E21");
|
|
206
|
+
console.error("Submit error:", error);
|
|
207
|
+
} finally {
|
|
208
|
+
isLoading.value = false;
|
|
209
|
+
}
|
|
122
210
|
};
|
|
123
211
|
</script>
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export interface DrawerPostBlogItem {
|
|
2
2
|
title: string;
|
|
3
3
|
content: object[];
|
|
4
|
-
tags:
|
|
4
|
+
tags: any[];
|
|
5
5
|
disableComment: boolean;
|
|
6
|
-
coverImage:
|
|
6
|
+
coverImage: {
|
|
7
|
+
file?: File;
|
|
8
|
+
url: string;
|
|
9
|
+
}[];
|
|
7
10
|
}
|
|
8
11
|
export interface DrawerPostBlogProps {
|
|
9
12
|
item?: DrawerPostBlogItem;
|
|
@@ -36,9 +36,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
36
36
|
id: string;
|
|
37
37
|
name: string;
|
|
38
38
|
description: string;
|
|
39
|
+
limit: number;
|
|
39
40
|
options: AutocompleteOption[] | string[] | number[];
|
|
40
41
|
placeholder: string;
|
|
41
|
-
limit: number;
|
|
42
42
|
disabledErrorMessage: boolean;
|
|
43
43
|
disabledBorder: boolean;
|
|
44
44
|
showCounter: boolean;
|
|
@@ -36,9 +36,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
36
36
|
id: string;
|
|
37
37
|
name: string;
|
|
38
38
|
description: string;
|
|
39
|
+
limit: number;
|
|
39
40
|
options: AutocompleteOption[] | string[] | number[];
|
|
40
41
|
placeholder: string;
|
|
41
|
-
limit: number;
|
|
42
42
|
disabledErrorMessage: boolean;
|
|
43
43
|
disabledBorder: boolean;
|
|
44
44
|
showCounter: boolean;
|
|
@@ -26,8 +26,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
26
26
|
}>, {
|
|
27
27
|
name: string;
|
|
28
28
|
state: "user" | "admin";
|
|
29
|
-
placeholder: string;
|
|
30
29
|
limit: number;
|
|
30
|
+
placeholder: string;
|
|
31
31
|
ignore: string[];
|
|
32
32
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
33
33
|
declare const _default: typeof __VLS_export;
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
<!-- Selected Tags as Chips -->
|
|
21
21
|
<Chip
|
|
22
22
|
v-for="tag in selectedTags"
|
|
23
|
-
:key="tag.
|
|
23
|
+
:key="tag.id"
|
|
24
24
|
closable
|
|
25
|
-
@closable="onRemoveTag(tag.
|
|
25
|
+
@closable="onRemoveTag(tag.id)"
|
|
26
26
|
class="bg-bright"
|
|
27
27
|
>
|
|
28
|
-
{{ tag.
|
|
28
|
+
{{ tag.name }}
|
|
29
29
|
</Chip>
|
|
30
30
|
<!-- Input for search -->
|
|
31
31
|
<InputTextField
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
|
|
62
62
|
<!-- Popular Tab -->
|
|
63
63
|
<ShadTabsContent value="popular" class="m-0">
|
|
64
|
-
<ShadCommandList class="max-h-64">
|
|
64
|
+
<ShadCommandList class="max-h-64 overflow-y-auto">
|
|
65
65
|
<ShadCommandGroup>
|
|
66
66
|
<ShadCommandItem
|
|
67
67
|
v-for="tag in filteredPopularTags"
|
|
@@ -76,7 +76,13 @@
|
|
|
76
76
|
</div>
|
|
77
77
|
</ShadCommandItem>
|
|
78
78
|
</ShadCommandGroup>
|
|
79
|
-
|
|
79
|
+
|
|
80
|
+
<!-- Initital Loading / Empty State -->
|
|
81
|
+
<ShadCommandEmpty
|
|
82
|
+
:force-show="
|
|
83
|
+
filteredPopularTags.length === 0 && !popularState.loading
|
|
84
|
+
"
|
|
85
|
+
>
|
|
80
86
|
<div
|
|
81
87
|
class="flex flex-col items-center justify-center h-full gap-2"
|
|
82
88
|
>
|
|
@@ -84,12 +90,23 @@
|
|
|
84
90
|
<div class="text-gray font-body-medium">ไม่พบข้อมูล</div>
|
|
85
91
|
</div>
|
|
86
92
|
</ShadCommandEmpty>
|
|
93
|
+
|
|
94
|
+
<!-- Loading Indicator -->
|
|
95
|
+
<div v-if="popularState.loading" class="flex justify-center p-2">
|
|
96
|
+
<Icon
|
|
97
|
+
name="lucide:loader-2"
|
|
98
|
+
class="animate-spin h-5 w-5 text-primary"
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<!-- Sentinel for Infinite Scroll -->
|
|
103
|
+
<div ref="popularSentinel" class="h-1" />
|
|
87
104
|
</ShadCommandList>
|
|
88
105
|
</ShadTabsContent>
|
|
89
106
|
|
|
90
107
|
<!-- Latest Tab -->
|
|
91
108
|
<ShadTabsContent value="latest" class="m-0">
|
|
92
|
-
<ShadCommandList class="max-h-64">
|
|
109
|
+
<ShadCommandList class="max-h-64 overflow-y-auto">
|
|
93
110
|
<ShadCommandGroup>
|
|
94
111
|
<ShadCommandItem
|
|
95
112
|
v-for="tag in filteredLatestTags"
|
|
@@ -104,7 +121,13 @@
|
|
|
104
121
|
</div>
|
|
105
122
|
</ShadCommandItem>
|
|
106
123
|
</ShadCommandGroup>
|
|
107
|
-
|
|
124
|
+
|
|
125
|
+
<!-- Initital Loading / Empty State -->
|
|
126
|
+
<ShadCommandEmpty
|
|
127
|
+
:force-show="
|
|
128
|
+
filteredLatestTags.length === 0 && !latestState.loading
|
|
129
|
+
"
|
|
130
|
+
>
|
|
108
131
|
<div
|
|
109
132
|
class="flex flex-col items-center justify-center h-full gap-2"
|
|
110
133
|
>
|
|
@@ -112,6 +135,17 @@
|
|
|
112
135
|
<div class="text-gray font-body-medium">ไม่พบข้อมูล</div>
|
|
113
136
|
</div>
|
|
114
137
|
</ShadCommandEmpty>
|
|
138
|
+
|
|
139
|
+
<!-- Loading Indicator -->
|
|
140
|
+
<div v-if="latestState.loading" class="flex justify-center p-2">
|
|
141
|
+
<Icon
|
|
142
|
+
name="lucide:loader-2"
|
|
143
|
+
class="animate-spin h-5 w-5 text-primary"
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<!-- Sentinel for Infinite Scroll -->
|
|
148
|
+
<div ref="latestSentinel" class="h-1" />
|
|
115
149
|
</ShadCommandList>
|
|
116
150
|
</ShadTabsContent>
|
|
117
151
|
</ShadTabs>
|
|
@@ -121,9 +155,10 @@
|
|
|
121
155
|
</template>
|
|
122
156
|
|
|
123
157
|
<script setup>
|
|
124
|
-
import { ref, computed, onMounted } from "vue";
|
|
158
|
+
import { ref, computed, onMounted, reactive, watch } from "vue";
|
|
125
159
|
import { useNuxtApp } from "nuxt/app";
|
|
126
160
|
import { useApi } from "../../composables/useApi";
|
|
161
|
+
import { useIntersectionObserver } from "@vueuse/core";
|
|
127
162
|
const { $convert } = useNuxtApp();
|
|
128
163
|
const convertNumber = (val) => $convert?.convertNumber(val) || val;
|
|
129
164
|
const api = useApi();
|
|
@@ -146,34 +181,78 @@ const popoverOpen = ref(false);
|
|
|
146
181
|
const currentTab = ref("popular");
|
|
147
182
|
const searchQuery = ref("");
|
|
148
183
|
const inputRef = ref();
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
184
|
+
const popularState = reactive({
|
|
185
|
+
data: [],
|
|
186
|
+
page: 1,
|
|
187
|
+
hasMore: true,
|
|
188
|
+
loading: false
|
|
189
|
+
});
|
|
190
|
+
const latestState = reactive({
|
|
191
|
+
data: [],
|
|
192
|
+
page: 1,
|
|
193
|
+
hasMore: true,
|
|
194
|
+
loading: false
|
|
195
|
+
});
|
|
153
196
|
const mapTag = (tag) => ({
|
|
154
197
|
label: tag.name,
|
|
155
198
|
value: tag.id,
|
|
156
199
|
postCount: tag.usage_count
|
|
157
200
|
});
|
|
158
|
-
const
|
|
159
|
-
|
|
201
|
+
const PAGE_SIZE = 20;
|
|
202
|
+
const fetchTags = async (type) => {
|
|
203
|
+
const state = type === "popular" ? popularState : latestState;
|
|
204
|
+
if (state.loading || !state.hasMore) return;
|
|
205
|
+
state.loading = true;
|
|
160
206
|
try {
|
|
161
|
-
const res = await api(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
207
|
+
const res = await api(
|
|
208
|
+
`/tags/${type}?page=${state.page}&page_size=${PAGE_SIZE}`
|
|
209
|
+
);
|
|
210
|
+
if ((res.code === 200 || res.code === "SUCCESS_OK") && res.data) {
|
|
211
|
+
const newTags = res.data.map(mapTag);
|
|
212
|
+
state.data = [...state.data, ...newTags];
|
|
213
|
+
state.page++;
|
|
214
|
+
state.hasMore = state.page <= res.meta.total_page;
|
|
215
|
+
} else {
|
|
216
|
+
state.hasMore = false;
|
|
166
217
|
}
|
|
167
218
|
} catch (e) {
|
|
168
|
-
console.error(
|
|
219
|
+
console.error(`Failed to fetch ${type} tags:`, e);
|
|
220
|
+
state.hasMore = false;
|
|
169
221
|
} finally {
|
|
170
|
-
|
|
222
|
+
state.loading = false;
|
|
171
223
|
}
|
|
172
224
|
};
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
225
|
+
watch(popoverOpen, (isOpen) => {
|
|
226
|
+
if (isOpen) {
|
|
227
|
+
if (currentTab.value === "popular" && popularState.data.length === 0) {
|
|
228
|
+
fetchTags("popular");
|
|
229
|
+
} else if (currentTab.value === "latest" && latestState.data.length === 0) {
|
|
230
|
+
fetchTags("latest");
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
const popularSentinel = ref(null);
|
|
235
|
+
const latestSentinel = ref(null);
|
|
236
|
+
useIntersectionObserver(popularSentinel, (entries) => {
|
|
237
|
+
const entry = entries[0];
|
|
238
|
+
if (entry?.isIntersecting && currentTab.value === "popular" && popoverOpen.value) {
|
|
239
|
+
fetchTags("popular");
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
useIntersectionObserver(latestSentinel, (entries) => {
|
|
243
|
+
const entry = entries[0];
|
|
244
|
+
if (entry?.isIntersecting && currentTab.value === "latest" && popoverOpen.value) {
|
|
245
|
+
fetchTags("latest");
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
watch(currentTab, (newTab) => {
|
|
249
|
+
if (newTab === "popular" && popularState.data.length === 0) {
|
|
250
|
+
fetchTags("popular");
|
|
251
|
+
} else if (newTab === "latest" && latestState.data.length === 0) {
|
|
252
|
+
fetchTags("latest");
|
|
253
|
+
}
|
|
176
254
|
});
|
|
255
|
+
const selectedTags = computed(() => modelValue.value);
|
|
177
256
|
const isLimitReached = computed(() => {
|
|
178
257
|
if (props.limit <= 0) return false;
|
|
179
258
|
return modelValue.value.length >= props.limit;
|
|
@@ -196,8 +275,8 @@ const handleInteractOutside = (event) => {
|
|
|
196
275
|
event.preventDefault();
|
|
197
276
|
}
|
|
198
277
|
};
|
|
199
|
-
const
|
|
200
|
-
const availableTags =
|
|
278
|
+
const filterTags = (tags) => {
|
|
279
|
+
const availableTags = tags.filter(
|
|
201
280
|
(tag) => !isSelected(tag.value) && !props.ignore.includes(tag.value) && !props.ignore.includes(tag.label)
|
|
202
281
|
);
|
|
203
282
|
if (!searchQuery.value) return availableTags;
|
|
@@ -205,17 +284,9 @@ const filteredPopularTags = computed(() => {
|
|
|
205
284
|
return availableTags.filter(
|
|
206
285
|
(tag) => tag.label.toLowerCase().includes(query) || tag.value.toLowerCase().includes(query)
|
|
207
286
|
);
|
|
208
|
-
}
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
(tag) => !isSelected(tag.value) && !props.ignore.includes(tag.value) && !props.ignore.includes(tag.label)
|
|
212
|
-
);
|
|
213
|
-
if (!searchQuery.value) return availableTags;
|
|
214
|
-
const query = searchQuery.value.toLowerCase();
|
|
215
|
-
return availableTags.filter(
|
|
216
|
-
(tag) => tag.label.toLowerCase().includes(query) || tag.value.toLowerCase().includes(query)
|
|
217
|
-
);
|
|
218
|
-
});
|
|
287
|
+
};
|
|
288
|
+
const filteredPopularTags = computed(() => filterTags(popularState.data));
|
|
289
|
+
const filteredLatestTags = computed(() => filterTags(latestState.data));
|
|
219
290
|
const onSelectTag = (tag) => {
|
|
220
291
|
if (isSelected(tag.value)) {
|
|
221
292
|
modelValue.value = modelValue.value.filter((t) => t.id !== tag.value);
|
|
@@ -247,7 +318,7 @@ const onAddCustomTag = () => {
|
|
|
247
318
|
return;
|
|
248
319
|
}
|
|
249
320
|
const newValue = trimmedQuery.toLowerCase().replace(/\s+/g, "-");
|
|
250
|
-
const existingTag =
|
|
321
|
+
const existingTag = [...popularState.data, ...latestState.data].find(
|
|
251
322
|
(tag) => tag.value === newValue || tag.label === trimmedQuery
|
|
252
323
|
);
|
|
253
324
|
if (existingTag) {
|
|
@@ -262,12 +333,6 @@ const onAddCustomTag = () => {
|
|
|
262
333
|
];
|
|
263
334
|
}
|
|
264
335
|
} else {
|
|
265
|
-
const newTag = {
|
|
266
|
-
label: trimmedQuery,
|
|
267
|
-
value: newValue,
|
|
268
|
-
postCount: 0
|
|
269
|
-
};
|
|
270
|
-
allTags.value = [...allTags.value, newTag];
|
|
271
336
|
modelValue.value = [
|
|
272
337
|
...modelValue.value,
|
|
273
338
|
{ id: newValue, name: trimmedQuery, usage_count: 0 }
|
|
@@ -26,8 +26,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
26
26
|
}>, {
|
|
27
27
|
name: string;
|
|
28
28
|
state: "user" | "admin";
|
|
29
|
-
placeholder: string;
|
|
30
29
|
limit: number;
|
|
30
|
+
placeholder: string;
|
|
31
31
|
ignore: string[];
|
|
32
32
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
33
33
|
declare const _default: typeof __VLS_export;
|