@webx-ui/module-blog 0.7.3 → 0.8.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/ArticleEditorPage-DViFCNvm.js +368 -0
- package/dist/ArticleEditorPage-DViFCNvm.js.map +1 -0
- package/dist/ArticlesPage-CI-Nwhpy.js +535 -0
- package/dist/ArticlesPage-CI-Nwhpy.js.map +1 -0
- package/dist/AuthorsPage-BN6sRqyE.js +197 -0
- package/dist/AuthorsPage-BN6sRqyE.js.map +1 -0
- package/dist/TagsPage-rFfpCqPs.js +463 -0
- package/dist/TagsPage-rFfpCqPs.js.map +1 -0
- package/dist/index-DqN5h0Ej.js +1516 -0
- package/dist/index-DqN5h0Ej.js.map +1 -0
- package/dist/index.d.ts +30 -4
- package/dist/index.js +24 -3034
- package/dist/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,1516 @@
|
|
|
1
|
+
import { provide as Me, inject as Pe, defineComponent as z, useModel as re, computed as T, openBlock as k, createElementBlock as R, createVNode as b, unref as e, createBlock as C, withCtx as g, createTextVNode as W, toDisplayString as V, createCommentVNode as L, mergeModels as ue, ref as S, watch as X, createElementVNode as E, Fragment as Y, renderList as ce, normalizeClass as Ue, onBeforeUnmount as de, normalizeProps as Ie, guardReactiveProps as Re, onMounted as he, createSlots as De, useTemplateRef as ke, nextTick as $e, isRef as pe, withKeys as ie, defineAsyncComponent as le } from "vue";
|
|
2
|
+
import { useAdmin as K, useTranslate as H, useErrorText as Z, WxDate as Le, WxDrafts as Be, categoryRoutes as Ee, useBodyKeys as Oe, WxScreenHead as ze, WxScreen as Ke, WxSaveState as He } from "@webx-ui/module-admin";
|
|
3
|
+
import { RouterLink as Fe, useRoute as je, onBeforeRouteUpdate as Ge, onBeforeRouteLeave as Je } from "vue-router";
|
|
4
|
+
import { WxSelect as ee, WxSkeleton as Te, WxEmpty as Ze, WxText as ve, WxBadge as q, WxButton as O, toast as U, confirm as te, WxSortableList as Qe, WxAction as Xe, useLocales as Ae, WxInput as ae, WxAlert as ne, WxFormItem as J, localizedValue as Ye, WxCard as qe, WxActionBar as et, useModal as ge, WxDialog as me, WxSpace as fe, WxIcon as tt, WxCheckbox as at } from "@webx-ui/core";
|
|
5
|
+
const Se = /* @__PURE__ */ Symbol("wx-article-editor");
|
|
6
|
+
function Kt(n) {
|
|
7
|
+
Me(Se, n);
|
|
8
|
+
}
|
|
9
|
+
function Q() {
|
|
10
|
+
return Pe(Se, null);
|
|
11
|
+
}
|
|
12
|
+
const lt = {
|
|
13
|
+
module: {
|
|
14
|
+
group: "Blog",
|
|
15
|
+
articles: "Articles",
|
|
16
|
+
rubrics: "Rubrics",
|
|
17
|
+
tags: "Tags",
|
|
18
|
+
authors: "Authors",
|
|
19
|
+
author: "Author"
|
|
20
|
+
},
|
|
21
|
+
panel: {
|
|
22
|
+
new: "New article",
|
|
23
|
+
search: "Search by title or address",
|
|
24
|
+
empty: "No articles yet.",
|
|
25
|
+
"empty-search": "Nothing matches that.",
|
|
26
|
+
"empty-bin": "The bin is empty.",
|
|
27
|
+
"column-title": "Title",
|
|
28
|
+
"column-rubrics": "Rubrics",
|
|
29
|
+
"column-author": "Author",
|
|
30
|
+
"column-date": "Date",
|
|
31
|
+
"column-status": "Status",
|
|
32
|
+
"column-deleted": "Deleted",
|
|
33
|
+
"status-draft": "Draft",
|
|
34
|
+
"status-scheduled": "Scheduled",
|
|
35
|
+
"status-published": "Live",
|
|
36
|
+
"status-modified": "Live",
|
|
37
|
+
"status-unpublished": "Off the site",
|
|
38
|
+
edits: "edits",
|
|
39
|
+
pinned: "Pinned to the top",
|
|
40
|
+
"no-address": "The address appears when it is published",
|
|
41
|
+
"no-author": "Nobody",
|
|
42
|
+
"view-all": "All",
|
|
43
|
+
"view-published": "Live",
|
|
44
|
+
"view-scheduled": "Scheduled",
|
|
45
|
+
"view-draft": "Drafts",
|
|
46
|
+
"view-unpublished": "Off the site",
|
|
47
|
+
bin: "Bin",
|
|
48
|
+
"filter-rubric": "Rubric",
|
|
49
|
+
"filter-tag": "Tag",
|
|
50
|
+
"filter-author": "Author",
|
|
51
|
+
"any-rubric": "Any rubric",
|
|
52
|
+
"any-tag": "Any tag",
|
|
53
|
+
"any-author": "Any author",
|
|
54
|
+
open: "Open",
|
|
55
|
+
"open-on-site": "Open on the site",
|
|
56
|
+
"copy-address": "Copy the address",
|
|
57
|
+
pin: "Pin to the top",
|
|
58
|
+
unpin: "Unpin",
|
|
59
|
+
publish: "Publish",
|
|
60
|
+
unpublish: "Take off the site",
|
|
61
|
+
delete: "Delete",
|
|
62
|
+
restore: "Restore",
|
|
63
|
+
cancel: "Cancel",
|
|
64
|
+
"delete-title": "Delete “:title”?",
|
|
65
|
+
"delete-text": "It goes to the bin and comes off the site, and its address is free again.",
|
|
66
|
+
deleted: "The article is in the bin.",
|
|
67
|
+
restored: "The article is back.",
|
|
68
|
+
published: "The article is on the site.",
|
|
69
|
+
"unpublished-done": "The article is off the site.",
|
|
70
|
+
"pinned-done": "Pinned to the top.",
|
|
71
|
+
unpinned: "No longer pinned.",
|
|
72
|
+
"address-copied": "The address is on the clipboard.",
|
|
73
|
+
"new-title": "New article",
|
|
74
|
+
"field-title": "Title",
|
|
75
|
+
create: "Create"
|
|
76
|
+
},
|
|
77
|
+
article: {
|
|
78
|
+
trail: "Where this article sits",
|
|
79
|
+
untitled: "Untitled",
|
|
80
|
+
save: "Save",
|
|
81
|
+
"save-failed": "The article was not saved.",
|
|
82
|
+
schedule: "Schedule",
|
|
83
|
+
scheduled: "The article is scheduled.",
|
|
84
|
+
"publish-title": "Put “:title” on the site?",
|
|
85
|
+
"publish-text": "It answers at :address from the moment you do, for everyone.",
|
|
86
|
+
"publish-later": "It goes on the site on :date and not before. Until then nothing changes.",
|
|
87
|
+
"publish-nowhere": "It has no address in this language yet, so nothing will answer.",
|
|
88
|
+
"publish-now": "now",
|
|
89
|
+
preview: "Preview",
|
|
90
|
+
more: "More",
|
|
91
|
+
discard: "Discard changes",
|
|
92
|
+
discarded: "The article is back to what is published.",
|
|
93
|
+
"conflict-title": "The article changed while you were editing",
|
|
94
|
+
"conflict-mine": "Keep mine",
|
|
95
|
+
"conflict-theirs": "Take the newer version",
|
|
96
|
+
"conflict-theirs-title": "Give up what you wrote?",
|
|
97
|
+
"conflict-theirs-text": "The article is read again as it now is, and what you have typed since goes.",
|
|
98
|
+
leave: "Leave",
|
|
99
|
+
"leave-title": "Leave without saving?",
|
|
100
|
+
"leave-text": "The article could not be saved, and what you wrote is not on the server.",
|
|
101
|
+
"live-scheduled": "Goes out :date",
|
|
102
|
+
"live-since": "On the site since :date",
|
|
103
|
+
"unpublish-title": "Take “:title” off the site?",
|
|
104
|
+
"unpublish-text": "It stops answering at its address. The draft, the history and the rubrics stay — publishing puts it back.",
|
|
105
|
+
"unpublish-waiting": "It has not gone out yet. The day it was set for will pass without it.",
|
|
106
|
+
"unpublish-help": "Takes the article off the site without deleting it.",
|
|
107
|
+
"address-moving": "The address is changing. The old one keeps working and leads to the new one.",
|
|
108
|
+
author: "Author",
|
|
109
|
+
"no-author": "Nobody",
|
|
110
|
+
rubrics: "Rubrics",
|
|
111
|
+
"rubrics-empty": "In no rubric yet.",
|
|
112
|
+
"rubric-main": "Main",
|
|
113
|
+
"rubric-add": "Add a rubric",
|
|
114
|
+
"rubric-remove": "Take out of this rubric",
|
|
115
|
+
"rubric-none-left": "Every rubric is already on this article.",
|
|
116
|
+
"tags-empty": "No tags yet.",
|
|
117
|
+
"tag-add": "Find or make a tag",
|
|
118
|
+
"tag-remove": "Take this tag off",
|
|
119
|
+
"tag-option": ":title · :count",
|
|
120
|
+
"tag-nothing": "No tag is spelled that way.",
|
|
121
|
+
"tag-create": "Make “:title”",
|
|
122
|
+
related: "Related",
|
|
123
|
+
"related-empty": "Nothing pinned by hand.",
|
|
124
|
+
"related-add": "Find an article",
|
|
125
|
+
"related-remove": "Unpin",
|
|
126
|
+
"related-nothing": "Nothing matches that.",
|
|
127
|
+
"history-empty": "This article has never been published.",
|
|
128
|
+
version: "#:number",
|
|
129
|
+
"version-live": "On the site",
|
|
130
|
+
"source-panel": "From the panel",
|
|
131
|
+
"source-mcp": "By an agent",
|
|
132
|
+
"source-import": "Imported",
|
|
133
|
+
"restore-title": "Restore version :number?",
|
|
134
|
+
"restore-text": "It becomes the draft. The site keeps showing what is published until you publish this.",
|
|
135
|
+
"restore-version": "Restore",
|
|
136
|
+
"restored-version": "Version :number is now the draft."
|
|
137
|
+
},
|
|
138
|
+
rubric: {
|
|
139
|
+
new: "New rubric",
|
|
140
|
+
empty: "No rubrics yet.",
|
|
141
|
+
"empty-help": "A rubric is a section of the blog. An article can be in several of them.",
|
|
142
|
+
order: "The order here is the order on the site",
|
|
143
|
+
hidden: "Hidden from the site",
|
|
144
|
+
"no-address": "No address in this language",
|
|
145
|
+
articles: ":count articles",
|
|
146
|
+
"show-articles": "Show its articles",
|
|
147
|
+
edit: "Edit",
|
|
148
|
+
"tab-content": "Content",
|
|
149
|
+
"tab-seo": "SEO",
|
|
150
|
+
"field-title": "Name",
|
|
151
|
+
"field-slug": "Address",
|
|
152
|
+
visible: "Show on the site",
|
|
153
|
+
"visible-help": "Hidden, it drops out of the menu and answers 404. Its articles go on answering at their own addresses.",
|
|
154
|
+
"field-lead": "Introduction",
|
|
155
|
+
"lead-help": "Printed above the list of articles.",
|
|
156
|
+
"cover-help": "Shown wherever the site lists the sections.",
|
|
157
|
+
"address-moving": "The address is changing. The old one keeps working and leads to the new one.",
|
|
158
|
+
"seo-help": "Left empty, the title and the description of this page come from the SEO rules.",
|
|
159
|
+
delete: "Delete",
|
|
160
|
+
"delete-blocked": "While it holds articles it cannot go — move them first.",
|
|
161
|
+
"delete-title": "Delete “:name”?",
|
|
162
|
+
"delete-text": "It goes to the bin and comes off the site, and its address is free again.",
|
|
163
|
+
deleted: "The rubric is in the bin.",
|
|
164
|
+
cancel: "Cancel",
|
|
165
|
+
save: "Save",
|
|
166
|
+
saved: "The rubric is saved.",
|
|
167
|
+
created: "The rubric is made.",
|
|
168
|
+
"reorder-failed": "The new order was not saved."
|
|
169
|
+
},
|
|
170
|
+
author: {
|
|
171
|
+
"tab-profile": "Profile",
|
|
172
|
+
"field-name": "Name on the site",
|
|
173
|
+
"field-name-help": "What readers see under the articles and on the page. Required in the main language.",
|
|
174
|
+
"field-role": "Role",
|
|
175
|
+
"field-bio": "About",
|
|
176
|
+
"field-bio-help": "A few lines for the author's page.",
|
|
177
|
+
"card-page": "On the site",
|
|
178
|
+
"field-photo": "Photo",
|
|
179
|
+
"field-public": "Page on the site",
|
|
180
|
+
"field-public-help": "With it, the name under the articles links to a page with all of the author's articles. Without it, the name is plain text.",
|
|
181
|
+
"field-slug": "Address",
|
|
182
|
+
"field-slug-help": "The last part of the page's address, after …/author/.",
|
|
183
|
+
"account-missing": "Choose the account this profile is for.",
|
|
184
|
+
"account-taken": "This account already has a profile.",
|
|
185
|
+
"name-required": "Write the name in the main language.",
|
|
186
|
+
new: "New author",
|
|
187
|
+
search: "Search by name",
|
|
188
|
+
empty: "No authors yet.",
|
|
189
|
+
"empty-help": "A profile gives an administrator who writes a name for readers, a photo and, if they want it, a page with their articles.",
|
|
190
|
+
"empty-search": "Nothing matches that.",
|
|
191
|
+
choose: "Choose an author",
|
|
192
|
+
"choose-help": "Or add a new one: pick the account and write the name.",
|
|
193
|
+
account: "Account",
|
|
194
|
+
"account-help": "Whose articles these are. Chosen once.",
|
|
195
|
+
"no-accounts": "Every account already has a profile.",
|
|
196
|
+
articles: "Articles: :count",
|
|
197
|
+
"page-open": "Page on the site",
|
|
198
|
+
"page-closed": "No page",
|
|
199
|
+
"open-page": "Open the page",
|
|
200
|
+
save: "Save",
|
|
201
|
+
saved: "Saved",
|
|
202
|
+
"save-failed": "Check the highlighted fields",
|
|
203
|
+
delete: "Delete",
|
|
204
|
+
"delete-title": "Delete the profile of :name?",
|
|
205
|
+
"delete-text": "The articles stay; under them the account's name is shown instead.",
|
|
206
|
+
deleted: "Profile deleted",
|
|
207
|
+
cancel: "Cancel",
|
|
208
|
+
back: "Authors",
|
|
209
|
+
"leave-title": "Leave without saving?",
|
|
210
|
+
"leave-text": "The changes to this profile will be lost.",
|
|
211
|
+
leave: "Leave",
|
|
212
|
+
untitled: "Without a name",
|
|
213
|
+
profile: "Author profile",
|
|
214
|
+
"make-profile": "Make a profile",
|
|
215
|
+
"field-socials": "Networks",
|
|
216
|
+
"field-socials-help": "Shown on the author's page, and named to search engines as the same person.",
|
|
217
|
+
"socials-add": "Add a network",
|
|
218
|
+
"socials-empty": "No networks yet.",
|
|
219
|
+
"social-network": "Network",
|
|
220
|
+
"social-url": "Address",
|
|
221
|
+
"social-network-missing": "Choose the network.",
|
|
222
|
+
"social-url-invalid": "An address that starts with https://."
|
|
223
|
+
},
|
|
224
|
+
tag: {
|
|
225
|
+
new: "New tag",
|
|
226
|
+
"new-title": "New tag",
|
|
227
|
+
"field-title": "Name",
|
|
228
|
+
"field-slug": "Address",
|
|
229
|
+
"field-slug-help": "Left empty, it is made out of the name.",
|
|
230
|
+
create: "Create",
|
|
231
|
+
cancel: "Cancel",
|
|
232
|
+
search: "Search by word or address",
|
|
233
|
+
empty: "No tags yet.",
|
|
234
|
+
"no-address": "No address in this language",
|
|
235
|
+
"column-title": "Name",
|
|
236
|
+
"column-address": "Address",
|
|
237
|
+
"column-articles": "Articles",
|
|
238
|
+
"column-indexing": "Indexing",
|
|
239
|
+
"view-all": "All",
|
|
240
|
+
"view-empty": "Nothing filed",
|
|
241
|
+
"view-noindex": "Not indexed",
|
|
242
|
+
"sort-articles": "Most used",
|
|
243
|
+
"sort-name": "A to Z",
|
|
244
|
+
"indexing-open": "indexed",
|
|
245
|
+
"indexing-rule": "indexed — SEO rule",
|
|
246
|
+
"indexing-noindex": "noindex",
|
|
247
|
+
"indexing-rule-help": "A rule in the SEO section covers this address, so the page is in the index however this tag is set.",
|
|
248
|
+
rename: "Rename",
|
|
249
|
+
renamed: "The tag is renamed.",
|
|
250
|
+
index: "Index",
|
|
251
|
+
noindex: "Keep out of the index",
|
|
252
|
+
indexed: "The tag page is in the index.",
|
|
253
|
+
"kept-out": "The tag page is out of the index.",
|
|
254
|
+
"indexed-many": ":count tag pages are in the index.",
|
|
255
|
+
"kept-out-many": ":count tag pages are out of the index.",
|
|
256
|
+
"open-on-site": "Open on the site",
|
|
257
|
+
"show-articles": "Show its articles",
|
|
258
|
+
delete: "Delete",
|
|
259
|
+
"delete-title": "Delete “:title”?",
|
|
260
|
+
"delete-text": "A tag has no bin: it is gone for good.",
|
|
261
|
+
"delete-text-used": "It is on :count articles and comes off all of them. A tag has no bin: it is gone for good.",
|
|
262
|
+
deleted: "The tag is gone.",
|
|
263
|
+
"delete-many-title": "Delete :count tags?",
|
|
264
|
+
"delete-many-text": "A tag has no bin: they are gone for good.",
|
|
265
|
+
"delete-many-text-used": "They are on :count articles between them and come off all of them. A tag has no bin.",
|
|
266
|
+
"deleted-many": ":count tags are gone.",
|
|
267
|
+
selected: ":count selected",
|
|
268
|
+
clear: "Clear the selection",
|
|
269
|
+
merge: "Merge into one",
|
|
270
|
+
merged: ":count articles now carry “:tag”.",
|
|
271
|
+
"merge-title": "Merge tags",
|
|
272
|
+
"merge-keep": "Which tag to keep",
|
|
273
|
+
"merge-redirect": "Redirect the old addresses",
|
|
274
|
+
"merge-redirect-help": ":addresses will answer 301.",
|
|
275
|
+
"merge-redirect-none": "These tags have no address in this language, so there is nothing to redirect.",
|
|
276
|
+
"merge-warning": ":count articles will carry “:tag” instead. :merged tags will be deleted, and there is no undoing it.",
|
|
277
|
+
"merge-confirm": "Merge"
|
|
278
|
+
}
|
|
279
|
+
}, _e = /* @__PURE__ */ new WeakSet();
|
|
280
|
+
function F() {
|
|
281
|
+
try {
|
|
282
|
+
const { i18n: n } = K();
|
|
283
|
+
_e.has(n) || (n.defaults("webx-blog", lt), _e.add(n));
|
|
284
|
+
} catch {
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const ot = { class: "wx-article-author" }, st = /* @__PURE__ */ z({
|
|
288
|
+
name: "WxArticleAuthor",
|
|
289
|
+
__name: "ArticleAuthor",
|
|
290
|
+
props: /* @__PURE__ */ ue({
|
|
291
|
+
disabled: { type: Boolean, default: !1 }
|
|
292
|
+
}, {
|
|
293
|
+
modelValue: { default: null },
|
|
294
|
+
modelModifiers: {}
|
|
295
|
+
}),
|
|
296
|
+
emits: ["update:modelValue"],
|
|
297
|
+
setup(n) {
|
|
298
|
+
const l = n, o = re(n, "modelValue"), i = Q();
|
|
299
|
+
F();
|
|
300
|
+
const t = H("webx-blog"), a = K(), r = T(() => l.disabled || i?.disabled.value === !0), u = T(
|
|
301
|
+
() => (i?.options.value.authors ?? []).map((c) => ({
|
|
302
|
+
label: c.title,
|
|
303
|
+
value: c.id
|
|
304
|
+
}))
|
|
305
|
+
), s = T(() => {
|
|
306
|
+
if (!a.state.manifest?.modules.some((w) => w.id === "authors") || !a.can("blog.authors.manage") || o.value === null) return null;
|
|
307
|
+
const m = i?.base ?? "/blog", x = i?.options.value.authors.find((w) => w.id === o.value)?.profile;
|
|
308
|
+
return x ? {
|
|
309
|
+
to: { path: `${m}/authors`, query: { author: String(x) } },
|
|
310
|
+
label: t("author.profile")
|
|
311
|
+
} : {
|
|
312
|
+
to: { path: `${m}/authors`, query: { author: "new", account: String(o.value) } },
|
|
313
|
+
label: t("author.make-profile")
|
|
314
|
+
};
|
|
315
|
+
}), v = T({
|
|
316
|
+
get: () => o.value,
|
|
317
|
+
set: (c) => {
|
|
318
|
+
o.value = typeof c == "number" ? c : null;
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
return (c, m) => (k(), R("div", ot, [
|
|
322
|
+
b(e(ee), {
|
|
323
|
+
modelValue: v.value,
|
|
324
|
+
"onUpdate:modelValue": m[0] || (m[0] = (x) => v.value = x),
|
|
325
|
+
options: u.value,
|
|
326
|
+
placeholder: e(t)("article.no-author"),
|
|
327
|
+
disabled: r.value,
|
|
328
|
+
clearable: "",
|
|
329
|
+
filterable: "",
|
|
330
|
+
teleport: "",
|
|
331
|
+
"aria-label": e(t)("article.author")
|
|
332
|
+
}, null, 8, ["modelValue", "options", "placeholder", "disabled", "aria-label"]),
|
|
333
|
+
s.value ? (k(), C(e(Fe), {
|
|
334
|
+
key: 0,
|
|
335
|
+
class: "wx-article-author__profile",
|
|
336
|
+
to: s.value.to
|
|
337
|
+
}, {
|
|
338
|
+
default: g(() => [
|
|
339
|
+
W(V(s.value.label), 1)
|
|
340
|
+
]),
|
|
341
|
+
_: 1
|
|
342
|
+
}, 8, ["to"])) : L("", !0)
|
|
343
|
+
]));
|
|
344
|
+
}
|
|
345
|
+
}), j = (n, l) => {
|
|
346
|
+
const o = n.__vccOpts || n;
|
|
347
|
+
for (const [i, t] of l)
|
|
348
|
+
o[i] = t;
|
|
349
|
+
return o;
|
|
350
|
+
}, it = /* @__PURE__ */ j(st, [["__scopeId", "data-v-4b275a4c"]]);
|
|
351
|
+
function G(n) {
|
|
352
|
+
const l = `${n.apiPath}/blog/articles`, o = `${n.apiPath}/blog/tags`, i = (t) => t.data;
|
|
353
|
+
return {
|
|
354
|
+
articles: (t = {}) => {
|
|
355
|
+
const a = new URLSearchParams();
|
|
356
|
+
t.q && a.set("q", t.q), t.rubric != null && a.set("rubric", String(t.rubric)), t.tag != null && a.set("tag", String(t.tag)), t.author != null && a.set("author", String(t.author)), t.status && a.set("status", t.status), t.sort && a.set("sort", t.sort), t.trashed && a.set("trashed", "1"), t.page && t.page > 1 && a.set("page", String(t.page)), t.per_page && a.set("per_page", String(t.per_page));
|
|
357
|
+
const r = a.size > 0 ? `?${a}` : "";
|
|
358
|
+
return n.http.get(`${l}${r}`).then((u) => ({ ...u.meta, data: u.data, filters: u.filters }));
|
|
359
|
+
},
|
|
360
|
+
get: (t) => n.http.get(`${l}/${t}`).then(i),
|
|
361
|
+
create: (t) => n.http.post(l, t).then(i),
|
|
362
|
+
save: (t, a) => n.http.put(`${l}/${t}`, a).then(i),
|
|
363
|
+
discard: (t) => n.http.post(`${l}/${t}/discard`, {}).then(i),
|
|
364
|
+
versions: (t) => n.http.get(`${l}/${t}/versions`).then(i),
|
|
365
|
+
restoreVersion: (t, a) => n.http.post(`${l}/${t}/versions/${a}/restore`, {}).then(i),
|
|
366
|
+
tags: (t = "") => {
|
|
367
|
+
const a = t.trim() === "" ? "" : `?q=${encodeURIComponent(t.trim())}`;
|
|
368
|
+
return n.http.get(`${o}${a}`).then(i);
|
|
369
|
+
},
|
|
370
|
+
createTag: (t) => n.http.post(o, t).then(i),
|
|
371
|
+
publish: (t, a, r) => n.http.post(`${l}/${t}/publish`, {
|
|
372
|
+
...a == null ? {} : { at: a },
|
|
373
|
+
...r ? { revision: r } : {}
|
|
374
|
+
}).then(i),
|
|
375
|
+
unpublish: (t) => n.http.post(`${l}/${t}/unpublish`, {}).then(i),
|
|
376
|
+
remove: (t) => n.http.delete(`${l}/${t}`).then(() => {
|
|
377
|
+
}),
|
|
378
|
+
restore: (t) => n.http.post(`${l}/${t}/restore`, {}).then(i),
|
|
379
|
+
tagsPage: (t = {}) => {
|
|
380
|
+
const a = new URLSearchParams();
|
|
381
|
+
t.q && a.set("q", t.q), t.empty && a.set("empty", "1"), t.noindex && a.set("noindex", "1"), t.sort && a.set("sort", t.sort), t.page && t.page > 1 && a.set("page", String(t.page)), t.per_page && a.set("per_page", String(t.per_page));
|
|
382
|
+
const r = a.size > 0 ? `?${a}` : "";
|
|
383
|
+
return n.http.get(`${o}${r}`).then((u) => ({ ...u.meta, data: u.data, filters: u.filters }));
|
|
384
|
+
},
|
|
385
|
+
saveTag: (t, a) => n.http.put(`${o}/${t}`, a).then(i),
|
|
386
|
+
removeTag: (t) => n.http.delete(`${o}/${t}`).then(() => {
|
|
387
|
+
}),
|
|
388
|
+
massTags: (t, a) => n.http.post(`${o}/mass`, { ids: t, action: a }).then((r) => r.data.affected),
|
|
389
|
+
mergeTags: (t, a, r) => n.http.post(`${o}/merge`, { ids: t, keep: a, redirect: r }).then(i)
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
const nt = { class: "wx-article-history-tab" }, rt = { class: "wx-article-history" }, ut = { class: "wx-article-history__number" }, ct = { class: "wx-article-history__who" }, dt = /* @__PURE__ */ z({
|
|
393
|
+
name: "WxArticleHistory",
|
|
394
|
+
__name: "ArticleHistory",
|
|
395
|
+
setup(n) {
|
|
396
|
+
const l = K(), o = G(l), i = Q();
|
|
397
|
+
F();
|
|
398
|
+
const t = H("webx-blog"), a = Z(), r = S(null), u = S(!1), s = T(() => i?.article.value ?? null), v = T(() => l.can("blog.articles.manage")), c = T(
|
|
399
|
+
() => s.value?.status === "published" || s.value?.status === "modified" ? r.value?.[0]?.number ?? null : null
|
|
400
|
+
);
|
|
401
|
+
async function m() {
|
|
402
|
+
const w = s.value;
|
|
403
|
+
if (w)
|
|
404
|
+
try {
|
|
405
|
+
r.value = await o.versions(w.id);
|
|
406
|
+
} catch (h) {
|
|
407
|
+
r.value = [], U.danger(a(h));
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
async function x(w) {
|
|
411
|
+
const h = s.value;
|
|
412
|
+
if (!(!h || !await te({
|
|
413
|
+
title: t("article.restore-title", { number: w.number }),
|
|
414
|
+
message: t("article.restore-text"),
|
|
415
|
+
confirmText: t("article.restore-version"),
|
|
416
|
+
cancelText: t("panel.cancel")
|
|
417
|
+
}))) {
|
|
418
|
+
u.value = !0;
|
|
419
|
+
try {
|
|
420
|
+
await o.restoreVersion(h.id, w.number), await i?.reload(), U.success(t("article.restored-version", { number: w.number }));
|
|
421
|
+
} catch (M) {
|
|
422
|
+
U.danger(a(M));
|
|
423
|
+
} finally {
|
|
424
|
+
u.value = !1;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return X(
|
|
429
|
+
() => [s.value?.id, s.value?.published_at, s.value?.updated_at],
|
|
430
|
+
() => {
|
|
431
|
+
m();
|
|
432
|
+
},
|
|
433
|
+
{ immediate: !0 }
|
|
434
|
+
), (w, h) => (k(), R("div", nt, [
|
|
435
|
+
E("div", rt, [
|
|
436
|
+
r.value === null ? (k(), C(e(Te), {
|
|
437
|
+
key: 0,
|
|
438
|
+
class: "wx-article-history__ghost",
|
|
439
|
+
rows: 3
|
|
440
|
+
})) : r.value.length === 0 ? (k(), C(e(Ze), {
|
|
441
|
+
key: 1,
|
|
442
|
+
description: e(t)("article.history-empty")
|
|
443
|
+
}, null, 8, ["description"])) : (k(!0), R(Y, { key: 2 }, ce(r.value, (f) => (k(), R("div", {
|
|
444
|
+
key: f.number,
|
|
445
|
+
class: Ue(["wx-article-history__row", { "is-live": f.number === c.value }])
|
|
446
|
+
}, [
|
|
447
|
+
E("code", ut, V(e(t)("article.version", { number: f.number })), 1),
|
|
448
|
+
E("div", ct, [
|
|
449
|
+
f.created_at ? (k(), C(e(Le), {
|
|
450
|
+
key: 0,
|
|
451
|
+
value: f.created_at,
|
|
452
|
+
size: "md",
|
|
453
|
+
tone: "default"
|
|
454
|
+
}, null, 8, ["value"])) : L("", !0),
|
|
455
|
+
b(e(ve), {
|
|
456
|
+
size: "sm",
|
|
457
|
+
tone: "muted"
|
|
458
|
+
}, {
|
|
459
|
+
default: g(() => [
|
|
460
|
+
W(V(f.author ?? e(t)(`article.source-${f.source}`)) + " ", 1),
|
|
461
|
+
f.comment ? (k(), R(Y, { key: 0 }, [
|
|
462
|
+
W(" · " + V(f.comment), 1)
|
|
463
|
+
], 64)) : L("", !0)
|
|
464
|
+
]),
|
|
465
|
+
_: 2
|
|
466
|
+
}, 1024)
|
|
467
|
+
]),
|
|
468
|
+
f.number === c.value ? (k(), C(e(q), {
|
|
469
|
+
key: 0,
|
|
470
|
+
type: "success",
|
|
471
|
+
dot: ""
|
|
472
|
+
}, {
|
|
473
|
+
default: g(() => [
|
|
474
|
+
W(V(e(t)("article.version-live")), 1)
|
|
475
|
+
]),
|
|
476
|
+
_: 1
|
|
477
|
+
})) : L("", !0),
|
|
478
|
+
v.value && f.number !== c.value ? (k(), C(e(O), {
|
|
479
|
+
key: 1,
|
|
480
|
+
size: "sm",
|
|
481
|
+
variant: "outline",
|
|
482
|
+
loading: u.value,
|
|
483
|
+
onClick: (M) => x(f)
|
|
484
|
+
}, {
|
|
485
|
+
default: g(() => [
|
|
486
|
+
W(V(e(t)("article.restore-version")), 1)
|
|
487
|
+
]),
|
|
488
|
+
_: 1
|
|
489
|
+
}, 8, ["loading", "onClick"])) : L("", !0)
|
|
490
|
+
], 2))), 128))
|
|
491
|
+
]),
|
|
492
|
+
b(e(Be), {
|
|
493
|
+
id: s.value?.id,
|
|
494
|
+
entity: "articles",
|
|
495
|
+
screen: "blog.article-form",
|
|
496
|
+
"can-restore": v.value,
|
|
497
|
+
stamp: [s.value?.published_at, s.value?.updated_at],
|
|
498
|
+
onRestored: h[0] || (h[0] = (f) => e(i)?.reload())
|
|
499
|
+
}, null, 8, ["id", "can-restore", "stamp"])
|
|
500
|
+
]));
|
|
501
|
+
}
|
|
502
|
+
}), ht = /* @__PURE__ */ j(dt, [["__scopeId", "data-v-0052c4f9"]]), pt = { class: "wx-article-related" }, vt = { class: "wx-article-related__name" }, gt = 250, mt = 10, ft = /* @__PURE__ */ z({
|
|
503
|
+
name: "WxArticleRelated",
|
|
504
|
+
__name: "ArticleRelated",
|
|
505
|
+
props: /* @__PURE__ */ ue({
|
|
506
|
+
disabled: { type: Boolean, default: !1 }
|
|
507
|
+
}, {
|
|
508
|
+
modelValue: { default: () => [] },
|
|
509
|
+
modelModifiers: {}
|
|
510
|
+
}),
|
|
511
|
+
emits: ["update:modelValue"],
|
|
512
|
+
setup(n) {
|
|
513
|
+
const l = n, o = re(n, "modelValue"), i = K(), t = G(i), a = Q();
|
|
514
|
+
F();
|
|
515
|
+
const r = H("webx-blog"), u = Z(), s = T(() => l.disabled || a?.disabled.value === !0), v = S(/* @__PURE__ */ new Map()), c = S([]);
|
|
516
|
+
let m;
|
|
517
|
+
X(
|
|
518
|
+
() => a?.related.value,
|
|
519
|
+
(_) => {
|
|
520
|
+
const y = new Map(v.value);
|
|
521
|
+
for (const $ of _ ?? []) y.set($.id, $.title);
|
|
522
|
+
v.value = y;
|
|
523
|
+
},
|
|
524
|
+
{ immediate: !0, deep: !0 }
|
|
525
|
+
);
|
|
526
|
+
const x = T({
|
|
527
|
+
get: () => o.value.map((_) => ({ id: _, title: v.value.get(_) ?? `#${_}` })),
|
|
528
|
+
set: (_) => {
|
|
529
|
+
o.value = _.map((y) => y.id);
|
|
530
|
+
}
|
|
531
|
+
}), w = T(
|
|
532
|
+
() => c.value.filter((_) => !o.value.includes(_.id)).map((_) => ({ label: _.title, value: _.id }))
|
|
533
|
+
);
|
|
534
|
+
async function h(_) {
|
|
535
|
+
const y = a?.article.value?.id;
|
|
536
|
+
try {
|
|
537
|
+
const $ = await t.articles({ q: _, per_page: mt });
|
|
538
|
+
c.value = $.data.filter((p) => p.id !== y).map((p) => ({ id: p.id, title: p.title }));
|
|
539
|
+
const P = new Map(v.value);
|
|
540
|
+
for (const p of c.value) P.set(p.id, p.title);
|
|
541
|
+
v.value = P;
|
|
542
|
+
} catch ($) {
|
|
543
|
+
U.danger(u($));
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
function f(_) {
|
|
547
|
+
clearTimeout(m), m = setTimeout(() => {
|
|
548
|
+
h(_);
|
|
549
|
+
}, gt);
|
|
550
|
+
}
|
|
551
|
+
function M(_) {
|
|
552
|
+
typeof _ != "number" || o.value.includes(_) || (o.value = [...o.value, _]);
|
|
553
|
+
}
|
|
554
|
+
function D(_) {
|
|
555
|
+
o.value = o.value.filter((y) => y !== _);
|
|
556
|
+
}
|
|
557
|
+
return X(
|
|
558
|
+
() => a?.article.value?.id,
|
|
559
|
+
() => {
|
|
560
|
+
h("");
|
|
561
|
+
},
|
|
562
|
+
{ immediate: !0 }
|
|
563
|
+
), de(() => clearTimeout(m)), (_, y) => (k(), R("div", pt, [
|
|
564
|
+
b(e(Qe), {
|
|
565
|
+
modelValue: x.value,
|
|
566
|
+
"onUpdate:modelValue": y[0] || (y[0] = ($) => x.value = $),
|
|
567
|
+
plain: "",
|
|
568
|
+
size: "sm",
|
|
569
|
+
"item-key": "id",
|
|
570
|
+
"item-label": "title",
|
|
571
|
+
disabled: s.value,
|
|
572
|
+
"empty-text": e(r)("article.related-empty"),
|
|
573
|
+
"aria-label": e(r)("article.related")
|
|
574
|
+
}, {
|
|
575
|
+
default: g(({ item: $ }) => [
|
|
576
|
+
E("span", vt, V($.title), 1)
|
|
577
|
+
]),
|
|
578
|
+
actions: g(({ item: $ }) => [
|
|
579
|
+
b(e(Xe), {
|
|
580
|
+
type: "remove",
|
|
581
|
+
size: "sm",
|
|
582
|
+
disabled: s.value,
|
|
583
|
+
title: e(r)("article.related-remove"),
|
|
584
|
+
onClick: (P) => D($.id)
|
|
585
|
+
}, null, 8, ["disabled", "title", "onClick"])
|
|
586
|
+
]),
|
|
587
|
+
_: 1
|
|
588
|
+
}, 8, ["modelValue", "disabled", "empty-text", "aria-label"]),
|
|
589
|
+
b(e(ee), {
|
|
590
|
+
"model-value": null,
|
|
591
|
+
options: w.value,
|
|
592
|
+
placeholder: e(r)("article.related-add"),
|
|
593
|
+
"empty-text": e(r)("article.related-nothing"),
|
|
594
|
+
disabled: s.value,
|
|
595
|
+
filterable: "",
|
|
596
|
+
teleport: "",
|
|
597
|
+
"aria-label": e(r)("article.related-add"),
|
|
598
|
+
onSearch: f,
|
|
599
|
+
"onUpdate:modelValue": M
|
|
600
|
+
}, null, 8, ["options", "placeholder", "empty-text", "disabled", "aria-label"])
|
|
601
|
+
]));
|
|
602
|
+
}
|
|
603
|
+
}), bt = /* @__PURE__ */ j(ft, [["__scopeId", "data-v-164e86fe"]]), wt = { class: "wx-article-slug" }, yt = { class: "wx-article-slug__prefix" }, xt = /* @__PURE__ */ z({
|
|
604
|
+
name: "WxArticleSlug",
|
|
605
|
+
inheritAttrs: !1,
|
|
606
|
+
__name: "ArticleSlug",
|
|
607
|
+
setup(n) {
|
|
608
|
+
const l = Q(), o = Ae();
|
|
609
|
+
F();
|
|
610
|
+
const i = H("webx-blog"), t = T(() => {
|
|
611
|
+
const u = l?.prefix.value ?? "";
|
|
612
|
+
return u === "" ? "/" : `/${u}/`;
|
|
613
|
+
}), a = T(() => {
|
|
614
|
+
const u = l?.values.value.slug;
|
|
615
|
+
return typeof u == "string" ? u : u?.[o.active.value] ?? "";
|
|
616
|
+
}), r = T(() => {
|
|
617
|
+
const u = l?.article.value?.path;
|
|
618
|
+
return typeof u == "string" && a.value !== "" && `${t.value}${a.value}` != `/${u}`;
|
|
619
|
+
});
|
|
620
|
+
return (u, s) => (k(), R("div", wt, [
|
|
621
|
+
b(e(ae), Ie(Re(u.$attrs)), {
|
|
622
|
+
prefix: g(() => [
|
|
623
|
+
E("span", yt, V(t.value), 1)
|
|
624
|
+
]),
|
|
625
|
+
_: 1
|
|
626
|
+
}, 16),
|
|
627
|
+
r.value ? (k(), C(e(ne), {
|
|
628
|
+
key: 0,
|
|
629
|
+
type: "info",
|
|
630
|
+
variant: "soft",
|
|
631
|
+
description: e(i)("article.address-moving")
|
|
632
|
+
}, null, 8, ["description"])) : L("", !0)
|
|
633
|
+
]));
|
|
634
|
+
}
|
|
635
|
+
}), _t = /* @__PURE__ */ j(xt, [["__scopeId", "data-v-5da20e5e"]]), kt = { class: "wx-article-tags" }, $t = {
|
|
636
|
+
key: 0,
|
|
637
|
+
class: "wx-article-tags__chips"
|
|
638
|
+
}, Tt = { class: "wx-article-tags__pick" }, At = 250, St = /* @__PURE__ */ z({
|
|
639
|
+
name: "WxArticleTags",
|
|
640
|
+
__name: "ArticleTags",
|
|
641
|
+
props: /* @__PURE__ */ ue({
|
|
642
|
+
disabled: { type: Boolean, default: !1 }
|
|
643
|
+
}, {
|
|
644
|
+
modelValue: { default: () => [] },
|
|
645
|
+
modelModifiers: {}
|
|
646
|
+
}),
|
|
647
|
+
emits: ["update:modelValue"],
|
|
648
|
+
setup(n) {
|
|
649
|
+
const l = n, o = re(n, "modelValue"), i = K(), t = G(i), a = Q();
|
|
650
|
+
F();
|
|
651
|
+
const r = H("webx-blog"), u = Z(), s = T(() => l.disabled || a?.disabled.value === !0), v = S(/* @__PURE__ */ new Map()), c = S([]), m = S(""), x = S(!1);
|
|
652
|
+
let w;
|
|
653
|
+
X(
|
|
654
|
+
() => a?.article.value?.tags,
|
|
655
|
+
(p) => {
|
|
656
|
+
const N = new Map(v.value);
|
|
657
|
+
for (const I of p ?? []) N.set(I.id, I.title);
|
|
658
|
+
v.value = N;
|
|
659
|
+
},
|
|
660
|
+
{ immediate: !0, deep: !0 }
|
|
661
|
+
);
|
|
662
|
+
const h = T(
|
|
663
|
+
() => o.value.map((p) => ({ id: p, title: v.value.get(p) ?? `#${p}` }))
|
|
664
|
+
), f = T(
|
|
665
|
+
() => c.value.filter((p) => !o.value.includes(p.id)).map((p) => ({
|
|
666
|
+
// The count is part of the label rather than a column: a select draws a line of text, and
|
|
667
|
+
// the number is what the reader is choosing between two near-identical words on.
|
|
668
|
+
label: r("article.tag-option", { title: p.title, count: p.articles_count }),
|
|
669
|
+
value: p.id
|
|
670
|
+
}))
|
|
671
|
+
), M = T(() => {
|
|
672
|
+
const p = m.value.trim();
|
|
673
|
+
if (p === "") return null;
|
|
674
|
+
const N = (I) => I.toLowerCase() === p.toLowerCase();
|
|
675
|
+
return c.value.some((I) => N(I.title)) ? null : p;
|
|
676
|
+
});
|
|
677
|
+
async function D() {
|
|
678
|
+
try {
|
|
679
|
+
c.value = await t.tags(m.value);
|
|
680
|
+
const p = new Map(v.value);
|
|
681
|
+
for (const N of c.value) p.set(N.id, N.title);
|
|
682
|
+
v.value = p;
|
|
683
|
+
} catch (p) {
|
|
684
|
+
U.danger(u(p));
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
function _(p) {
|
|
688
|
+
m.value = p, clearTimeout(w), w = setTimeout(() => {
|
|
689
|
+
D();
|
|
690
|
+
}, At);
|
|
691
|
+
}
|
|
692
|
+
function y(p) {
|
|
693
|
+
typeof p != "number" || o.value.includes(p) || (o.value = [...o.value, p], m.value = "");
|
|
694
|
+
}
|
|
695
|
+
function $(p) {
|
|
696
|
+
o.value = o.value.filter((N) => N !== p);
|
|
697
|
+
}
|
|
698
|
+
async function P() {
|
|
699
|
+
const p = M.value;
|
|
700
|
+
if (!(p === null || x.value)) {
|
|
701
|
+
x.value = !0;
|
|
702
|
+
try {
|
|
703
|
+
const N = await t.createTag({ title: p });
|
|
704
|
+
v.value = new Map(v.value).set(N.id, N.title), c.value = [N, ...c.value], y(N.id);
|
|
705
|
+
} catch (N) {
|
|
706
|
+
U.danger(u(N));
|
|
707
|
+
} finally {
|
|
708
|
+
x.value = !1;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return X(
|
|
713
|
+
() => a?.article.value?.id,
|
|
714
|
+
() => {
|
|
715
|
+
D();
|
|
716
|
+
},
|
|
717
|
+
{ immediate: !0 }
|
|
718
|
+
), de(() => clearTimeout(w)), (p, N) => (k(), R("div", kt, [
|
|
719
|
+
h.value.length > 0 ? (k(), R("div", $t, [
|
|
720
|
+
(k(!0), R(Y, null, ce(h.value, (I) => (k(), C(e(q), {
|
|
721
|
+
key: I.id,
|
|
722
|
+
type: "default",
|
|
723
|
+
closable: !s.value,
|
|
724
|
+
"close-label": e(r)("article.tag-remove"),
|
|
725
|
+
onClose: (oe) => $(I.id)
|
|
726
|
+
}, {
|
|
727
|
+
default: g(() => [
|
|
728
|
+
W(V(I.title), 1)
|
|
729
|
+
]),
|
|
730
|
+
_: 2
|
|
731
|
+
}, 1032, ["closable", "close-label", "onClose"]))), 128))
|
|
732
|
+
])) : (k(), C(e(ve), {
|
|
733
|
+
key: 1,
|
|
734
|
+
size: "sm",
|
|
735
|
+
tone: "muted"
|
|
736
|
+
}, {
|
|
737
|
+
default: g(() => [
|
|
738
|
+
W(V(e(r)("article.tags-empty")), 1)
|
|
739
|
+
]),
|
|
740
|
+
_: 1
|
|
741
|
+
})),
|
|
742
|
+
E("div", Tt, [
|
|
743
|
+
b(e(ee), {
|
|
744
|
+
"model-value": null,
|
|
745
|
+
options: f.value,
|
|
746
|
+
placeholder: e(r)("article.tag-add"),
|
|
747
|
+
"empty-text": e(r)("article.tag-nothing"),
|
|
748
|
+
disabled: s.value,
|
|
749
|
+
filterable: "",
|
|
750
|
+
teleport: "",
|
|
751
|
+
"aria-label": e(r)("article.tag-add"),
|
|
752
|
+
onSearch: _,
|
|
753
|
+
"onUpdate:modelValue": y
|
|
754
|
+
}, null, 8, ["options", "placeholder", "empty-text", "disabled", "aria-label"]),
|
|
755
|
+
M.value ? (k(), C(e(O), {
|
|
756
|
+
key: 0,
|
|
757
|
+
variant: "outline",
|
|
758
|
+
icon: "plus",
|
|
759
|
+
loading: x.value,
|
|
760
|
+
disabled: s.value,
|
|
761
|
+
onClick: P
|
|
762
|
+
}, {
|
|
763
|
+
default: g(() => [
|
|
764
|
+
W(V(e(r)("article.tag-create", { title: M.value })), 1)
|
|
765
|
+
]),
|
|
766
|
+
_: 1
|
|
767
|
+
}, 8, ["loading", "disabled"])) : L("", !0)
|
|
768
|
+
])
|
|
769
|
+
]));
|
|
770
|
+
}
|
|
771
|
+
}), Vt = /* @__PURE__ */ j(St, [["__scopeId", "data-v-faf5adec"]]), Ct = /* @__PURE__ */ z({
|
|
772
|
+
name: "WxArticleUnpublish",
|
|
773
|
+
__name: "ArticleUnpublish",
|
|
774
|
+
setup(n) {
|
|
775
|
+
const l = K(), o = G(l), i = Q();
|
|
776
|
+
F();
|
|
777
|
+
const t = H("webx-blog"), a = Z(), r = S(!1), u = T(() => {
|
|
778
|
+
const c = i?.article.value?.status;
|
|
779
|
+
return c === "published" || c === "modified" || c === "scheduled";
|
|
780
|
+
}), s = T(() => i?.disabled.value === !0 || r.value);
|
|
781
|
+
async function v() {
|
|
782
|
+
const c = i?.article.value;
|
|
783
|
+
if (!(!c || !await te({
|
|
784
|
+
title: t("article.unpublish-title", { title: c.title }),
|
|
785
|
+
message: c.status === "scheduled" ? t("article.unpublish-waiting") : t("article.unpublish-text"),
|
|
786
|
+
confirmText: t("panel.unpublish"),
|
|
787
|
+
cancelText: t("panel.cancel"),
|
|
788
|
+
tone: "danger"
|
|
789
|
+
}))) {
|
|
790
|
+
r.value = !0;
|
|
791
|
+
try {
|
|
792
|
+
await o.unpublish(c.id), await i?.reload(), U.success(t("panel.unpublished-done"));
|
|
793
|
+
} catch (x) {
|
|
794
|
+
U.danger(a(x));
|
|
795
|
+
} finally {
|
|
796
|
+
r.value = !1;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return (c, m) => u.value && e(i)?.canManage ? (k(), C(e(J), {
|
|
801
|
+
key: 0,
|
|
802
|
+
class: "wx-article-unpublish",
|
|
803
|
+
help: e(t)("article.unpublish-help")
|
|
804
|
+
}, {
|
|
805
|
+
default: g(() => [
|
|
806
|
+
b(e(O), {
|
|
807
|
+
variant: "outline",
|
|
808
|
+
type: "danger",
|
|
809
|
+
icon: "eye-off",
|
|
810
|
+
loading: r.value,
|
|
811
|
+
disabled: s.value,
|
|
812
|
+
onClick: v
|
|
813
|
+
}, {
|
|
814
|
+
default: g(() => [
|
|
815
|
+
W(V(e(t)("panel.unpublish")), 1)
|
|
816
|
+
]),
|
|
817
|
+
_: 1
|
|
818
|
+
}, 8, ["loading", "disabled"])
|
|
819
|
+
]),
|
|
820
|
+
_: 1
|
|
821
|
+
}, 8, ["help"])) : L("", !0);
|
|
822
|
+
}
|
|
823
|
+
}), Wt = /* @__PURE__ */ j(Ct, [["__scopeId", "data-v-c311cff2"]]);
|
|
824
|
+
function Nt(n = "/blog") {
|
|
825
|
+
return {
|
|
826
|
+
api: "blog/rubrics",
|
|
827
|
+
path: `${n}/rubrics`,
|
|
828
|
+
name: "webx.blog.rubrics",
|
|
829
|
+
module: "rubrics",
|
|
830
|
+
screen: "blog.category-form",
|
|
831
|
+
manage: "blog.taxonomy.manage",
|
|
832
|
+
count: "articles_count",
|
|
833
|
+
items: (l) => ({ path: `${n}/articles`, query: { rubric: String(l) } }),
|
|
834
|
+
words: {
|
|
835
|
+
new: "webx-blog::rubric.new",
|
|
836
|
+
empty: "webx-blog::rubric.empty",
|
|
837
|
+
"empty-help": "webx-blog::rubric.empty-help",
|
|
838
|
+
order: "webx-blog::rubric.order",
|
|
839
|
+
hidden: "webx-blog::rubric.hidden",
|
|
840
|
+
"no-address": "webx-blog::rubric.no-address",
|
|
841
|
+
count: "webx-blog::rubric.articles",
|
|
842
|
+
"show-items": "webx-blog::rubric.show-articles",
|
|
843
|
+
"delete-blocked": "webx-blog::rubric.delete-blocked",
|
|
844
|
+
"delete-text": "webx-blog::rubric.delete-text",
|
|
845
|
+
deleted: "webx-blog::rubric.deleted",
|
|
846
|
+
saved: "webx-blog::rubric.saved",
|
|
847
|
+
"field-title": "webx-blog::rubric.field-title",
|
|
848
|
+
"field-slug": "webx-blog::rubric.field-slug",
|
|
849
|
+
"address-moving": "webx-blog::rubric.address-moving"
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
function Ht(n = {}) {
|
|
854
|
+
const l = n.path ?? "/blog";
|
|
855
|
+
return [
|
|
856
|
+
{
|
|
857
|
+
id: "articles",
|
|
858
|
+
path: `${l}/articles`,
|
|
859
|
+
routes: [
|
|
860
|
+
// The section's own path travels as a prop, so a panel that mounted the blog somewhere
|
|
861
|
+
// else still links between its screens correctly.
|
|
862
|
+
{
|
|
863
|
+
path: `${l}/articles`,
|
|
864
|
+
name: "webx.blog.articles",
|
|
865
|
+
component: () => import("./ArticlesPage-CI-Nwhpy.js"),
|
|
866
|
+
props: { base: l }
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
path: `${l}/articles/:id(\\d+)`,
|
|
870
|
+
name: "webx.blog.articles.edit",
|
|
871
|
+
component: () => import("./ArticleEditorPage-DViFCNvm.js"),
|
|
872
|
+
props: { base: l }
|
|
873
|
+
}
|
|
874
|
+
],
|
|
875
|
+
/*
|
|
876
|
+
* The parts of `blog.article-form` that only this module can draw.
|
|
877
|
+
*
|
|
878
|
+
* The editor is a described screen so that a module can add a tab to it with a patch, and
|
|
879
|
+
* the price of that is that everything on it has to be a node type. Four of these are
|
|
880
|
+
* fields — the value is ids, and the control over them is a list that can be dragged or a
|
|
881
|
+
* box that makes a tag — and two only draw. Each reads the article from the editor above
|
|
882
|
+
* it rather than from the description, because a screen is a description and not a
|
|
883
|
+
* binding.
|
|
884
|
+
*
|
|
885
|
+
* The slug is here for a different reason: what it edits is an ordinary string, but the
|
|
886
|
+
* whole address is the prefix of the blog and that string, and the prefix is not in the
|
|
887
|
+
* description — it is configuration the editor was handed with the record.
|
|
888
|
+
*/
|
|
889
|
+
types: {
|
|
890
|
+
"wx-article-slug": { component: _t, kind: "field" },
|
|
891
|
+
"wx-article-author": { component: it, kind: "field" },
|
|
892
|
+
"wx-article-tags": { component: Vt, kind: "field" },
|
|
893
|
+
"wx-article-related": { component: bt, kind: "field" },
|
|
894
|
+
"wx-article-unpublish": { component: Wt, kind: "display" },
|
|
895
|
+
"wx-article-history": { component: ht, kind: "display" }
|
|
896
|
+
}
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
id: "rubrics",
|
|
900
|
+
path: `${l}/rubrics`,
|
|
901
|
+
// The list and the page of one rubric are the panel's shared category screens (§3.6 of
|
|
902
|
+
// the services spec); what is the blog's is the description they are handed.
|
|
903
|
+
routes: Ee(Nt(l))
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
id: "tags",
|
|
907
|
+
path: `${l}/tags`,
|
|
908
|
+
routes: [
|
|
909
|
+
{
|
|
910
|
+
path: `${l}/tags`,
|
|
911
|
+
name: "webx.blog.tags",
|
|
912
|
+
component: () => import("./TagsPage-rFfpCqPs.js"),
|
|
913
|
+
props: { base: l }
|
|
914
|
+
}
|
|
915
|
+
]
|
|
916
|
+
},
|
|
917
|
+
{
|
|
918
|
+
// Only on a site with author pages (§19): the server leaves the module out of the manifest
|
|
919
|
+
// otherwise, and a module the manifest does not name is never drawn.
|
|
920
|
+
id: "authors",
|
|
921
|
+
path: `${l}/authors`,
|
|
922
|
+
routes: [
|
|
923
|
+
{
|
|
924
|
+
path: `${l}/authors`,
|
|
925
|
+
name: "webx.blog.authors",
|
|
926
|
+
component: () => import("./AuthorsPage-BN6sRqyE.js"),
|
|
927
|
+
props: { base: l }
|
|
928
|
+
}
|
|
929
|
+
]
|
|
930
|
+
}
|
|
931
|
+
];
|
|
932
|
+
}
|
|
933
|
+
function Mt(n) {
|
|
934
|
+
const l = `${n.apiPath}/blog/authors`, o = (i) => i.data;
|
|
935
|
+
return {
|
|
936
|
+
list: (i = "") => {
|
|
937
|
+
const t = i.trim() === "" ? "" : `?q=${encodeURIComponent(i.trim())}`;
|
|
938
|
+
return n.http.get(`${l}${t}`).then(o);
|
|
939
|
+
},
|
|
940
|
+
accounts: () => n.http.get(`${l}/accounts`).then(o),
|
|
941
|
+
get: (i) => n.http.get(`${l}/${i}`).then(o),
|
|
942
|
+
create: (i, t) => n.http.post(l, { user_id: i, values: t }).then(o),
|
|
943
|
+
save: (i, t) => n.http.put(`${l}/${i}`, { values: t }).then(o),
|
|
944
|
+
remove: (i) => n.http.delete(`${l}/${i}`).then(() => {
|
|
945
|
+
})
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
const Pt = {
|
|
949
|
+
key: 1,
|
|
950
|
+
class: "wx-author__account"
|
|
951
|
+
}, Ut = /* @__PURE__ */ z({
|
|
952
|
+
name: "WxAuthorPane",
|
|
953
|
+
__name: "AuthorPane",
|
|
954
|
+
props: {
|
|
955
|
+
id: {},
|
|
956
|
+
inline: { type: Boolean, default: !0 }
|
|
957
|
+
},
|
|
958
|
+
emits: ["back", "saved", "created", "removed"],
|
|
959
|
+
setup(n, { emit: l }) {
|
|
960
|
+
const o = n, i = l, t = K(), a = Mt(t), r = je(), u = Ae();
|
|
961
|
+
F();
|
|
962
|
+
const s = H("webx-blog"), v = Z(), c = S(null), m = S({}), x = S(""), w = S([]), h = S(null), f = S(!0), M = S(!1), D = S({}), _ = T(() => t.can("blog.authors.manage")), y = T(() => JSON.stringify(m.value)), $ = T(
|
|
963
|
+
() => x.value !== "" && (y.value !== x.value || h.value !== null)
|
|
964
|
+
), P = T(() => M.value ? "saving" : $.value || o.id === null ? "unsaved" : "saved"), p = T(() => {
|
|
965
|
+
const d = m.value.title, A = o.id === null ? s("author.new") : c.value?.name ?? "";
|
|
966
|
+
return Ye(d, u.active.value, A) || s("author.untitled");
|
|
967
|
+
}), N = T(
|
|
968
|
+
() => w.value.map((d) => ({
|
|
969
|
+
label: d.articles_count > 0 ? `${d.name} · ${s("author.articles", { count: d.articles_count })}` : d.name,
|
|
970
|
+
value: d.id
|
|
971
|
+
}))
|
|
972
|
+
), I = T({
|
|
973
|
+
get: () => h.value,
|
|
974
|
+
set: (d) => {
|
|
975
|
+
h.value = typeof d == "number" ? d : null;
|
|
976
|
+
const A = w.value.find((Ne) => Ne.id === h.value), B = m.value.title, se = u.list.value[0]?.code;
|
|
977
|
+
A && se && !(B?.[se] ?? "").trim() && (m.value = { ...m.value, title: { ...B ?? {}, [se]: A.name } });
|
|
978
|
+
}
|
|
979
|
+
});
|
|
980
|
+
function oe(d) {
|
|
981
|
+
c.value = d.author, m.value = d.values, x.value = JSON.stringify(d.values), h.value = null;
|
|
982
|
+
}
|
|
983
|
+
async function Ve() {
|
|
984
|
+
f.value = !0;
|
|
985
|
+
try {
|
|
986
|
+
if (o.id === null) {
|
|
987
|
+
const d = {
|
|
988
|
+
title: {},
|
|
989
|
+
slug: {},
|
|
990
|
+
role: {},
|
|
991
|
+
bio: {},
|
|
992
|
+
photo: null,
|
|
993
|
+
socials: [],
|
|
994
|
+
is_public: !1
|
|
995
|
+
};
|
|
996
|
+
m.value = d, x.value = JSON.stringify(d), w.value = await a.accounts();
|
|
997
|
+
const A = Number(r.query.account);
|
|
998
|
+
w.value.some((B) => B.id === A) && (I.value = A);
|
|
999
|
+
} else
|
|
1000
|
+
oe(await a.get(o.id));
|
|
1001
|
+
} catch (d) {
|
|
1002
|
+
U.danger(v(d)), i("back");
|
|
1003
|
+
} finally {
|
|
1004
|
+
f.value = !1;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
async function be() {
|
|
1008
|
+
if (!(M.value || !_.value)) {
|
|
1009
|
+
M.value = !0, D.value = {};
|
|
1010
|
+
try {
|
|
1011
|
+
const d = o.id === null;
|
|
1012
|
+
if (d && h.value === null) {
|
|
1013
|
+
D.value = { user_id: [s("author.account-missing")] }, U.danger(s("author.save-failed"));
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
const A = d ? await a.create(h.value, m.value) : await a.save(o.id, m.value);
|
|
1017
|
+
oe(A), U.success(s("author.saved")), i(d ? "created" : "saved", A.author);
|
|
1018
|
+
} catch (d) {
|
|
1019
|
+
const A = d.body;
|
|
1020
|
+
A?.errors ? (D.value = A.errors, U.danger(s("author.save-failed"))) : U.danger(v(d));
|
|
1021
|
+
} finally {
|
|
1022
|
+
M.value = !1;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
async function Ce() {
|
|
1027
|
+
const d = c.value;
|
|
1028
|
+
if (!(!d || !await te({
|
|
1029
|
+
title: s("author.delete-title", { name: d.name }),
|
|
1030
|
+
message: s("author.delete-text"),
|
|
1031
|
+
confirmText: s("author.delete"),
|
|
1032
|
+
cancelText: s("author.cancel"),
|
|
1033
|
+
tone: "danger"
|
|
1034
|
+
})))
|
|
1035
|
+
try {
|
|
1036
|
+
await a.remove(d.id), U.success(s("author.deleted")), x.value = y.value, h.value = null, i("removed", d.id);
|
|
1037
|
+
} catch (B) {
|
|
1038
|
+
U.danger(v(B));
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
function we(d) {
|
|
1042
|
+
$.value && d.preventDefault();
|
|
1043
|
+
}
|
|
1044
|
+
function ye(d) {
|
|
1045
|
+
(d.ctrlKey || d.metaKey) && d.key.toLowerCase() === "s" && (d.preventDefault(), ($.value || o.id === null) && be());
|
|
1046
|
+
}
|
|
1047
|
+
Oe(ye), he(() => {
|
|
1048
|
+
Ve(), window.addEventListener("beforeunload", we);
|
|
1049
|
+
}), de(() => {
|
|
1050
|
+
window.removeEventListener("beforeunload", we);
|
|
1051
|
+
});
|
|
1052
|
+
async function xe() {
|
|
1053
|
+
return !$.value || !_.value ? !0 : await te({
|
|
1054
|
+
title: s("author.leave-title"),
|
|
1055
|
+
message: s("author.leave-text"),
|
|
1056
|
+
confirmText: s("author.leave"),
|
|
1057
|
+
cancelText: s("author.cancel"),
|
|
1058
|
+
tone: "danger"
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
Ge(
|
|
1062
|
+
async (d, A) => d.query.author === A.query.author ? !0 : await xe()
|
|
1063
|
+
), Je(xe);
|
|
1064
|
+
const We = T(() => {
|
|
1065
|
+
const d = [], A = c.value;
|
|
1066
|
+
return A?.open && A.url && d.push({
|
|
1067
|
+
key: "open",
|
|
1068
|
+
label: s("author.open-page"),
|
|
1069
|
+
icon: "external-link",
|
|
1070
|
+
run: () => {
|
|
1071
|
+
window.open(A.url, "_blank", "noopener");
|
|
1072
|
+
}
|
|
1073
|
+
}), _.value && A !== null && d.push({
|
|
1074
|
+
key: "delete",
|
|
1075
|
+
label: s("author.delete"),
|
|
1076
|
+
icon: "trash",
|
|
1077
|
+
danger: !0,
|
|
1078
|
+
menu: !0,
|
|
1079
|
+
run: () => {
|
|
1080
|
+
Ce();
|
|
1081
|
+
}
|
|
1082
|
+
}), d;
|
|
1083
|
+
});
|
|
1084
|
+
return (d, A) => (k(), R("div", {
|
|
1085
|
+
class: "wx-author",
|
|
1086
|
+
onKeydown: ye
|
|
1087
|
+
}, [
|
|
1088
|
+
f.value ? (k(), C(e(Te), {
|
|
1089
|
+
key: 0,
|
|
1090
|
+
class: "wx-author__ghost",
|
|
1091
|
+
title: "",
|
|
1092
|
+
rows: 6
|
|
1093
|
+
})) : (k(), R(Y, { key: 1 }, [
|
|
1094
|
+
b(e(ze), {
|
|
1095
|
+
level: 3,
|
|
1096
|
+
back: !o.inline,
|
|
1097
|
+
"back-label": e(s)("author.back"),
|
|
1098
|
+
title: p.value,
|
|
1099
|
+
actions: We.value,
|
|
1100
|
+
"collapse-below": 480,
|
|
1101
|
+
onBack: A[0] || (A[0] = (B) => i("back"))
|
|
1102
|
+
}, De({ _: 2 }, [
|
|
1103
|
+
c.value && !c.value.open ? {
|
|
1104
|
+
name: "title-after",
|
|
1105
|
+
fn: g(() => [
|
|
1106
|
+
b(e(q), { dot: "" }, {
|
|
1107
|
+
default: g(() => [
|
|
1108
|
+
W(V(e(s)("author.page-closed")), 1)
|
|
1109
|
+
]),
|
|
1110
|
+
_: 1
|
|
1111
|
+
})
|
|
1112
|
+
]),
|
|
1113
|
+
key: "0"
|
|
1114
|
+
} : void 0
|
|
1115
|
+
]), 1032, ["back", "back-label", "title", "actions"]),
|
|
1116
|
+
o.id === null ? (k(), C(e(qe), { key: 0 }, {
|
|
1117
|
+
default: g(() => [
|
|
1118
|
+
b(e(J), {
|
|
1119
|
+
label: e(s)("author.account"),
|
|
1120
|
+
help: w.value.length === 0 ? e(s)("author.no-accounts") : e(s)("author.account-help"),
|
|
1121
|
+
error: D.value.user_id?.[0],
|
|
1122
|
+
required: ""
|
|
1123
|
+
}, {
|
|
1124
|
+
default: g(() => [
|
|
1125
|
+
b(e(ee), {
|
|
1126
|
+
modelValue: I.value,
|
|
1127
|
+
"onUpdate:modelValue": A[1] || (A[1] = (B) => I.value = B),
|
|
1128
|
+
options: N.value,
|
|
1129
|
+
disabled: !_.value || M.value || w.value.length === 0,
|
|
1130
|
+
filterable: "",
|
|
1131
|
+
teleport: "",
|
|
1132
|
+
"aria-label": e(s)("author.account")
|
|
1133
|
+
}, null, 8, ["modelValue", "options", "disabled", "aria-label"])
|
|
1134
|
+
]),
|
|
1135
|
+
_: 1
|
|
1136
|
+
}, 8, ["label", "help", "error"])
|
|
1137
|
+
]),
|
|
1138
|
+
_: 1
|
|
1139
|
+
})) : c.value?.user ? (k(), R("p", Pt, V(e(s)("author.account")) + ": " + V(c.value.user.name), 1)) : L("", !0),
|
|
1140
|
+
b(e(Ke), {
|
|
1141
|
+
modelValue: m.value,
|
|
1142
|
+
"onUpdate:modelValue": A[2] || (A[2] = (B) => m.value = B),
|
|
1143
|
+
name: "blog.author-form",
|
|
1144
|
+
errors: D.value,
|
|
1145
|
+
disabled: !_.value || M.value
|
|
1146
|
+
}, null, 8, ["modelValue", "errors", "disabled"]),
|
|
1147
|
+
_.value ? (k(), C(e(et), { key: 2 }, {
|
|
1148
|
+
state: g(() => [
|
|
1149
|
+
b(e(He), { state: P.value }, null, 8, ["state"])
|
|
1150
|
+
]),
|
|
1151
|
+
default: g(() => [
|
|
1152
|
+
b(e(O), {
|
|
1153
|
+
type: "primary",
|
|
1154
|
+
loading: M.value,
|
|
1155
|
+
disabled: !$.value && o.id !== null,
|
|
1156
|
+
onClick: be
|
|
1157
|
+
}, {
|
|
1158
|
+
default: g(() => [
|
|
1159
|
+
W(V(e(s)("author.save")), 1)
|
|
1160
|
+
]),
|
|
1161
|
+
_: 1
|
|
1162
|
+
}, 8, ["loading", "disabled"])
|
|
1163
|
+
]),
|
|
1164
|
+
_: 1
|
|
1165
|
+
})) : L("", !0)
|
|
1166
|
+
], 64))
|
|
1167
|
+
], 32));
|
|
1168
|
+
}
|
|
1169
|
+
}), Ft = /* @__PURE__ */ j(Ut, [["__scopeId", "data-v-60f7aa2e"]]), jt = /* @__PURE__ */ z({
|
|
1170
|
+
__name: "TagCreateDialog",
|
|
1171
|
+
setup(n) {
|
|
1172
|
+
const { open: l, resolve: o, dismiss: i } = ge(), t = K(), a = G(t);
|
|
1173
|
+
F();
|
|
1174
|
+
const r = H("webx-blog"), u = S(""), s = S(""), v = S(!1), c = S({}), m = ke("field");
|
|
1175
|
+
he(async () => {
|
|
1176
|
+
await $e(), m.value?.querySelector("input")?.focus();
|
|
1177
|
+
});
|
|
1178
|
+
async function x() {
|
|
1179
|
+
if (!(u.value.trim() === "" || v.value)) {
|
|
1180
|
+
v.value = !0, c.value = {};
|
|
1181
|
+
try {
|
|
1182
|
+
o(
|
|
1183
|
+
await a.createTag({
|
|
1184
|
+
title: u.value.trim(),
|
|
1185
|
+
...s.value.trim() === "" ? {} : { slug: s.value.trim() }
|
|
1186
|
+
})
|
|
1187
|
+
);
|
|
1188
|
+
} catch (w) {
|
|
1189
|
+
c.value = w.body?.errors ?? {};
|
|
1190
|
+
} finally {
|
|
1191
|
+
v.value = !1;
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
return (w, h) => (k(), C(e(me), {
|
|
1196
|
+
open: e(l),
|
|
1197
|
+
"onUpdate:open": h[3] || (h[3] = (f) => pe(l) ? l.value = f : null),
|
|
1198
|
+
title: e(r)("tag.new-title"),
|
|
1199
|
+
width: 440
|
|
1200
|
+
}, {
|
|
1201
|
+
footer: g(() => [
|
|
1202
|
+
b(e(fe), { size: "sm" }, {
|
|
1203
|
+
default: g(() => [
|
|
1204
|
+
b(e(O), {
|
|
1205
|
+
variant: "outline",
|
|
1206
|
+
onClick: h[2] || (h[2] = (f) => e(i)())
|
|
1207
|
+
}, {
|
|
1208
|
+
default: g(() => [
|
|
1209
|
+
W(V(e(r)("tag.cancel")), 1)
|
|
1210
|
+
]),
|
|
1211
|
+
_: 1
|
|
1212
|
+
}),
|
|
1213
|
+
b(e(O), {
|
|
1214
|
+
type: "primary",
|
|
1215
|
+
loading: v.value,
|
|
1216
|
+
disabled: u.value.trim() === "",
|
|
1217
|
+
onClick: x
|
|
1218
|
+
}, {
|
|
1219
|
+
default: g(() => [
|
|
1220
|
+
W(V(e(r)("tag.create")), 1)
|
|
1221
|
+
]),
|
|
1222
|
+
_: 1
|
|
1223
|
+
}, 8, ["loading", "disabled"])
|
|
1224
|
+
]),
|
|
1225
|
+
_: 1
|
|
1226
|
+
})
|
|
1227
|
+
]),
|
|
1228
|
+
default: g(() => [
|
|
1229
|
+
b(e(J), {
|
|
1230
|
+
label: e(r)("tag.field-title"),
|
|
1231
|
+
error: c.value.title?.[0],
|
|
1232
|
+
required: ""
|
|
1233
|
+
}, {
|
|
1234
|
+
default: g(() => [
|
|
1235
|
+
E("div", {
|
|
1236
|
+
ref_key: "field",
|
|
1237
|
+
ref: m
|
|
1238
|
+
}, [
|
|
1239
|
+
b(e(ae), {
|
|
1240
|
+
modelValue: u.value,
|
|
1241
|
+
"onUpdate:modelValue": h[0] || (h[0] = (f) => u.value = f),
|
|
1242
|
+
"aria-label": e(r)("tag.field-title"),
|
|
1243
|
+
onKeyup: ie(x, ["enter"])
|
|
1244
|
+
}, null, 8, ["modelValue", "aria-label"])
|
|
1245
|
+
], 512)
|
|
1246
|
+
]),
|
|
1247
|
+
_: 1
|
|
1248
|
+
}, 8, ["label", "error"]),
|
|
1249
|
+
b(e(J), {
|
|
1250
|
+
label: e(r)("tag.field-slug"),
|
|
1251
|
+
error: c.value.slug?.[0],
|
|
1252
|
+
help: e(r)("tag.field-slug-help")
|
|
1253
|
+
}, {
|
|
1254
|
+
default: g(() => [
|
|
1255
|
+
b(e(ae), {
|
|
1256
|
+
modelValue: s.value,
|
|
1257
|
+
"onUpdate:modelValue": h[1] || (h[1] = (f) => s.value = f),
|
|
1258
|
+
"aria-label": e(r)("tag.field-slug"),
|
|
1259
|
+
onKeyup: ie(x, ["enter"])
|
|
1260
|
+
}, null, 8, ["modelValue", "aria-label"])
|
|
1261
|
+
]),
|
|
1262
|
+
_: 1
|
|
1263
|
+
}, 8, ["label", "error", "help"])
|
|
1264
|
+
]),
|
|
1265
|
+
_: 1
|
|
1266
|
+
}, 8, ["open", "title"]));
|
|
1267
|
+
}
|
|
1268
|
+
}), It = { class: "wx-tag-merge" }, Rt = { class: "wx-tag-merge__chips" }, Dt = { class: "wx-tag-merge__redirect" }, Lt = /* @__PURE__ */ z({
|
|
1269
|
+
__name: "TagMergeDialog",
|
|
1270
|
+
props: {
|
|
1271
|
+
tags: {}
|
|
1272
|
+
},
|
|
1273
|
+
setup(n) {
|
|
1274
|
+
const l = n, { open: o, resolve: i, dismiss: t } = ge(), a = K(), r = G(a);
|
|
1275
|
+
F();
|
|
1276
|
+
const u = H("webx-blog"), s = Z(), v = S(
|
|
1277
|
+
[...l.tags].sort((y, $) => $.articles_count - y.articles_count)[0]?.id ?? 0
|
|
1278
|
+
), c = S(!1), m = S(!0), x = S(null), w = T(
|
|
1279
|
+
() => l.tags.map((y) => ({ value: y.id, label: `${y.title} · ${y.articles_count}` }))
|
|
1280
|
+
), h = T(() => l.tags.find((y) => y.id === v.value) ?? null), f = T(() => l.tags.filter((y) => y.id !== v.value)), M = T(() => f.value.reduce((y, $) => y + $.articles_count, 0)), D = T(() => f.value.map((y) => y.path).filter(Boolean));
|
|
1281
|
+
async function _() {
|
|
1282
|
+
if (!(h.value === null || f.value.length === 0 || c.value)) {
|
|
1283
|
+
c.value = !0, x.value = null;
|
|
1284
|
+
try {
|
|
1285
|
+
i(
|
|
1286
|
+
await r.mergeTags(
|
|
1287
|
+
f.value.map((y) => y.id),
|
|
1288
|
+
v.value,
|
|
1289
|
+
m.value
|
|
1290
|
+
)
|
|
1291
|
+
);
|
|
1292
|
+
} catch (y) {
|
|
1293
|
+
x.value = s(y);
|
|
1294
|
+
} finally {
|
|
1295
|
+
c.value = !1;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
return (y, $) => (k(), C(e(me), {
|
|
1300
|
+
open: e(o),
|
|
1301
|
+
"onUpdate:open": $[3] || ($[3] = (P) => pe(o) ? o.value = P : null),
|
|
1302
|
+
title: e(u)("tag.merge-title"),
|
|
1303
|
+
width: 520
|
|
1304
|
+
}, {
|
|
1305
|
+
footer: g(() => [
|
|
1306
|
+
b(e(fe), { size: "sm" }, {
|
|
1307
|
+
default: g(() => [
|
|
1308
|
+
b(e(O), {
|
|
1309
|
+
variant: "outline",
|
|
1310
|
+
onClick: $[2] || ($[2] = (P) => e(t)())
|
|
1311
|
+
}, {
|
|
1312
|
+
default: g(() => [
|
|
1313
|
+
W(V(e(u)("tag.cancel")), 1)
|
|
1314
|
+
]),
|
|
1315
|
+
_: 1
|
|
1316
|
+
}),
|
|
1317
|
+
b(e(O), {
|
|
1318
|
+
type: "primary",
|
|
1319
|
+
loading: c.value,
|
|
1320
|
+
disabled: f.value.length === 0,
|
|
1321
|
+
onClick: _
|
|
1322
|
+
}, {
|
|
1323
|
+
default: g(() => [
|
|
1324
|
+
W(V(e(u)("tag.merge-confirm")), 1)
|
|
1325
|
+
]),
|
|
1326
|
+
_: 1
|
|
1327
|
+
}, 8, ["loading", "disabled"])
|
|
1328
|
+
]),
|
|
1329
|
+
_: 1
|
|
1330
|
+
})
|
|
1331
|
+
]),
|
|
1332
|
+
default: g(() => [
|
|
1333
|
+
E("div", It, [
|
|
1334
|
+
E("div", Rt, [
|
|
1335
|
+
(k(!0), R(Y, null, ce(f.value, (P) => (k(), C(e(q), {
|
|
1336
|
+
key: P.id,
|
|
1337
|
+
size: "sm",
|
|
1338
|
+
round: ""
|
|
1339
|
+
}, {
|
|
1340
|
+
default: g(() => [
|
|
1341
|
+
W(V(P.title) + " · " + V(P.articles_count), 1)
|
|
1342
|
+
]),
|
|
1343
|
+
_: 2
|
|
1344
|
+
}, 1024))), 128)),
|
|
1345
|
+
b(e(tt), {
|
|
1346
|
+
name: "arrow-right",
|
|
1347
|
+
size: "sm"
|
|
1348
|
+
}),
|
|
1349
|
+
h.value ? (k(), C(e(q), {
|
|
1350
|
+
key: 0,
|
|
1351
|
+
type: "primary",
|
|
1352
|
+
size: "sm",
|
|
1353
|
+
round: ""
|
|
1354
|
+
}, {
|
|
1355
|
+
default: g(() => [
|
|
1356
|
+
W(V(h.value.title) + " · " + V(h.value.articles_count), 1)
|
|
1357
|
+
]),
|
|
1358
|
+
_: 1
|
|
1359
|
+
})) : L("", !0)
|
|
1360
|
+
]),
|
|
1361
|
+
b(e(J), {
|
|
1362
|
+
label: e(u)("tag.merge-keep")
|
|
1363
|
+
}, {
|
|
1364
|
+
default: g(() => [
|
|
1365
|
+
b(e(ee), {
|
|
1366
|
+
modelValue: v.value,
|
|
1367
|
+
"onUpdate:modelValue": $[0] || ($[0] = (P) => v.value = P),
|
|
1368
|
+
options: w.value,
|
|
1369
|
+
"aria-label": e(u)("tag.merge-keep")
|
|
1370
|
+
}, null, 8, ["modelValue", "options", "aria-label"])
|
|
1371
|
+
]),
|
|
1372
|
+
_: 1
|
|
1373
|
+
}, 8, ["label"]),
|
|
1374
|
+
E("div", Dt, [
|
|
1375
|
+
b(e(at), {
|
|
1376
|
+
modelValue: m.value,
|
|
1377
|
+
"onUpdate:modelValue": $[1] || ($[1] = (P) => m.value = P),
|
|
1378
|
+
label: e(u)("tag.merge-redirect")
|
|
1379
|
+
}, null, 8, ["modelValue", "label"]),
|
|
1380
|
+
b(e(ve), {
|
|
1381
|
+
size: "sm",
|
|
1382
|
+
tone: "muted"
|
|
1383
|
+
}, {
|
|
1384
|
+
default: g(() => [
|
|
1385
|
+
W(V(D.value.length === 0 ? e(u)("tag.merge-redirect-none") : e(u)("tag.merge-redirect-help", { addresses: D.value.join(", ") })), 1)
|
|
1386
|
+
]),
|
|
1387
|
+
_: 1
|
|
1388
|
+
})
|
|
1389
|
+
]),
|
|
1390
|
+
b(e(ne), {
|
|
1391
|
+
type: "warning",
|
|
1392
|
+
variant: "soft",
|
|
1393
|
+
description: e(u)("tag.merge-warning", {
|
|
1394
|
+
count: M.value,
|
|
1395
|
+
tag: h.value?.title ?? "",
|
|
1396
|
+
merged: f.value.length
|
|
1397
|
+
})
|
|
1398
|
+
}, null, 8, ["description"]),
|
|
1399
|
+
x.value ? (k(), C(e(ne), {
|
|
1400
|
+
key: 0,
|
|
1401
|
+
type: "danger",
|
|
1402
|
+
variant: "soft",
|
|
1403
|
+
description: x.value
|
|
1404
|
+
}, null, 8, ["description"])) : L("", !0)
|
|
1405
|
+
])
|
|
1406
|
+
]),
|
|
1407
|
+
_: 1
|
|
1408
|
+
}, 8, ["open", "title"]));
|
|
1409
|
+
}
|
|
1410
|
+
}), Gt = /* @__PURE__ */ j(Lt, [["__scopeId", "data-v-aa68b3a8"]]), Jt = /* @__PURE__ */ z({
|
|
1411
|
+
__name: "ArticleCreateDialog",
|
|
1412
|
+
setup(n) {
|
|
1413
|
+
const { open: l, resolve: o, dismiss: i } = ge(), t = K(), a = G(t);
|
|
1414
|
+
F();
|
|
1415
|
+
const r = H("webx-blog"), u = S(""), s = S(!1), v = S({}), c = ke("field");
|
|
1416
|
+
he(async () => {
|
|
1417
|
+
await $e(), c.value?.querySelector("input")?.focus();
|
|
1418
|
+
});
|
|
1419
|
+
async function m() {
|
|
1420
|
+
if (!(u.value.trim() === "" || s.value)) {
|
|
1421
|
+
s.value = !0, v.value = {};
|
|
1422
|
+
try {
|
|
1423
|
+
o(await a.create({ title: u.value.trim() }));
|
|
1424
|
+
} catch (x) {
|
|
1425
|
+
v.value = x.body?.errors ?? {};
|
|
1426
|
+
} finally {
|
|
1427
|
+
s.value = !1;
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
return (x, w) => (k(), C(e(me), {
|
|
1432
|
+
open: e(l),
|
|
1433
|
+
"onUpdate:open": w[2] || (w[2] = (h) => pe(l) ? l.value = h : null),
|
|
1434
|
+
title: e(r)("panel.new-title"),
|
|
1435
|
+
width: 440
|
|
1436
|
+
}, {
|
|
1437
|
+
footer: g(() => [
|
|
1438
|
+
b(e(fe), { size: "sm" }, {
|
|
1439
|
+
default: g(() => [
|
|
1440
|
+
b(e(O), {
|
|
1441
|
+
variant: "outline",
|
|
1442
|
+
onClick: w[1] || (w[1] = (h) => e(i)())
|
|
1443
|
+
}, {
|
|
1444
|
+
default: g(() => [
|
|
1445
|
+
W(V(e(r)("panel.cancel")), 1)
|
|
1446
|
+
]),
|
|
1447
|
+
_: 1
|
|
1448
|
+
}),
|
|
1449
|
+
b(e(O), {
|
|
1450
|
+
type: "primary",
|
|
1451
|
+
loading: s.value,
|
|
1452
|
+
disabled: u.value.trim() === "",
|
|
1453
|
+
onClick: m
|
|
1454
|
+
}, {
|
|
1455
|
+
default: g(() => [
|
|
1456
|
+
W(V(e(r)("panel.create")), 1)
|
|
1457
|
+
]),
|
|
1458
|
+
_: 1
|
|
1459
|
+
}, 8, ["loading", "disabled"])
|
|
1460
|
+
]),
|
|
1461
|
+
_: 1
|
|
1462
|
+
})
|
|
1463
|
+
]),
|
|
1464
|
+
default: g(() => [
|
|
1465
|
+
b(e(J), {
|
|
1466
|
+
label: e(r)("panel.field-title"),
|
|
1467
|
+
error: v.value.title?.[0] ?? v.value.slug?.[0],
|
|
1468
|
+
required: ""
|
|
1469
|
+
}, {
|
|
1470
|
+
default: g(() => [
|
|
1471
|
+
E("div", {
|
|
1472
|
+
ref_key: "field",
|
|
1473
|
+
ref: c
|
|
1474
|
+
}, [
|
|
1475
|
+
b(e(ae), {
|
|
1476
|
+
modelValue: u.value,
|
|
1477
|
+
"onUpdate:modelValue": w[0] || (w[0] = (h) => u.value = h),
|
|
1478
|
+
"aria-label": e(r)("panel.field-title"),
|
|
1479
|
+
onKeyup: ie(m, ["enter"])
|
|
1480
|
+
}, null, 8, ["modelValue", "aria-label"])
|
|
1481
|
+
], 512)
|
|
1482
|
+
]),
|
|
1483
|
+
_: 1
|
|
1484
|
+
}, 8, ["label", "error"])
|
|
1485
|
+
]),
|
|
1486
|
+
_: 1
|
|
1487
|
+
}, 8, ["open", "title"]));
|
|
1488
|
+
}
|
|
1489
|
+
}), Zt = le(() => import("./ArticlesPage-CI-Nwhpy.js")), Qt = le(() => import("./TagsPage-rFfpCqPs.js")), Xt = le(() => import("./AuthorsPage-BN6sRqyE.js")), Yt = le(() => import("./ArticleEditorPage-DViFCNvm.js"));
|
|
1490
|
+
export {
|
|
1491
|
+
Ft as A,
|
|
1492
|
+
Gt as T,
|
|
1493
|
+
Yt as W,
|
|
1494
|
+
Jt as _,
|
|
1495
|
+
j as a,
|
|
1496
|
+
jt as b,
|
|
1497
|
+
G as c,
|
|
1498
|
+
Mt as d,
|
|
1499
|
+
it as e,
|
|
1500
|
+
ht as f,
|
|
1501
|
+
bt as g,
|
|
1502
|
+
_t as h,
|
|
1503
|
+
Vt as i,
|
|
1504
|
+
Wt as j,
|
|
1505
|
+
Zt as k,
|
|
1506
|
+
Xt as l,
|
|
1507
|
+
Qt as m,
|
|
1508
|
+
Se as n,
|
|
1509
|
+
Ht as o,
|
|
1510
|
+
Kt as p,
|
|
1511
|
+
lt as q,
|
|
1512
|
+
Nt as r,
|
|
1513
|
+
Q as s,
|
|
1514
|
+
F as u
|
|
1515
|
+
};
|
|
1516
|
+
//# sourceMappingURL=index-DqN5h0Ej.js.map
|