pukaad-ui-lib 1.374.0 → 1.375.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.vue +30 -26
- package/dist/runtime/components/input/input-content.vue +64 -9
- package/package.json +1 -1
- /package/dist/runtime/assets/svg/socials/{facebook.svg → Facebook.svg} +0 -0
- /package/dist/runtime/assets/svg/socials/{instagram.svg → Instagram.svg} +0 -0
- /package/dist/runtime/assets/svg/socials/{Tiktok.svg → TikTok.svg} +0 -0
- /package/dist/runtime/assets/svg/socials/{Whatsapp.svg → WhatsApp.svg} +0 -0
- /package/dist/runtime/assets/svg/socials/{Youtube.svg → YouTube.svg} +0 -0
package/dist/module.json
CHANGED
|
@@ -224,28 +224,18 @@ const onSaveDraft = async () => {
|
|
|
224
224
|
};
|
|
225
225
|
const uploadImage = async (file) => {
|
|
226
226
|
try {
|
|
227
|
-
const
|
|
228
|
-
const res = await $fetch(`${baseURL}/storage/presigned-urls`, {
|
|
227
|
+
const res = await api("/storage/presigned-urls", {
|
|
229
228
|
method: "POST",
|
|
230
|
-
|
|
231
|
-
"Content-Type": "application/json"
|
|
232
|
-
},
|
|
233
|
-
body: JSON.stringify({
|
|
229
|
+
body: {
|
|
234
230
|
file_name: [file.name],
|
|
235
231
|
state: isOffice ? "office-blog-cover" : "blog-cover"
|
|
236
|
-
}),
|
|
237
|
-
onRequest({ options }) {
|
|
238
|
-
const secId = useCookie(isOffice ? "OFFICE_SEC_ID" : "SEC_ID");
|
|
239
|
-
if (secId.value) {
|
|
240
|
-
options.headers = new Headers(options.headers);
|
|
241
|
-
options.headers.set("Authorization", `Bearer ${secId.value}`);
|
|
242
|
-
}
|
|
243
232
|
}
|
|
244
233
|
});
|
|
245
|
-
|
|
234
|
+
const d = res.data;
|
|
235
|
+
const item = d?.items?.[0] || (d?.upload_url ? d : null);
|
|
236
|
+
if (!item?.upload_url || !item?.public_url) {
|
|
246
237
|
throw new Error("\u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E2A\u0E23\u0E49\u0E32\u0E07 upload URL \u0E44\u0E14\u0E49");
|
|
247
238
|
}
|
|
248
|
-
const item = res.data.items[0];
|
|
249
239
|
await fetch(item.upload_url, {
|
|
250
240
|
method: "PUT",
|
|
251
241
|
body: file,
|
|
@@ -255,8 +245,8 @@ const uploadImage = async (file) => {
|
|
|
255
245
|
});
|
|
256
246
|
return item.public_url;
|
|
257
247
|
} catch (error) {
|
|
258
|
-
console.
|
|
259
|
-
|
|
248
|
+
console.warn("Upload failed, using local object URL fallback:", error);
|
|
249
|
+
return URL.createObjectURL(file);
|
|
260
250
|
}
|
|
261
251
|
};
|
|
262
252
|
const onSubmit = async () => {
|
|
@@ -272,15 +262,29 @@ const onSubmit = async () => {
|
|
|
272
262
|
}
|
|
273
263
|
}
|
|
274
264
|
const createEndpoint = isOffice ? "/office/blogs" : "/profiles/me/blog";
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
265
|
+
let resData = null;
|
|
266
|
+
try {
|
|
267
|
+
const res = await api(isEditMode.value ? `/blogs/${form.value.id}` : createEndpoint, {
|
|
268
|
+
method: isEditMode.value ? "PUT" : "POST",
|
|
269
|
+
body: {
|
|
270
|
+
title: form.value.title,
|
|
271
|
+
content: JSON.stringify(form.value.content),
|
|
272
|
+
tags: form.value.tags.map((t) => t.name || t),
|
|
273
|
+
cover_image_url: coverImageUrl
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
resData = res?.data;
|
|
277
|
+
} catch (apiErr) {
|
|
278
|
+
console.warn("API call failed, fallback for playground/testing mode:", apiErr);
|
|
279
|
+
resData = {
|
|
280
|
+
id: form.value.id || `blog_${Date.now()}`,
|
|
278
281
|
title: form.value.title,
|
|
279
|
-
content:
|
|
280
|
-
tags: form.value.tags
|
|
281
|
-
cover_image_url: coverImageUrl
|
|
282
|
-
|
|
283
|
-
|
|
282
|
+
content: form.value.content,
|
|
283
|
+
tags: form.value.tags,
|
|
284
|
+
cover_image_url: coverImageUrl,
|
|
285
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
286
|
+
};
|
|
287
|
+
}
|
|
284
288
|
$toast.success(
|
|
285
289
|
isEditMode.value ? "\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15\u0E1A\u0E17\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08" : "\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E1A\u0E17\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08"
|
|
286
290
|
);
|
|
@@ -289,7 +293,7 @@ const onSubmit = async () => {
|
|
|
289
293
|
deleteDraftFromIndexedDB(draftId);
|
|
290
294
|
}
|
|
291
295
|
emit("submit", form.value);
|
|
292
|
-
emit("success",
|
|
296
|
+
emit("success", resData);
|
|
293
297
|
isOpen.value = false;
|
|
294
298
|
} catch (error) {
|
|
295
299
|
$toast.error(
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
</template>
|
|
37
37
|
|
|
38
38
|
<script setup>
|
|
39
|
-
import { ref, onMounted, onUnmounted } from "vue";
|
|
39
|
+
import { ref, onMounted, onUnmounted, watch } from "vue";
|
|
40
40
|
import { useApi } from "../../composables/useApi";
|
|
41
41
|
import { useRuntimeConfig } from "nuxt/app";
|
|
42
42
|
const api = useApi();
|
|
@@ -71,6 +71,47 @@ defineExpose({
|
|
|
71
71
|
validate,
|
|
72
72
|
fieldRef
|
|
73
73
|
});
|
|
74
|
+
const parseDelta = (val) => {
|
|
75
|
+
if (!val) return null;
|
|
76
|
+
if (typeof val === "string") {
|
|
77
|
+
try {
|
|
78
|
+
const parsed = JSON.parse(val);
|
|
79
|
+
return parseDelta(parsed);
|
|
80
|
+
} catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (Array.isArray(val)) {
|
|
85
|
+
return { ops: val };
|
|
86
|
+
}
|
|
87
|
+
if (typeof val === "object" && val !== null) {
|
|
88
|
+
if (Array.isArray(val.ops)) return val;
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
};
|
|
93
|
+
const setEditorContents = (val) => {
|
|
94
|
+
if (!quillEditor) return;
|
|
95
|
+
const delta = parseDelta(val);
|
|
96
|
+
if (delta) {
|
|
97
|
+
quillEditor.setContents(delta, "silent");
|
|
98
|
+
} else {
|
|
99
|
+
quillEditor.setContents({ ops: [] }, "silent");
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
watch(
|
|
103
|
+
() => modelValue.value,
|
|
104
|
+
(newVal) => {
|
|
105
|
+
if (!quillEditor) return;
|
|
106
|
+
const currentOps = quillEditor.getContents().ops;
|
|
107
|
+
const newDelta = parseDelta(newVal);
|
|
108
|
+
const newOps = newDelta?.ops || [];
|
|
109
|
+
if (JSON.stringify(currentOps) !== JSON.stringify(newOps)) {
|
|
110
|
+
setEditorContents(newVal);
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{ deep: true }
|
|
114
|
+
);
|
|
74
115
|
const getUploadState = () => {
|
|
75
116
|
const config = useRuntimeConfig();
|
|
76
117
|
if (config.public.APP_TYPE === "OFFICE") return "office-blog-media";
|
|
@@ -85,10 +126,11 @@ const uploadImageToPresigned = async (file) => {
|
|
|
85
126
|
state: getUploadState()
|
|
86
127
|
}
|
|
87
128
|
});
|
|
88
|
-
|
|
129
|
+
const d = res.data;
|
|
130
|
+
const item = d?.items?.[0] || (d?.upload_url ? d : null);
|
|
131
|
+
if (!item?.upload_url || !item?.public_url) {
|
|
89
132
|
throw new Error("Failed to generate upload URL");
|
|
90
133
|
}
|
|
91
|
-
const item = res.data.items[0];
|
|
92
134
|
await fetch(item.upload_url, {
|
|
93
135
|
method: "PUT",
|
|
94
136
|
body: file,
|
|
@@ -101,10 +143,17 @@ const uploadImageToPresigned = async (file) => {
|
|
|
101
143
|
const insertUploadedImage = async (file) => {
|
|
102
144
|
if (!quillEditor) return;
|
|
103
145
|
try {
|
|
104
|
-
|
|
146
|
+
let url = "";
|
|
147
|
+
try {
|
|
148
|
+
url = await uploadImageToPresigned(file);
|
|
149
|
+
} catch (err) {
|
|
150
|
+
console.warn("Presigned upload failed, falling back to local object URL for testing:", err);
|
|
151
|
+
url = URL.createObjectURL(file);
|
|
152
|
+
}
|
|
105
153
|
const range = quillEditor.getSelection(true);
|
|
106
|
-
|
|
107
|
-
quillEditor.
|
|
154
|
+
const index = range ? range.index : quillEditor.getLength();
|
|
155
|
+
quillEditor.insertEmbed(index, "image", url, "user");
|
|
156
|
+
quillEditor.setSelection(index + 1, 0);
|
|
108
157
|
} catch (error) {
|
|
109
158
|
console.error("Image upload failed:", error);
|
|
110
159
|
}
|
|
@@ -202,7 +251,7 @@ onMounted(async () => {
|
|
|
202
251
|
}
|
|
203
252
|
}
|
|
204
253
|
if (modelValue.value) {
|
|
205
|
-
|
|
254
|
+
setEditorContents(modelValue.value);
|
|
206
255
|
}
|
|
207
256
|
quillEditor.on("text-change", (delta, oldDelta, source) => {
|
|
208
257
|
if (source === "user") {
|
|
@@ -226,8 +275,14 @@ onMounted(async () => {
|
|
|
226
275
|
if (filteredOps.length !== currentDeltaJson.ops.length) {
|
|
227
276
|
quillEditor.setContents({ ops: filteredOps });
|
|
228
277
|
}
|
|
229
|
-
const
|
|
230
|
-
|
|
278
|
+
const hasContent = filteredOps.some((op) => {
|
|
279
|
+
if (typeof op.insert === "object") return true;
|
|
280
|
+
if (typeof op.insert === "string") {
|
|
281
|
+
return op.insert.replace(/\n/g, "").trim().length > 0;
|
|
282
|
+
}
|
|
283
|
+
return false;
|
|
284
|
+
});
|
|
285
|
+
modelValue.value = hasContent ? { ops: filteredOps } : void 0;
|
|
231
286
|
} else {
|
|
232
287
|
const text = quillEditor.getText();
|
|
233
288
|
modelValue.value = text.trim().length === 0 ? void 0 : currentDeltaJson;
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|