@webx-ui/module-blog 0.1.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/index.js ADDED
@@ -0,0 +1,2991 @@
1
+ import { provide as mt, inject as ft, defineComponent as ee, computed as b, openBlock as p, createElementBlock as K, createVNode as n, unref as e, withCtx as a, createBlock as V, createTextVNode as g, toDisplayString as f, createCommentVNode as I, useModel as Be, mergeModels as Ne, ref as z, useTemplateRef as We, watch as oe, onMounted as Le, onBeforeUnmount as Fe, Fragment as ne, createElementVNode as q, renderList as ze, normalizeClass as Ae, nextTick as Ke, isRef as He, withKeys as Ce, createSlots as st, resolveDynamicComponent as tt, mergeProps as gt } from "vue";
2
+ import { useAdmin as se, useTranslate as te, useDates as bt, useErrorText as me, WxBackButton as ht, WxScreen as yt, WxDate as De, WxListScreen as je, WxRowMenu as Ie } from "@webx-ui/module-admin";
3
+ import { useLocales as Ge, WxFormItem as ge, WxText as G, WxAlert as Se, WxSelect as be, useElementWidth as rt, localizedValue as _t, confirm as pe, WxSkeleton as Ue, WxBreadcrumb as wt, WxBreadcrumbItem as at, WxBadge as re, WxDropdown as xt, WxDropdownItem as lt, WxAction as Re, WxButton as F, WxActionBar as ot, toast as L, WxEmpty as Oe, WxSortableList as Je, useModal as Ze, WxDialog as Qe, WxInput as $e, WxSpace as Xe, createModal as Ee, WxTable as ut, WxIcon as Y, WxTooltip as Ye, WxHeading as kt, WxTextarea as $t, WxSwitch as Tt, WxCard as Vt, WxListDetail as At, WxCheckbox as Ct } from "@webx-ui/core";
4
+ import { useRoute as qe, useRouter as Me, onBeforeRouteLeave as St } from "vue-router";
5
+ import { provideBlocksPreview as Wt } from "@webx-ui/module-blocks";
6
+ const dt = /* @__PURE__ */ Symbol("wx-article-editor");
7
+ function zt(y) {
8
+ mt(dt, y);
9
+ }
10
+ function Te() {
11
+ return ft(dt, null);
12
+ }
13
+ const Rt = {
14
+ module: {
15
+ group: "Blog",
16
+ articles: "Articles",
17
+ rubrics: "Rubrics",
18
+ tags: "Tags"
19
+ },
20
+ panel: {
21
+ new: "New article",
22
+ search: "Search by title or address",
23
+ empty: "No articles yet.",
24
+ "empty-search": "Nothing matches that.",
25
+ "empty-bin": "The bin is empty.",
26
+ "column-title": "Title",
27
+ "column-rubrics": "Rubrics",
28
+ "column-author": "Author",
29
+ "column-date": "Date",
30
+ "column-status": "Status",
31
+ "column-deleted": "Deleted",
32
+ "status-draft": "Draft",
33
+ "status-scheduled": "Scheduled",
34
+ "status-published": "Live",
35
+ "status-modified": "Live",
36
+ "status-unpublished": "Off the site",
37
+ edits: "edits",
38
+ pinned: "Pinned to the top",
39
+ "no-address": "The address appears when it is published",
40
+ "no-author": "Nobody",
41
+ "view-all": "All",
42
+ "view-published": "Live",
43
+ "view-scheduled": "Scheduled",
44
+ "view-draft": "Drafts",
45
+ "view-unpublished": "Off the site",
46
+ bin: "Bin",
47
+ "any-rubric": "Any rubric",
48
+ "any-tag": "Any tag",
49
+ "any-author": "Any author",
50
+ open: "Open",
51
+ "open-on-site": "Open on the site",
52
+ "copy-address": "Copy the address",
53
+ pin: "Pin to the top",
54
+ unpin: "Unpin",
55
+ publish: "Publish",
56
+ unpublish: "Take off the site",
57
+ delete: "Delete",
58
+ restore: "Restore",
59
+ cancel: "Cancel",
60
+ "delete-title": "Delete “:title”?",
61
+ "delete-text": "It goes to the bin and comes off the site, and its address is free again.",
62
+ deleted: "The article is in the bin.",
63
+ restored: "The article is back.",
64
+ published: "The article is on the site.",
65
+ "unpublished-done": "The article is off the site.",
66
+ "pinned-done": "Pinned to the top.",
67
+ unpinned: "No longer pinned.",
68
+ "address-copied": "The address is on the clipboard.",
69
+ "new-title": "New article",
70
+ "field-title": "Title",
71
+ create: "Create"
72
+ },
73
+ article: {
74
+ trail: "Where this article sits",
75
+ untitled: "Untitled",
76
+ "state-saved": "Saved",
77
+ "state-saving": "Saving…",
78
+ "state-unsaved": "Not saved yet",
79
+ save: "Save draft",
80
+ "save-failed": "The article was not saved.",
81
+ schedule: "Schedule",
82
+ scheduled: "The article is scheduled.",
83
+ "publish-title": "Put “:title” on the site?",
84
+ "publish-text": "It answers at :address from the moment you do, for everyone.",
85
+ "publish-later": "It goes on the site on :date and not before. Until then nothing changes.",
86
+ "publish-nowhere": "It has no address in this language yet, so nothing will answer.",
87
+ "publish-now": "now",
88
+ preview: "Preview",
89
+ more: "More",
90
+ discard: "Discard changes",
91
+ "discard-title": "Discard what is waiting?",
92
+ "discard-text": "The article goes back to what the site is showing. What was written since is not listed anywhere.",
93
+ discarded: "The article is back to what is published.",
94
+ "conflict-title": "The article changed while you were editing",
95
+ "conflict-mine": "Keep mine",
96
+ "conflict-theirs": "Take the newer version",
97
+ "conflict-theirs-title": "Give up what you wrote?",
98
+ "conflict-theirs-text": "The article is read again as it now is, and what you have typed since goes.",
99
+ leave: "Leave",
100
+ "leave-title": "Leave without saving?",
101
+ "leave-text": "The article could not be saved, and what you wrote is not on the server.",
102
+ "live-never": "Never published",
103
+ "live-scheduled": "Goes out :date",
104
+ "live-since": "On the site since :date",
105
+ "live-edited": "edits waiting",
106
+ "live-off": "Off the site",
107
+ address: "Address",
108
+ "no-address": "No address in this language",
109
+ "address-moving": "The address is changing. The old one keeps working and leads to the new one.",
110
+ author: "Author",
111
+ "no-author": "Nobody",
112
+ rubrics: "Rubrics",
113
+ "rubrics-empty": "In no rubric yet.",
114
+ "rubric-main": "Main",
115
+ "rubric-add": "Add a rubric",
116
+ "rubric-remove": "Take out of this rubric",
117
+ "rubric-none-left": "Every rubric is already on this article.",
118
+ "tags-empty": "No tags yet.",
119
+ "tag-add": "Find or make a tag",
120
+ "tag-remove": "Take this tag off",
121
+ "tag-option": ":title · :count",
122
+ "tag-nothing": "No tag is spelled that way.",
123
+ "tag-create": "Make “:title”",
124
+ related: "Related",
125
+ "related-empty": "Nothing pinned by hand.",
126
+ "related-add": "Find an article",
127
+ "related-remove": "Unpin",
128
+ "related-nothing": "Nothing matches that.",
129
+ "history-empty": "This article has never been published.",
130
+ version: "#:number",
131
+ "version-live": "On the site",
132
+ "source-panel": "From the panel",
133
+ "source-mcp": "By an agent",
134
+ "source-import": "Imported",
135
+ "restore-title": "Restore version :number?",
136
+ "restore-text": "It becomes the draft. The site keeps showing what is published until you publish this.",
137
+ "restore-version": "Restore",
138
+ "restored-version": "Version :number is now the draft."
139
+ },
140
+ rubric: {
141
+ new: "New rubric",
142
+ empty: "No rubrics yet.",
143
+ "empty-help": "A rubric is a section of the blog. An article can be in several of them.",
144
+ choose: "Pick a rubric to edit it.",
145
+ order: "The order here is the order on the site",
146
+ hidden: "Hidden from the site",
147
+ "no-address": "No address in this language",
148
+ back: "Rubrics",
149
+ articles: ":count articles",
150
+ "show-articles": "Show its articles",
151
+ "field-title": "Name",
152
+ "field-slug": "Address",
153
+ "field-lead": "Introduction",
154
+ "lead-help": "Printed above the list of articles.",
155
+ "field-cover": "Cover",
156
+ visible: "Show on the site",
157
+ "visible-help": "Hidden, it drops out of the menu and answers 404. Its articles go on answering at their own addresses.",
158
+ "address-moving": "The address is changing. The old one keeps working and leads to the new one.",
159
+ seo: "SEO for this rubric",
160
+ "seo-help": "The title and the description of this page come from the SEO rules.",
161
+ "seo-override": "Write them for “:name”",
162
+ delete: "Delete",
163
+ "delete-blocked": "While it holds articles it cannot go — move them first.",
164
+ "delete-title": "Delete “:name”?",
165
+ "delete-text": "It goes to the bin and comes off the site, and its address is free again.",
166
+ deleted: "The rubric is in the bin.",
167
+ cancel: "Cancel",
168
+ save: "Save",
169
+ saved: "The rubric is saved.",
170
+ created: "The rubric is made.",
171
+ "reorder-failed": "The new order was not saved."
172
+ },
173
+ tag: {
174
+ new: "New tag",
175
+ "new-title": "New tag",
176
+ "field-title": "Name",
177
+ "field-slug": "Address",
178
+ "field-slug-help": "Left empty, it is made out of the name.",
179
+ create: "Create",
180
+ cancel: "Cancel",
181
+ search: "Search by word or address",
182
+ empty: "No tags yet.",
183
+ "no-address": "No address in this language",
184
+ "column-title": "Name",
185
+ "column-address": "Address",
186
+ "column-articles": "Articles",
187
+ "column-indexing": "Indexing",
188
+ "view-all": "All",
189
+ "view-empty": "Nothing filed",
190
+ "view-noindex": "Not indexed",
191
+ "sort-articles": "Most used",
192
+ "sort-name": "A to Z",
193
+ "indexing-open": "indexed",
194
+ "indexing-rule": "indexed — SEO rule",
195
+ "indexing-noindex": "noindex",
196
+ "indexing-rule-help": "A rule in the SEO section covers this address, so the page is in the index however this tag is set.",
197
+ rename: "Rename",
198
+ renamed: "The tag is renamed.",
199
+ index: "Index",
200
+ noindex: "Keep out of the index",
201
+ indexed: "The tag page is in the index.",
202
+ "kept-out": "The tag page is out of the index.",
203
+ "indexed-many": ":count tag pages are in the index.",
204
+ "kept-out-many": ":count tag pages are out of the index.",
205
+ "open-on-site": "Open on the site",
206
+ "show-articles": "Show its articles",
207
+ delete: "Delete",
208
+ "delete-title": "Delete “:title”?",
209
+ "delete-text": "A tag has no bin: it is gone for good.",
210
+ "delete-text-used": "It is on :count articles and comes off all of them. A tag has no bin: it is gone for good.",
211
+ deleted: "The tag is gone.",
212
+ "delete-many-title": "Delete :count tags?",
213
+ "delete-many-text": "A tag has no bin: they are gone for good.",
214
+ "delete-many-text-used": "They are on :count articles between them and come off all of them. A tag has no bin.",
215
+ "deleted-many": ":count tags are gone.",
216
+ selected: ":count selected",
217
+ clear: "Clear the selection",
218
+ merge: "Merge into one",
219
+ merged: ":count articles now carry “:tag”.",
220
+ "merge-title": "Merge tags",
221
+ "merge-keep": "Which tag to keep",
222
+ "merge-redirect": "Redirect the old addresses",
223
+ "merge-redirect-help": ":addresses will answer 301.",
224
+ "merge-redirect-none": "These tags have no address in this language, so there is nothing to redirect.",
225
+ "merge-warning": ":count articles will carry “:tag” instead. :merged tags will be deleted, and there is no undoing it.",
226
+ "merge-confirm": "Merge"
227
+ }
228
+ }, it = /* @__PURE__ */ new WeakSet();
229
+ function ae() {
230
+ try {
231
+ const { i18n: y } = se();
232
+ it.has(y) || (y.defaults("webx-blog", Rt), it.add(y));
233
+ } catch {
234
+ }
235
+ }
236
+ const Ut = { class: "wx-article-address" }, Bt = /* @__PURE__ */ ee({
237
+ name: "WxArticleAddress",
238
+ __name: "ArticleAddress",
239
+ setup(y) {
240
+ const _ = Te(), u = Ge();
241
+ ae();
242
+ const x = te("webx-blog"), c = b(() => {
243
+ const r = _?.values.value.slug;
244
+ return typeof r == "string" ? r : r?.[u.active.value] ?? "";
245
+ }), l = b(() => c.value === "" ? null : `/${[_?.prefix.value ?? "", c.value].filter(Boolean).join("/")}`), t = b(() => {
246
+ const r = _?.article.value?.path;
247
+ return typeof r == "string" && l.value !== null && l.value !== `/${r}`;
248
+ });
249
+ return (r, i) => (p(), K("div", Ut, [
250
+ n(e(ge), {
251
+ label: e(x)("article.address")
252
+ }, {
253
+ default: a(() => [
254
+ l.value ? (p(), V(e(G), {
255
+ key: 0,
256
+ mono: "",
257
+ class: "wx-article-address__value"
258
+ }, {
259
+ default: a(() => [
260
+ g(f(l.value), 1)
261
+ ]),
262
+ _: 1
263
+ })) : (p(), V(e(G), {
264
+ key: 1,
265
+ size: "sm",
266
+ tone: "muted"
267
+ }, {
268
+ default: a(() => [
269
+ g(f(e(x)("article.no-address")), 1)
270
+ ]),
271
+ _: 1
272
+ }))
273
+ ]),
274
+ _: 1
275
+ }, 8, ["label"]),
276
+ t.value ? (p(), V(e(Se), {
277
+ key: 0,
278
+ type: "info",
279
+ variant: "soft",
280
+ description: e(x)("article.address-moving")
281
+ }, null, 8, ["description"])) : I("", !0)
282
+ ]));
283
+ }
284
+ }), ce = (y, _) => {
285
+ const u = y.__vccOpts || y;
286
+ for (const [x, c] of _)
287
+ u[x] = c;
288
+ return u;
289
+ }, Nt = /* @__PURE__ */ ce(Bt, [["__scopeId", "data-v-2ee0dcfe"]]), qt = /* @__PURE__ */ ee({
290
+ name: "WxArticleAuthor",
291
+ __name: "ArticleAuthor",
292
+ props: /* @__PURE__ */ Ne({
293
+ disabled: { type: Boolean, default: !1 }
294
+ }, {
295
+ modelValue: { default: null },
296
+ modelModifiers: {}
297
+ }),
298
+ emits: ["update:modelValue"],
299
+ setup(y) {
300
+ const _ = y, u = Be(y, "modelValue"), x = Te();
301
+ ae();
302
+ const c = te("webx-blog"), l = b(() => _.disabled || x?.disabled.value === !0), t = b(
303
+ () => (x?.options.value.authors ?? []).map((i) => ({
304
+ label: i.title,
305
+ value: i.id
306
+ }))
307
+ ), r = b({
308
+ get: () => u.value,
309
+ set: (i) => {
310
+ u.value = typeof i == "number" ? i : null;
311
+ }
312
+ });
313
+ return (i, $) => (p(), V(e(be), {
314
+ modelValue: r.value,
315
+ "onUpdate:modelValue": $[0] || ($[0] = (T) => r.value = T),
316
+ options: t.value,
317
+ placeholder: e(c)("article.no-author"),
318
+ disabled: l.value,
319
+ clearable: "",
320
+ filterable: "",
321
+ teleport: "",
322
+ "aria-label": e(c)("article.author")
323
+ }, null, 8, ["modelValue", "options", "placeholder", "disabled", "aria-label"]));
324
+ }
325
+ });
326
+ function ue(y) {
327
+ const _ = `${y.apiPath}/blog/articles`, u = `${y.apiPath}/blog/rubrics`, x = `${y.apiPath}/blog/tags`, c = (l) => l.data;
328
+ return {
329
+ articles: (l = {}) => {
330
+ const t = new URLSearchParams();
331
+ l.q && t.set("q", l.q), l.rubric != null && t.set("rubric", String(l.rubric)), l.tag != null && t.set("tag", String(l.tag)), l.author != null && t.set("author", String(l.author)), l.status && t.set("status", l.status), l.sort && t.set("sort", l.sort), l.trashed && t.set("trashed", "1"), l.page && l.page > 1 && t.set("page", String(l.page)), l.per_page && t.set("per_page", String(l.per_page));
332
+ const r = t.size > 0 ? `?${t}` : "";
333
+ return y.http.get(`${_}${r}`).then((i) => ({ ...i.meta, data: i.data, filters: i.filters }));
334
+ },
335
+ get: (l) => y.http.get(`${_}/${l}`).then(c),
336
+ create: (l) => y.http.post(_, l).then(c),
337
+ save: (l, t) => y.http.put(`${_}/${l}`, t).then(c),
338
+ discard: (l) => y.http.post(`${_}/${l}/discard`, {}).then(c),
339
+ versions: (l) => y.http.get(`${_}/${l}/versions`).then(c),
340
+ restoreVersion: (l, t) => y.http.post(`${_}/${l}/versions/${t}/restore`, {}).then(c),
341
+ tags: (l = "") => {
342
+ const t = l.trim() === "" ? "" : `?q=${encodeURIComponent(l.trim())}`;
343
+ return y.http.get(`${x}${t}`).then(c);
344
+ },
345
+ createTag: (l) => y.http.post(x, l).then(c),
346
+ publish: (l, t) => y.http.post(`${_}/${l}/publish`, t == null ? {} : { at: t }).then(c),
347
+ unpublish: (l) => y.http.post(`${_}/${l}/unpublish`, {}).then(c),
348
+ remove: (l) => y.http.delete(`${_}/${l}`).then(() => {
349
+ }),
350
+ restore: (l) => y.http.post(`${_}/${l}/restore`, {}).then(c),
351
+ rubrics: () => y.http.get(u),
352
+ createRubric: (l) => y.http.post(u, l).then(c),
353
+ saveRubric: (l, t) => y.http.put(`${u}/${l}`, t).then(c),
354
+ removeRubric: (l) => y.http.delete(`${u}/${l}`).then(() => {
355
+ }),
356
+ sortRubrics: (l) => y.http.post(`${u}/reorder`, { ids: l }).then(() => {
357
+ }),
358
+ tagsPage: (l = {}) => {
359
+ const t = new URLSearchParams();
360
+ l.q && t.set("q", l.q), l.empty && t.set("empty", "1"), l.noindex && t.set("noindex", "1"), l.sort && t.set("sort", l.sort), l.page && l.page > 1 && t.set("page", String(l.page)), l.per_page && t.set("per_page", String(l.per_page));
361
+ const r = t.size > 0 ? `?${t}` : "";
362
+ return y.http.get(`${x}${r}`).then((i) => ({ ...i.meta, data: i.data, filters: i.filters }));
363
+ },
364
+ saveTag: (l, t) => y.http.put(`${x}/${l}`, t).then(c),
365
+ removeTag: (l) => y.http.delete(`${x}/${l}`).then(() => {
366
+ }),
367
+ massTags: (l, t) => y.http.post(`${x}/mass`, { ids: l, action: t }).then((r) => r.data.affected),
368
+ mergeTags: (l, t, r) => y.http.post(`${x}/merge`, { ids: l, keep: t, redirect: r }).then(c)
369
+ };
370
+ }
371
+ const Mt = { class: "wx-article-editor__head" }, Pt = { class: "wx-article-editor__id" }, Dt = { class: "wx-article-editor__name" }, It = { class: "wx-article-editor__title" }, Ot = { class: "wx-article-editor__actions" }, Et = { class: "wx-article-editor__screen" }, Lt = 1200, Ft = 720, Kt = /* @__PURE__ */ ee({
372
+ __name: "ArticleEditorPage",
373
+ props: {
374
+ base: { default: "/blog" }
375
+ },
376
+ setup(y) {
377
+ const _ = y, u = se(), x = ue(u), c = qe(), l = Me(), t = Ge(), r = bt();
378
+ ae();
379
+ const i = te("webx-blog"), $ = me(), T = b(() => Number(c.params.id)), h = b(() => `${_.base}/articles`), d = z(null), k = z({}), S = z(""), C = z(""), M = z(null), P = z({ rubrics: [], authors: [] }), U = z([]), R = z(!0), W = z(!1), O = z(!1), A = z({}), N = z(null), H = z(""), D = z(0), m = b(() => u.can("blog.articles.manage")), E = b(() => !m.value || O.value), j = We("root"), de = rt(j), Ve = b(() => de.value > 0 && de.value < Ft), ve = b(() => JSON.stringify(k.value)), J = b(() => H.value !== "" && ve.value !== H.value), we = b(() => W.value ? "saving" : J.value ? "unsaved" : "saved"), he = b(() => {
380
+ const B = k.value.title;
381
+ return _t(B, t.active.value, d.value?.title ?? "");
382
+ }), Q = b(() => {
383
+ const B = k.value.published_at;
384
+ return typeof B == "string" && B !== "" ? B : null;
385
+ }), fe = b(() => {
386
+ if (Q.value === null) return !1;
387
+ const B = new Date(Q.value.replace(" ", "T"));
388
+ return !Number.isNaN(B.valueOf()) && B.valueOf() > Date.now();
389
+ }), ye = b(() => {
390
+ const B = d.value;
391
+ if (!B) return "";
392
+ const Z = r.short(B.published_at);
393
+ return {
394
+ draft: i("article.live-never"),
395
+ scheduled: i("article.live-scheduled", { date: Z }),
396
+ published: i("article.live-since", { date: Z }),
397
+ modified: `${i("article.live-since", { date: Z })} · ${i("article.live-edited")}`,
398
+ unpublished: i("article.live-off")
399
+ }[B.status] ?? "";
400
+ });
401
+ Wt({ url: b(() => M.value), reload: D }), zt({
402
+ article: d,
403
+ values: k,
404
+ options: P,
405
+ related: U,
406
+ prefix: C,
407
+ base: _.base,
408
+ canManage: m.value,
409
+ disabled: E,
410
+ reload: () => ie(!0),
411
+ save: () => w()
412
+ });
413
+ function _e(B) {
414
+ d.value = B.article, k.value = B.values, S.value = B.revision, C.value = B.prefix, M.value = B.preview_url, P.value = B.options, U.value = B.related, H.value = JSON.stringify(B.values), N.value = null;
415
+ }
416
+ async function ie(B = !1) {
417
+ B || (R.value = !0);
418
+ try {
419
+ _e(await x.get(T.value));
420
+ } catch (Z) {
421
+ L.danger($(Z)), l.push(h.value);
422
+ } finally {
423
+ R.value = !1;
424
+ }
425
+ }
426
+ let v;
427
+ function o() {
428
+ !m.value || N.value || !J.value || (clearTimeout(v), v = setTimeout(() => {
429
+ w();
430
+ }, Lt));
431
+ }
432
+ function s() {
433
+ !m.value || N.value || !J.value || W.value || (clearTimeout(v), w());
434
+ }
435
+ async function w() {
436
+ if (!d.value || W.value || !m.value) return;
437
+ clearTimeout(v);
438
+ const B = ve.value, Z = k.value;
439
+ W.value = !0, A.value = {};
440
+ try {
441
+ const X = await x.save(d.value.id, { values: Z, revision: S.value });
442
+ d.value = X.article, S.value = X.revision, C.value = X.prefix, M.value = X.preview_url, P.value = X.options, U.value = X.related, N.value = null, ve.value === B && (H.value = B), D.value += 1;
443
+ } catch (X) {
444
+ const ke = X;
445
+ ke.status === 409 && ke.body?.data ? N.value = ke.body : ke.body?.errors ? (A.value = ke.body.errors, L.danger(i("article.save-failed"))) : L.danger($(X));
446
+ } finally {
447
+ W.value = !1;
448
+ }
449
+ }
450
+ async function le() {
451
+ await pe({
452
+ title: i("article.conflict-theirs-title"),
453
+ message: i("article.conflict-theirs-text"),
454
+ confirmText: i("article.conflict-theirs"),
455
+ cancelText: i("panel.cancel"),
456
+ tone: "danger"
457
+ }) && await ie(!0);
458
+ }
459
+ async function xe() {
460
+ const B = N.value;
461
+ B && (S.value = B.data.revision, N.value = null, await w());
462
+ }
463
+ async function Pe() {
464
+ if (!(!d.value || !await pe({
465
+ title: i("article.discard-title"),
466
+ message: i("article.discard-text"),
467
+ confirmText: i("article.discard"),
468
+ cancelText: i("panel.cancel"),
469
+ tone: "danger"
470
+ }))) {
471
+ O.value = !0;
472
+ try {
473
+ _e(await x.discard(d.value.id)), L.success(i("article.discarded"));
474
+ } catch (Z) {
475
+ L.danger($(Z));
476
+ } finally {
477
+ O.value = !1;
478
+ }
479
+ }
480
+ }
481
+ async function ct() {
482
+ const B = d.value;
483
+ if (!B) return;
484
+ const Z = B.path === null ? null : `/${B.path}`, X = Q.value === null ? i("article.publish-now") : r.short(Q.value);
485
+ if (await pe({
486
+ title: i("article.publish-title", { title: B.title }),
487
+ message: fe.value ? i("article.publish-later", { date: X }) : Z === null ? i("article.publish-nowhere") : i("article.publish-text", { address: Z }),
488
+ confirmText: fe.value ? i("article.schedule") : i("panel.publish"),
489
+ cancelText: i("panel.cancel")
490
+ }) && (J.value && await w(), !N.value)) {
491
+ O.value = !0;
492
+ try {
493
+ await x.publish(B.id, Q.value), await ie(!0), L.success(fe.value ? i("article.scheduled") : i("panel.published"));
494
+ } catch (pt) {
495
+ L.danger($(pt));
496
+ } finally {
497
+ O.value = !1;
498
+ }
499
+ }
500
+ }
501
+ function vt() {
502
+ const B = d.value?.status;
503
+ return B === "published" ? "success" : B === "modified" ? "warning" : B === "scheduled" ? "primary" : "default";
504
+ }
505
+ function et(B) {
506
+ J.value && B.preventDefault();
507
+ }
508
+ return oe(ve, o), oe(T, () => {
509
+ ie();
510
+ }), Le(() => {
511
+ ie(), window.addEventListener("beforeunload", et);
512
+ }), Fe(() => {
513
+ clearTimeout(v), window.removeEventListener("beforeunload", et);
514
+ }), St(async () => !J.value || !m.value || (await w(), !J.value) ? !0 : await pe({
515
+ title: i("article.leave-title"),
516
+ message: i("article.leave-text"),
517
+ confirmText: i("article.leave"),
518
+ cancelText: i("panel.cancel"),
519
+ tone: "danger"
520
+ })), (B, Z) => (p(), K("div", {
521
+ ref_key: "root",
522
+ ref: j,
523
+ class: "wx-article-editor",
524
+ onFocusout: s
525
+ }, [
526
+ R.value || !d.value ? (p(), K(ne, { key: 0 }, [
527
+ n(e(Ue), {
528
+ class: "wx-article-editor__ghost",
529
+ title: "",
530
+ rows: 1
531
+ }),
532
+ n(e(Ue), { rows: 8 })
533
+ ], 64)) : (p(), K(ne, { key: 1 }, [
534
+ q("div", Mt, [
535
+ n(e(ht), {
536
+ class: "wx-article-editor__back",
537
+ to: h.value,
538
+ label: e(i)("module.articles")
539
+ }, null, 8, ["to", "label"]),
540
+ q("div", Pt, [
541
+ n(e(wt), {
542
+ size: "sm",
543
+ label: e(i)("article.trail")
544
+ }, {
545
+ default: a(() => [
546
+ n(e(at), {
547
+ as: "router-link",
548
+ to: h.value
549
+ }, {
550
+ default: a(() => [
551
+ g(f(e(i)("module.articles")), 1)
552
+ ]),
553
+ _: 1
554
+ }, 8, ["to"]),
555
+ n(e(at), { current: "" }, {
556
+ default: a(() => [
557
+ g(f(he.value || e(i)("article.untitled")), 1)
558
+ ]),
559
+ _: 1
560
+ })
561
+ ]),
562
+ _: 1
563
+ }, 8, ["label"]),
564
+ q("div", Dt, [
565
+ q("span", It, f(he.value || e(i)("article.untitled")), 1),
566
+ n(e(re), {
567
+ type: vt(),
568
+ dot: ""
569
+ }, {
570
+ default: a(() => [
571
+ g(f(e(i)(`panel.status-${d.value.status}`)), 1)
572
+ ]),
573
+ _: 1
574
+ }, 8, ["type"])
575
+ ])
576
+ ]),
577
+ q("div", Ot, [
578
+ Ve.value ? (p(), V(e(xt), {
579
+ key: 0,
580
+ align: "end"
581
+ }, {
582
+ trigger: a(() => [
583
+ n(e(Re), {
584
+ type: "more",
585
+ title: e(i)("article.more")
586
+ }, null, 8, ["title"])
587
+ ]),
588
+ default: a(() => [
589
+ M.value ? (p(), V(e(lt), {
590
+ key: 0,
591
+ icon: "eye",
592
+ href: M.value,
593
+ target: "_blank",
594
+ rel: "noopener"
595
+ }, {
596
+ default: a(() => [
597
+ g(f(e(i)("article.preview")), 1)
598
+ ]),
599
+ _: 1
600
+ }, 8, ["href"])) : I("", !0),
601
+ d.value.url && d.value.status !== "draft" ? (p(), V(e(lt), {
602
+ key: 1,
603
+ icon: "link",
604
+ href: d.value.url,
605
+ target: "_blank",
606
+ rel: "noopener"
607
+ }, {
608
+ default: a(() => [
609
+ g(f(e(i)("panel.open-on-site")), 1)
610
+ ]),
611
+ _: 1
612
+ }, 8, ["href"])) : I("", !0)
613
+ ]),
614
+ _: 1
615
+ })) : (p(), K(ne, { key: 1 }, [
616
+ M.value ? (p(), V(e(F), {
617
+ key: 0,
618
+ variant: "outline",
619
+ icon: "eye",
620
+ href: M.value,
621
+ target: "_blank",
622
+ rel: "noopener"
623
+ }, {
624
+ default: a(() => [
625
+ g(f(e(i)("article.preview")), 1)
626
+ ]),
627
+ _: 1
628
+ }, 8, ["href"])) : I("", !0),
629
+ d.value.url && d.value.status !== "draft" ? (p(), V(e(F), {
630
+ key: 1,
631
+ variant: "outline",
632
+ icon: "link",
633
+ href: d.value.url,
634
+ target: "_blank",
635
+ rel: "noopener"
636
+ }, {
637
+ default: a(() => [
638
+ g(f(e(i)("panel.open-on-site")), 1)
639
+ ]),
640
+ _: 1
641
+ }, 8, ["href"])) : I("", !0)
642
+ ], 64))
643
+ ])
644
+ ]),
645
+ N.value ? (p(), V(e(Se), {
646
+ key: 0,
647
+ type: "warning",
648
+ title: e(i)("article.conflict-title"),
649
+ description: N.value.message
650
+ }, {
651
+ actions: a(() => [
652
+ n(e(F), {
653
+ size: "sm",
654
+ variant: "outline",
655
+ onClick: le
656
+ }, {
657
+ default: a(() => [
658
+ g(f(e(i)("article.conflict-theirs")), 1)
659
+ ]),
660
+ _: 1
661
+ }),
662
+ n(e(F), {
663
+ size: "sm",
664
+ type: "primary",
665
+ onClick: xe
666
+ }, {
667
+ default: a(() => [
668
+ g(f(e(i)("article.conflict-mine")), 1)
669
+ ]),
670
+ _: 1
671
+ })
672
+ ]),
673
+ _: 1
674
+ }, 8, ["title", "description"])) : I("", !0),
675
+ q("div", Et, [
676
+ n(e(yt), {
677
+ modelValue: k.value,
678
+ "onUpdate:modelValue": Z[0] || (Z[0] = (X) => k.value = X),
679
+ name: "blog.article-form",
680
+ errors: A.value,
681
+ disabled: E.value
682
+ }, null, 8, ["modelValue", "errors", "disabled"])
683
+ ]),
684
+ m.value ? (p(), V(e(ot), { key: 1 }, {
685
+ state: a(() => [
686
+ n(e(G), {
687
+ size: "sm",
688
+ tone: "muted"
689
+ }, {
690
+ default: a(() => [
691
+ g(f(e(i)(`article.state-${we.value}`)), 1),
692
+ ye.value ? (p(), K(ne, { key: 0 }, [
693
+ g(" · " + f(ye.value), 1)
694
+ ], 64)) : I("", !0)
695
+ ]),
696
+ _: 1
697
+ })
698
+ ]),
699
+ default: a(() => [
700
+ d.value.status === "modified" ? (p(), V(e(F), {
701
+ key: 0,
702
+ variant: "text",
703
+ loading: O.value,
704
+ onClick: Pe
705
+ }, {
706
+ default: a(() => [
707
+ g(f(e(i)("article.discard")), 1)
708
+ ]),
709
+ _: 1
710
+ }, 8, ["loading"])) : I("", !0),
711
+ n(e(F), {
712
+ variant: "outline",
713
+ loading: W.value,
714
+ disabled: !J.value,
715
+ onClick: w
716
+ }, {
717
+ default: a(() => [
718
+ g(f(e(i)("article.save")), 1)
719
+ ]),
720
+ _: 1
721
+ }, 8, ["loading", "disabled"]),
722
+ n(e(F), {
723
+ type: "primary",
724
+ loading: O.value,
725
+ disabled: d.value.status === "published" && !J.value,
726
+ onClick: ct
727
+ }, {
728
+ default: a(() => [
729
+ g(f(fe.value ? e(i)("article.schedule") : e(i)("panel.publish")), 1)
730
+ ]),
731
+ _: 1
732
+ }, 8, ["loading", "disabled"])
733
+ ]),
734
+ _: 1
735
+ })) : I("", !0)
736
+ ], 64))
737
+ ], 544));
738
+ }
739
+ }), Ht = /* @__PURE__ */ ce(Kt, [["__scopeId", "data-v-9bf13356"]]), jt = { class: "wx-article-history" }, Gt = { class: "wx-article-history__number" }, Jt = { class: "wx-article-history__who" }, Zt = /* @__PURE__ */ ee({
740
+ name: "WxArticleHistory",
741
+ __name: "ArticleHistory",
742
+ setup(y) {
743
+ const _ = se(), u = ue(_), x = Te();
744
+ ae();
745
+ const c = te("webx-blog"), l = me(), t = z(null), r = z(!1), i = b(() => x?.article.value ?? null), $ = b(() => _.can("blog.articles.manage")), T = b(
746
+ () => i.value?.status === "published" || i.value?.status === "modified" ? t.value?.[0]?.number ?? null : null
747
+ );
748
+ async function h() {
749
+ const k = i.value;
750
+ if (k)
751
+ try {
752
+ t.value = await u.versions(k.id);
753
+ } catch (S) {
754
+ t.value = [], L.danger(l(S));
755
+ }
756
+ }
757
+ async function d(k) {
758
+ const S = i.value;
759
+ if (!(!S || !await pe({
760
+ title: c("article.restore-title", { number: k.number }),
761
+ message: c("article.restore-text"),
762
+ confirmText: c("article.restore-version"),
763
+ cancelText: c("panel.cancel")
764
+ }))) {
765
+ r.value = !0;
766
+ try {
767
+ await u.restoreVersion(S.id, k.number), await x?.reload(), L.success(c("article.restored-version", { number: k.number }));
768
+ } catch (M) {
769
+ L.danger(l(M));
770
+ } finally {
771
+ r.value = !1;
772
+ }
773
+ }
774
+ }
775
+ return oe(
776
+ () => [i.value?.id, i.value?.published_at, i.value?.updated_at],
777
+ () => {
778
+ h();
779
+ },
780
+ { immediate: !0 }
781
+ ), (k, S) => (p(), K("div", jt, [
782
+ t.value === null ? (p(), V(e(Ue), {
783
+ key: 0,
784
+ class: "wx-article-history__ghost",
785
+ rows: 3
786
+ })) : t.value.length === 0 ? (p(), V(e(Oe), {
787
+ key: 1,
788
+ description: e(c)("article.history-empty")
789
+ }, null, 8, ["description"])) : (p(!0), K(ne, { key: 2 }, ze(t.value, (C) => (p(), K("div", {
790
+ key: C.number,
791
+ class: Ae(["wx-article-history__row", { "is-live": C.number === T.value }])
792
+ }, [
793
+ q("code", Gt, f(e(c)("article.version", { number: C.number })), 1),
794
+ q("div", Jt, [
795
+ C.created_at ? (p(), V(e(De), {
796
+ key: 0,
797
+ value: C.created_at,
798
+ size: "md",
799
+ tone: "default"
800
+ }, null, 8, ["value"])) : I("", !0),
801
+ n(e(G), {
802
+ size: "sm",
803
+ tone: "muted"
804
+ }, {
805
+ default: a(() => [
806
+ g(f(C.author ?? e(c)(`article.source-${C.source}`)) + " ", 1),
807
+ C.comment ? (p(), K(ne, { key: 0 }, [
808
+ g(" · " + f(C.comment), 1)
809
+ ], 64)) : I("", !0)
810
+ ]),
811
+ _: 2
812
+ }, 1024)
813
+ ]),
814
+ C.number === T.value ? (p(), V(e(re), {
815
+ key: 0,
816
+ type: "success",
817
+ dot: ""
818
+ }, {
819
+ default: a(() => [
820
+ g(f(e(c)("article.version-live")), 1)
821
+ ]),
822
+ _: 1
823
+ })) : I("", !0),
824
+ $.value && C.number !== T.value ? (p(), V(e(F), {
825
+ key: 1,
826
+ size: "sm",
827
+ variant: "outline",
828
+ loading: r.value,
829
+ onClick: (M) => d(C)
830
+ }, {
831
+ default: a(() => [
832
+ g(f(e(c)("article.restore-version")), 1)
833
+ ]),
834
+ _: 1
835
+ }, 8, ["loading", "onClick"])) : I("", !0)
836
+ ], 2))), 128))
837
+ ]));
838
+ }
839
+ }), Qt = /* @__PURE__ */ ce(Zt, [["__scopeId", "data-v-0a997938"]]), Xt = { class: "wx-article-related" }, Yt = { class: "wx-article-related__name" }, ea = 250, ta = 10, aa = /* @__PURE__ */ ee({
840
+ name: "WxArticleRelated",
841
+ __name: "ArticleRelated",
842
+ props: /* @__PURE__ */ Ne({
843
+ disabled: { type: Boolean, default: !1 }
844
+ }, {
845
+ modelValue: { default: () => [] },
846
+ modelModifiers: {}
847
+ }),
848
+ emits: ["update:modelValue"],
849
+ setup(y) {
850
+ const _ = y, u = Be(y, "modelValue"), x = se(), c = ue(x), l = Te();
851
+ ae();
852
+ const t = te("webx-blog"), r = me(), i = b(() => _.disabled || l?.disabled.value === !0), $ = z(/* @__PURE__ */ new Map()), T = z([]);
853
+ let h;
854
+ oe(
855
+ () => l?.related.value,
856
+ (U) => {
857
+ const R = new Map($.value);
858
+ for (const W of U ?? []) R.set(W.id, W.title);
859
+ $.value = R;
860
+ },
861
+ { immediate: !0, deep: !0 }
862
+ );
863
+ const d = b({
864
+ get: () => u.value.map((U) => ({ id: U, title: $.value.get(U) ?? `#${U}` })),
865
+ set: (U) => {
866
+ u.value = U.map((R) => R.id);
867
+ }
868
+ }), k = b(
869
+ () => T.value.filter((U) => !u.value.includes(U.id)).map((U) => ({ label: U.title, value: U.id }))
870
+ );
871
+ async function S(U) {
872
+ const R = l?.article.value?.id;
873
+ try {
874
+ const W = await c.articles({ q: U, per_page: ta });
875
+ T.value = W.data.filter((A) => A.id !== R).map((A) => ({ id: A.id, title: A.title }));
876
+ const O = new Map($.value);
877
+ for (const A of T.value) O.set(A.id, A.title);
878
+ $.value = O;
879
+ } catch (W) {
880
+ L.danger(r(W));
881
+ }
882
+ }
883
+ function C(U) {
884
+ clearTimeout(h), h = setTimeout(() => {
885
+ S(U);
886
+ }, ea);
887
+ }
888
+ function M(U) {
889
+ typeof U != "number" || u.value.includes(U) || (u.value = [...u.value, U]);
890
+ }
891
+ function P(U) {
892
+ u.value = u.value.filter((R) => R !== U);
893
+ }
894
+ return oe(
895
+ () => l?.article.value?.id,
896
+ () => {
897
+ S("");
898
+ },
899
+ { immediate: !0 }
900
+ ), Fe(() => clearTimeout(h)), (U, R) => (p(), K("div", Xt, [
901
+ n(e(Je), {
902
+ modelValue: d.value,
903
+ "onUpdate:modelValue": R[0] || (R[0] = (W) => d.value = W),
904
+ plain: "",
905
+ size: "sm",
906
+ "item-key": "id",
907
+ "item-label": "title",
908
+ disabled: i.value,
909
+ "empty-text": e(t)("article.related-empty"),
910
+ "aria-label": e(t)("article.related")
911
+ }, {
912
+ default: a(({ item: W }) => [
913
+ q("span", Yt, f(W.title), 1)
914
+ ]),
915
+ actions: a(({ item: W }) => [
916
+ n(e(Re), {
917
+ type: "remove",
918
+ size: "sm",
919
+ disabled: i.value,
920
+ title: e(t)("article.related-remove"),
921
+ onClick: (O) => P(W.id)
922
+ }, null, 8, ["disabled", "title", "onClick"])
923
+ ]),
924
+ _: 1
925
+ }, 8, ["modelValue", "disabled", "empty-text", "aria-label"]),
926
+ n(e(be), {
927
+ "model-value": null,
928
+ options: k.value,
929
+ placeholder: e(t)("article.related-add"),
930
+ "empty-text": e(t)("article.related-nothing"),
931
+ disabled: i.value,
932
+ filterable: "",
933
+ teleport: "",
934
+ "aria-label": e(t)("article.related-add"),
935
+ onSearch: C,
936
+ "onUpdate:modelValue": M
937
+ }, null, 8, ["options", "placeholder", "empty-text", "disabled", "aria-label"])
938
+ ]));
939
+ }
940
+ }), la = /* @__PURE__ */ ce(aa, [["__scopeId", "data-v-164e86fe"]]), ia = { class: "wx-article-rubrics" }, na = { class: "wx-article-rubrics__name" }, sa = /* @__PURE__ */ ee({
941
+ name: "WxArticleRubrics",
942
+ __name: "ArticleRubrics",
943
+ props: /* @__PURE__ */ Ne({
944
+ disabled: { type: Boolean, default: !1 }
945
+ }, {
946
+ modelValue: { default: () => [] },
947
+ modelModifiers: {}
948
+ }),
949
+ emits: ["update:modelValue"],
950
+ setup(y) {
951
+ const _ = y, u = Be(y, "modelValue"), x = Te();
952
+ ae();
953
+ const c = te("webx-blog"), l = b(() => _.disabled || x?.disabled.value === !0), t = b(() => {
954
+ const h = /* @__PURE__ */ new Map();
955
+ for (const d of x?.options.value.rubrics ?? []) h.set(d.id, d.title);
956
+ return h;
957
+ }), r = b({
958
+ get: () => u.value.map((h) => ({ id: h, title: t.value.get(h) ?? `#${h}` })),
959
+ set: (h) => {
960
+ u.value = h.map((d) => d.id);
961
+ }
962
+ }), i = b(
963
+ () => (x?.options.value.rubrics ?? []).filter((h) => !u.value.includes(h.id)).map((h) => ({ label: h.title, value: h.id }))
964
+ );
965
+ function $(h) {
966
+ typeof h != "number" || u.value.includes(h) || (u.value = [...u.value, h]);
967
+ }
968
+ function T(h) {
969
+ u.value = u.value.filter((d) => d !== h);
970
+ }
971
+ return (h, d) => (p(), K("div", ia, [
972
+ n(e(Je), {
973
+ modelValue: r.value,
974
+ "onUpdate:modelValue": d[0] || (d[0] = (k) => r.value = k),
975
+ plain: "",
976
+ size: "sm",
977
+ "item-key": "id",
978
+ "item-label": "title",
979
+ disabled: l.value,
980
+ "empty-text": e(c)("article.rubrics-empty"),
981
+ "aria-label": e(c)("article.rubrics")
982
+ }, {
983
+ default: a(({ item: k, index: S }) => [
984
+ q("span", na, f(k.title), 1),
985
+ S === 0 ? (p(), V(e(re), {
986
+ key: 0,
987
+ type: "primary"
988
+ }, {
989
+ default: a(() => [
990
+ g(f(e(c)("article.rubric-main")), 1)
991
+ ]),
992
+ _: 1
993
+ })) : I("", !0)
994
+ ]),
995
+ actions: a(({ item: k }) => [
996
+ n(e(Re), {
997
+ type: "remove",
998
+ size: "sm",
999
+ disabled: l.value,
1000
+ title: e(c)("article.rubric-remove"),
1001
+ onClick: (S) => T(k.id)
1002
+ }, null, 8, ["disabled", "title", "onClick"])
1003
+ ]),
1004
+ _: 1
1005
+ }, 8, ["modelValue", "disabled", "empty-text", "aria-label"]),
1006
+ n(e(be), {
1007
+ "model-value": null,
1008
+ options: i.value,
1009
+ placeholder: e(c)("article.rubric-add"),
1010
+ disabled: l.value || i.value.length === 0,
1011
+ "empty-text": e(c)("article.rubric-none-left"),
1012
+ filterable: "",
1013
+ teleport: "",
1014
+ "aria-label": e(c)("article.rubric-add"),
1015
+ "onUpdate:modelValue": $
1016
+ }, null, 8, ["options", "placeholder", "disabled", "empty-text", "aria-label"])
1017
+ ]));
1018
+ }
1019
+ }), ra = /* @__PURE__ */ ce(sa, [["__scopeId", "data-v-db8c5bc8"]]), oa = { class: "wx-article-tags" }, ua = {
1020
+ key: 0,
1021
+ class: "wx-article-tags__chips"
1022
+ }, da = { class: "wx-article-tags__pick" }, ca = 250, va = /* @__PURE__ */ ee({
1023
+ name: "WxArticleTags",
1024
+ __name: "ArticleTags",
1025
+ props: /* @__PURE__ */ Ne({
1026
+ disabled: { type: Boolean, default: !1 }
1027
+ }, {
1028
+ modelValue: { default: () => [] },
1029
+ modelModifiers: {}
1030
+ }),
1031
+ emits: ["update:modelValue"],
1032
+ setup(y) {
1033
+ const _ = y, u = Be(y, "modelValue"), x = se(), c = ue(x), l = Te();
1034
+ ae();
1035
+ const t = te("webx-blog"), r = me(), i = b(() => _.disabled || l?.disabled.value === !0), $ = z(/* @__PURE__ */ new Map()), T = z([]), h = z(""), d = z(!1);
1036
+ let k;
1037
+ oe(
1038
+ () => l?.article.value?.tags,
1039
+ (A) => {
1040
+ const N = new Map($.value);
1041
+ for (const H of A ?? []) N.set(H.id, H.title);
1042
+ $.value = N;
1043
+ },
1044
+ { immediate: !0, deep: !0 }
1045
+ );
1046
+ const S = b(
1047
+ () => u.value.map((A) => ({ id: A, title: $.value.get(A) ?? `#${A}` }))
1048
+ ), C = b(
1049
+ () => T.value.filter((A) => !u.value.includes(A.id)).map((A) => ({
1050
+ // The count is part of the label rather than a column: a select draws a line of text, and
1051
+ // the number is what the reader is choosing between two near-identical words on.
1052
+ label: t("article.tag-option", { title: A.title, count: A.articles_count }),
1053
+ value: A.id
1054
+ }))
1055
+ ), M = b(() => {
1056
+ const A = h.value.trim();
1057
+ if (A === "") return null;
1058
+ const N = (H) => H.toLowerCase() === A.toLowerCase();
1059
+ return T.value.some((H) => N(H.title)) ? null : A;
1060
+ });
1061
+ async function P() {
1062
+ try {
1063
+ T.value = await c.tags(h.value);
1064
+ const A = new Map($.value);
1065
+ for (const N of T.value) A.set(N.id, N.title);
1066
+ $.value = A;
1067
+ } catch (A) {
1068
+ L.danger(r(A));
1069
+ }
1070
+ }
1071
+ function U(A) {
1072
+ h.value = A, clearTimeout(k), k = setTimeout(() => {
1073
+ P();
1074
+ }, ca);
1075
+ }
1076
+ function R(A) {
1077
+ typeof A != "number" || u.value.includes(A) || (u.value = [...u.value, A], h.value = "");
1078
+ }
1079
+ function W(A) {
1080
+ u.value = u.value.filter((N) => N !== A);
1081
+ }
1082
+ async function O() {
1083
+ const A = M.value;
1084
+ if (!(A === null || d.value)) {
1085
+ d.value = !0;
1086
+ try {
1087
+ const N = await c.createTag({ title: A });
1088
+ $.value = new Map($.value).set(N.id, N.title), T.value = [N, ...T.value], R(N.id);
1089
+ } catch (N) {
1090
+ L.danger(r(N));
1091
+ } finally {
1092
+ d.value = !1;
1093
+ }
1094
+ }
1095
+ }
1096
+ return oe(
1097
+ () => l?.article.value?.id,
1098
+ () => {
1099
+ P();
1100
+ },
1101
+ { immediate: !0 }
1102
+ ), Fe(() => clearTimeout(k)), (A, N) => (p(), K("div", oa, [
1103
+ S.value.length > 0 ? (p(), K("div", ua, [
1104
+ (p(!0), K(ne, null, ze(S.value, (H) => (p(), V(e(re), {
1105
+ key: H.id,
1106
+ type: "default",
1107
+ class: "wx-article-tags__chip"
1108
+ }, {
1109
+ default: a(() => [
1110
+ g(f(H.title) + " ", 1),
1111
+ n(e(Re), {
1112
+ icon: "close",
1113
+ tone: "neutral",
1114
+ size: "sm",
1115
+ disabled: i.value,
1116
+ title: e(t)("article.tag-remove"),
1117
+ onClick: (D) => W(H.id)
1118
+ }, null, 8, ["disabled", "title", "onClick"])
1119
+ ]),
1120
+ _: 2
1121
+ }, 1024))), 128))
1122
+ ])) : (p(), V(e(G), {
1123
+ key: 1,
1124
+ size: "sm",
1125
+ tone: "muted"
1126
+ }, {
1127
+ default: a(() => [
1128
+ g(f(e(t)("article.tags-empty")), 1)
1129
+ ]),
1130
+ _: 1
1131
+ })),
1132
+ q("div", da, [
1133
+ n(e(be), {
1134
+ "model-value": null,
1135
+ options: C.value,
1136
+ placeholder: e(t)("article.tag-add"),
1137
+ "empty-text": e(t)("article.tag-nothing"),
1138
+ disabled: i.value,
1139
+ filterable: "",
1140
+ teleport: "",
1141
+ "aria-label": e(t)("article.tag-add"),
1142
+ onSearch: U,
1143
+ "onUpdate:modelValue": R
1144
+ }, null, 8, ["options", "placeholder", "empty-text", "disabled", "aria-label"]),
1145
+ M.value ? (p(), V(e(F), {
1146
+ key: 0,
1147
+ variant: "outline",
1148
+ icon: "plus",
1149
+ loading: d.value,
1150
+ disabled: i.value,
1151
+ onClick: O
1152
+ }, {
1153
+ default: a(() => [
1154
+ g(f(e(t)("article.tag-create", { title: M.value })), 1)
1155
+ ]),
1156
+ _: 1
1157
+ }, 8, ["loading", "disabled"])) : I("", !0)
1158
+ ])
1159
+ ]));
1160
+ }
1161
+ }), pa = /* @__PURE__ */ ce(va, [["__scopeId", "data-v-ce095e37"]]), ma = /* @__PURE__ */ ee({
1162
+ __name: "ArticleCreateDialog",
1163
+ setup(y) {
1164
+ const { open: _, resolve: u, dismiss: x } = Ze(), c = se(), l = ue(c);
1165
+ ae();
1166
+ const t = te("webx-blog"), r = z(""), i = z(!1), $ = z({}), T = We("field");
1167
+ Le(async () => {
1168
+ await Ke(), T.value?.querySelector("input")?.focus();
1169
+ });
1170
+ async function h() {
1171
+ if (!(r.value.trim() === "" || i.value)) {
1172
+ i.value = !0, $.value = {};
1173
+ try {
1174
+ u(await l.create({ title: r.value.trim() }));
1175
+ } catch (d) {
1176
+ $.value = d.body?.errors ?? {};
1177
+ } finally {
1178
+ i.value = !1;
1179
+ }
1180
+ }
1181
+ }
1182
+ return (d, k) => (p(), V(e(Qe), {
1183
+ open: e(_),
1184
+ "onUpdate:open": k[2] || (k[2] = (S) => He(_) ? _.value = S : null),
1185
+ title: e(t)("panel.new-title"),
1186
+ width: 440
1187
+ }, {
1188
+ footer: a(() => [
1189
+ n(e(Xe), { size: "sm" }, {
1190
+ default: a(() => [
1191
+ n(e(F), {
1192
+ variant: "outline",
1193
+ onClick: k[1] || (k[1] = (S) => e(x)())
1194
+ }, {
1195
+ default: a(() => [
1196
+ g(f(e(t)("panel.cancel")), 1)
1197
+ ]),
1198
+ _: 1
1199
+ }),
1200
+ n(e(F), {
1201
+ type: "primary",
1202
+ loading: i.value,
1203
+ disabled: r.value.trim() === "",
1204
+ onClick: h
1205
+ }, {
1206
+ default: a(() => [
1207
+ g(f(e(t)("panel.create")), 1)
1208
+ ]),
1209
+ _: 1
1210
+ }, 8, ["loading", "disabled"])
1211
+ ]),
1212
+ _: 1
1213
+ })
1214
+ ]),
1215
+ default: a(() => [
1216
+ n(e(ge), {
1217
+ label: e(t)("panel.field-title"),
1218
+ error: $.value.title?.[0] ?? $.value.slug?.[0],
1219
+ required: ""
1220
+ }, {
1221
+ default: a(() => [
1222
+ q("div", {
1223
+ ref_key: "field",
1224
+ ref: T
1225
+ }, [
1226
+ n(e($e), {
1227
+ modelValue: r.value,
1228
+ "onUpdate:modelValue": k[0] || (k[0] = (S) => r.value = S),
1229
+ "aria-label": e(t)("panel.field-title"),
1230
+ onKeyup: Ce(h, ["enter"])
1231
+ }, null, 8, ["modelValue", "aria-label"])
1232
+ ], 512)
1233
+ ]),
1234
+ _: 1
1235
+ }, 8, ["label", "error"])
1236
+ ]),
1237
+ _: 1
1238
+ }, 8, ["open", "title"]));
1239
+ }
1240
+ }), fa = { class: "wx-articles__filters" }, ga = ["src"], ba = { class: "wx-articles__name" }, ha = { class: "wx-articles__name-text" }, ya = { class: "wx-articles__title" }, _a = { class: "wx-articles__address" }, wa = { class: "wx-articles__chips" }, xa = { class: "wx-articles__state" }, ka = { class: "wx-articles__card" }, $a = ["src"], Ta = { class: "wx-articles__card-body" }, Va = { class: "wx-articles__card-title" }, Aa = { class: "wx-articles__card-meta" }, nt = 640, Ca = /* @__PURE__ */ ee({
1241
+ __name: "ArticlesPage",
1242
+ props: {
1243
+ base: { default: "/blog" }
1244
+ },
1245
+ setup(y) {
1246
+ const _ = y, u = se(), x = ue(u), c = qe(), l = Me();
1247
+ ae();
1248
+ const t = te("webx-blog"), r = me(), i = We("root"), $ = rt(i), T = z(null), h = z(!0), d = Ee(ma), k = b(() => u.can("blog.articles.manage")), S = b(
1249
+ () => u.state.manifest?.modules.find((v) => v.id === "articles")?.title ?? t("module.articles")
1250
+ ), C = b({
1251
+ get: () => typeof c.query.view == "string" ? c.query.view : "",
1252
+ set: (v) => {
1253
+ l.replace({
1254
+ query: { ...c.query, view: v === "" ? void 0 : String(v), page: void 0 }
1255
+ });
1256
+ }
1257
+ }), M = b(() => C.value === "trashed"), P = b(() => ({
1258
+ q: typeof c.query.q == "string" ? c.query.q : "",
1259
+ rubric: U(c.query.rubric),
1260
+ tag: U(c.query.tag),
1261
+ author: U(c.query.author),
1262
+ sort: typeof c.query.sort == "string" ? c.query.sort : null,
1263
+ page: Number(c.query.page ?? 1) || 1
1264
+ }));
1265
+ function U(v) {
1266
+ return typeof v == "string" && v !== "" && Number(v) || null;
1267
+ }
1268
+ const R = b(() => [
1269
+ { value: "", label: t("panel.view-all") },
1270
+ { value: "published", label: t("panel.view-published") },
1271
+ { value: "scheduled", label: t("panel.view-scheduled") },
1272
+ { value: "draft", label: t("panel.view-draft") },
1273
+ { value: "unpublished", label: t("panel.view-unpublished") },
1274
+ { value: "trashed", label: t("panel.bin"), icon: "trash" }
1275
+ ]), W = b(() => T.value?.filters ?? { rubrics: [], tags: [], authors: [] }), O = b(() => $.value > 0 && $.value < nt), A = b(() => O.value ? [{ key: "card", label: "" }] : [
1276
+ { key: "cover", label: "", width: 68 },
1277
+ { key: "title", label: t("panel.column-title"), minWidth: 220 },
1278
+ { key: "rubrics", label: t("panel.column-rubrics"), width: 190, hideBelow: 840 },
1279
+ { key: "author", label: t("panel.column-author"), width: 160, hideBelow: 1e3 },
1280
+ {
1281
+ key: "date",
1282
+ label: M.value ? t("panel.column-deleted") : t("panel.column-date"),
1283
+ width: 130,
1284
+ hideBelow: 700,
1285
+ // "today at 16:22" is three words the table will break over two lines given half a
1286
+ // chance, and a date read down a column has to be one line to be read at all.
1287
+ cellClass: "wx-articles__when"
1288
+ },
1289
+ { key: "status", label: t("panel.column-status"), width: 150 },
1290
+ { key: "actions", label: "", width: 56, align: "right" }
1291
+ ]), N = b(() => P.value.q !== "" ? t("panel.empty-search") : M.value ? t("panel.empty-bin") : t("panel.empty"));
1292
+ async function H(v) {
1293
+ h.value = !0;
1294
+ try {
1295
+ T.value = await x.articles({
1296
+ q: v?.search ?? P.value.q,
1297
+ status: M.value ? "" : C.value,
1298
+ trashed: M.value,
1299
+ rubric: P.value.rubric,
1300
+ tag: P.value.tag,
1301
+ author: P.value.author,
1302
+ sort: v?.sort ? `${v.sort.order === "desc" ? "-" : ""}${v.sort.key}` : null,
1303
+ page: v?.page ?? P.value.page,
1304
+ per_page: v?.perPage
1305
+ });
1306
+ } catch (o) {
1307
+ L.danger(r(o));
1308
+ } finally {
1309
+ h.value = !1;
1310
+ }
1311
+ }
1312
+ function D(v) {
1313
+ const o = {
1314
+ ...c.query,
1315
+ q: v.search === "" ? void 0 : v.search,
1316
+ sort: v.sort === null ? void 0 : `${v.sort.order === "desc" ? "-" : ""}${v.sort.key}`,
1317
+ page: v.page === 1 ? void 0 : String(v.page)
1318
+ };
1319
+ l.replace({ query: o }), H(v);
1320
+ }
1321
+ function m(v, o) {
1322
+ l.replace({
1323
+ query: {
1324
+ ...c.query,
1325
+ [v]: typeof o == "number" ? String(o) : void 0,
1326
+ page: void 0
1327
+ }
1328
+ });
1329
+ }
1330
+ oe(
1331
+ () => [C.value, P.value.rubric, P.value.tag, P.value.author],
1332
+ () => {
1333
+ H();
1334
+ }
1335
+ ), H();
1336
+ function E(v) {
1337
+ const o = `${_.base}/articles/${v.id}`;
1338
+ l.resolve(o).matched.length > 0 && l.push({ path: o, query: { ...c.query } });
1339
+ }
1340
+ async function j() {
1341
+ const v = await d({});
1342
+ v && (await H(), E(v));
1343
+ }
1344
+ function de(v) {
1345
+ if (!k.value) return [];
1346
+ if (M.value)
1347
+ return [
1348
+ {
1349
+ key: "restore",
1350
+ icon: "refresh",
1351
+ label: t("panel.restore"),
1352
+ run: () => {
1353
+ he(v);
1354
+ }
1355
+ }
1356
+ ];
1357
+ const o = [
1358
+ { key: "open", icon: "edit", label: t("panel.open"), run: () => E(v) }
1359
+ ];
1360
+ return v.url && v.status !== "draft" && o.push({
1361
+ key: "site",
1362
+ icon: "external-link",
1363
+ label: t("panel.open-on-site"),
1364
+ href: v.url
1365
+ }), v.path !== null && o.push({
1366
+ key: "copy",
1367
+ icon: "copy",
1368
+ label: t("panel.copy-address"),
1369
+ run: () => {
1370
+ fe(v);
1371
+ }
1372
+ }), o.push({
1373
+ key: "pin",
1374
+ icon: "star",
1375
+ label: v.pinned ? t("panel.unpin") : t("panel.pin"),
1376
+ run: () => {
1377
+ J(v, !v.pinned);
1378
+ }
1379
+ }), o.push(
1380
+ v.status === "published" || v.status === "modified" || v.status === "scheduled" ? {
1381
+ key: "unpublish",
1382
+ icon: "eye-off",
1383
+ label: t("panel.unpublish"),
1384
+ run: () => {
1385
+ ve(v);
1386
+ }
1387
+ } : {
1388
+ key: "publish",
1389
+ icon: "upload",
1390
+ label: t("panel.publish"),
1391
+ run: () => {
1392
+ Ve(v);
1393
+ }
1394
+ }
1395
+ ), o.push({
1396
+ key: "delete",
1397
+ icon: "trash",
1398
+ label: t("panel.delete"),
1399
+ danger: !0,
1400
+ run: () => {
1401
+ we(v);
1402
+ }
1403
+ }), o;
1404
+ }
1405
+ async function Ve(v) {
1406
+ await Q(() => x.publish(v.id), t("panel.published"));
1407
+ }
1408
+ async function ve(v) {
1409
+ await Q(() => x.unpublish(v.id), t("panel.unpublished-done"));
1410
+ }
1411
+ async function J(v, o) {
1412
+ await Q(
1413
+ () => x.save(v.id, { values: { pinned: o }, revision: v.revision }),
1414
+ t(o ? "panel.pinned-done" : "panel.unpinned")
1415
+ );
1416
+ }
1417
+ async function we(v) {
1418
+ await pe({
1419
+ title: t("panel.delete-title", { title: v.title }),
1420
+ message: t("panel.delete-text"),
1421
+ confirmText: t("panel.delete"),
1422
+ cancelText: t("panel.cancel"),
1423
+ tone: "danger"
1424
+ }) && await Q(() => x.remove(v.id), t("panel.deleted"));
1425
+ }
1426
+ async function he(v) {
1427
+ await Q(() => x.restore(v.id), t("panel.restored"));
1428
+ }
1429
+ async function Q(v, o) {
1430
+ try {
1431
+ await v(), L.success(o);
1432
+ } catch (s) {
1433
+ L.danger(r(s));
1434
+ } finally {
1435
+ await H();
1436
+ }
1437
+ }
1438
+ async function fe(v) {
1439
+ if (v.url)
1440
+ try {
1441
+ await navigator.clipboard.writeText(v.url), L.success(t("panel.address-copied"));
1442
+ } catch {
1443
+ }
1444
+ }
1445
+ function ye(v) {
1446
+ return v === "published" || v === "modified" ? "success" : v === "scheduled" ? "warning" : "default";
1447
+ }
1448
+ function _e(v) {
1449
+ return M.value ? "—" : v.path === null ? t("panel.no-address") : `/${v.path}`;
1450
+ }
1451
+ function ie(v) {
1452
+ return M.value ? v.deleted_at : v.published_at;
1453
+ }
1454
+ return (v, o) => (p(), K("div", {
1455
+ ref_key: "root",
1456
+ ref: i,
1457
+ class: "wx-articles"
1458
+ }, [
1459
+ n(e(je), {
1460
+ view: C.value,
1461
+ "onUpdate:view": o[3] || (o[3] = (s) => C.value = s),
1462
+ title: S.value,
1463
+ views: R.value
1464
+ }, st({
1465
+ default: a(() => [
1466
+ n(e(ut), {
1467
+ data: T.value,
1468
+ columns: A.value,
1469
+ "row-key": "id",
1470
+ searchable: "",
1471
+ clickable: !M.value,
1472
+ hover: !M.value,
1473
+ flush: "",
1474
+ layout: "fixed",
1475
+ loading: h.value,
1476
+ "cards-below": nt,
1477
+ "search-placeholder": e(t)("panel.search"),
1478
+ "empty-text": N.value,
1479
+ "aria-label": S.value,
1480
+ onRowClick: E,
1481
+ onStateChange: D
1482
+ }, {
1483
+ actions: a(() => [
1484
+ q("div", fa, [
1485
+ n(e(be), {
1486
+ "model-value": P.value.rubric,
1487
+ options: W.value.rubrics.map((s) => ({ value: s.id, label: s.title })),
1488
+ placeholder: e(t)("panel.any-rubric"),
1489
+ clearable: "",
1490
+ size: "sm",
1491
+ "onUpdate:modelValue": o[0] || (o[0] = (s) => m("rubric", s))
1492
+ }, null, 8, ["model-value", "options", "placeholder"]),
1493
+ n(e(be), {
1494
+ "model-value": P.value.tag,
1495
+ options: W.value.tags.map((s) => ({ value: s.id, label: s.title })),
1496
+ placeholder: e(t)("panel.any-tag"),
1497
+ clearable: "",
1498
+ filterable: "",
1499
+ size: "sm",
1500
+ "onUpdate:modelValue": o[1] || (o[1] = (s) => m("tag", s))
1501
+ }, null, 8, ["model-value", "options", "placeholder"]),
1502
+ n(e(be), {
1503
+ "model-value": P.value.author,
1504
+ options: W.value.authors.map((s) => ({ value: s.id, label: s.title })),
1505
+ placeholder: e(t)("panel.any-author"),
1506
+ clearable: "",
1507
+ size: "sm",
1508
+ "onUpdate:modelValue": o[2] || (o[2] = (s) => m("author", s))
1509
+ }, null, 8, ["model-value", "options", "placeholder"])
1510
+ ])
1511
+ ]),
1512
+ "cell-cover": a(({ row: s }) => [
1513
+ q("span", {
1514
+ class: Ae(["wx-articles__cover", { "is-empty": !s.cover }])
1515
+ }, [
1516
+ s.cover?.thumb ? (p(), K("img", {
1517
+ key: 0,
1518
+ src: s.cover.thumb,
1519
+ alt: "",
1520
+ loading: "lazy"
1521
+ }, null, 8, ga)) : (p(), V(e(Y), {
1522
+ key: 1,
1523
+ name: "image",
1524
+ size: "sm"
1525
+ }))
1526
+ ], 2)
1527
+ ]),
1528
+ "cell-title": a(({ row: s }) => [
1529
+ q("div", ba, [
1530
+ s.pinned ? (p(), V(e(Ye), {
1531
+ key: 0,
1532
+ content: e(t)("panel.pinned")
1533
+ }, {
1534
+ default: a(() => [
1535
+ n(e(Y), {
1536
+ class: "wx-articles__pin",
1537
+ name: "star",
1538
+ size: "sm"
1539
+ })
1540
+ ]),
1541
+ _: 1
1542
+ }, 8, ["content"])) : I("", !0),
1543
+ q("div", ha, [
1544
+ q("span", ya, f(s.title), 1),
1545
+ q("span", _a, f(_e(s)), 1)
1546
+ ])
1547
+ ])
1548
+ ]),
1549
+ "cell-rubrics": a(({ row: s }) => [
1550
+ q("span", wa, [
1551
+ (p(!0), K(ne, null, ze(s.rubrics, (w) => (p(), V(e(re), {
1552
+ key: w.id,
1553
+ size: "sm",
1554
+ round: ""
1555
+ }, {
1556
+ default: a(() => [
1557
+ g(f(w.title), 1)
1558
+ ]),
1559
+ _: 2
1560
+ }, 1024))), 128))
1561
+ ])
1562
+ ]),
1563
+ "cell-author": a(({ row: s }) => [
1564
+ n(e(G), {
1565
+ size: "sm",
1566
+ tone: "muted",
1567
+ truncate: ""
1568
+ }, {
1569
+ default: a(() => [
1570
+ g(f(s.author ? s.author.name : "—"), 1)
1571
+ ]),
1572
+ _: 2
1573
+ }, 1024)
1574
+ ]),
1575
+ "cell-date": a(({ row: s }) => [
1576
+ ie(s) ? (p(), V(e(De), {
1577
+ key: 0,
1578
+ value: ie(s)
1579
+ }, null, 8, ["value"])) : (p(), V(e(G), {
1580
+ key: 1,
1581
+ size: "sm",
1582
+ tone: "muted"
1583
+ }, {
1584
+ default: a(() => [...o[4] || (o[4] = [
1585
+ g("—", -1)
1586
+ ])]),
1587
+ _: 1
1588
+ }))
1589
+ ]),
1590
+ "cell-status": a(({ row: s }) => [
1591
+ q("span", xa, [
1592
+ n(e(re), {
1593
+ type: ye(s.status),
1594
+ dot: "",
1595
+ size: "sm"
1596
+ }, {
1597
+ default: a(() => [
1598
+ g(f(e(t)(`panel.status-${s.status}`)), 1)
1599
+ ]),
1600
+ _: 2
1601
+ }, 1032, ["type"]),
1602
+ s.status === "modified" ? (p(), V(e(re), {
1603
+ key: 0,
1604
+ type: "primary",
1605
+ size: "sm",
1606
+ round: ""
1607
+ }, {
1608
+ default: a(() => [
1609
+ g(f(e(t)("panel.edits")), 1)
1610
+ ]),
1611
+ _: 1
1612
+ })) : I("", !0)
1613
+ ])
1614
+ ]),
1615
+ "cell-card": a(({ row: s }) => [
1616
+ q("div", ka, [
1617
+ q("span", {
1618
+ class: Ae(["wx-articles__cover is-card", { "is-empty": !s.cover }])
1619
+ }, [
1620
+ s.cover?.thumb ? (p(), K("img", {
1621
+ key: 0,
1622
+ src: s.cover.thumb,
1623
+ alt: "",
1624
+ loading: "lazy"
1625
+ }, null, 8, $a)) : (p(), V(e(Y), {
1626
+ key: 1,
1627
+ name: "image",
1628
+ size: "sm"
1629
+ }))
1630
+ ], 2),
1631
+ q("div", Ta, [
1632
+ q("div", Va, [
1633
+ s.pinned ? (p(), V(e(Y), {
1634
+ key: 0,
1635
+ class: "wx-articles__pin",
1636
+ name: "star",
1637
+ size: "sm"
1638
+ })) : I("", !0),
1639
+ q("span", null, f(s.title), 1)
1640
+ ]),
1641
+ q("div", Aa, [
1642
+ s.rubrics[0] ? (p(), V(e(re), {
1643
+ key: 0,
1644
+ size: "sm",
1645
+ round: ""
1646
+ }, {
1647
+ default: a(() => [
1648
+ g(f(s.rubrics[0].title), 1)
1649
+ ]),
1650
+ _: 2
1651
+ }, 1024)) : I("", !0),
1652
+ n(e(re), {
1653
+ type: ye(s.status),
1654
+ dot: "",
1655
+ size: "sm"
1656
+ }, {
1657
+ default: a(() => [
1658
+ g(f(e(t)(`panel.status-${s.status}`)), 1)
1659
+ ]),
1660
+ _: 2
1661
+ }, 1032, ["type"]),
1662
+ ie(s) ? (p(), V(e(De), {
1663
+ key: 1,
1664
+ value: ie(s)
1665
+ }, null, 8, ["value"])) : I("", !0),
1666
+ s.author ? (p(), V(e(G), {
1667
+ key: 2,
1668
+ size: "sm",
1669
+ tone: "muted",
1670
+ truncate: ""
1671
+ }, {
1672
+ default: a(() => [
1673
+ g(f(s.author.name), 1)
1674
+ ]),
1675
+ _: 2
1676
+ }, 1024)) : I("", !0)
1677
+ ])
1678
+ ]),
1679
+ n(e(Ie), {
1680
+ actions: de(s),
1681
+ label: s.title
1682
+ }, null, 8, ["actions", "label"])
1683
+ ])
1684
+ ]),
1685
+ "cell-actions": a(({ row: s }) => [
1686
+ n(e(Ie), {
1687
+ actions: de(s),
1688
+ label: s.title
1689
+ }, null, 8, ["actions", "label"])
1690
+ ]),
1691
+ _: 1
1692
+ }, 8, ["data", "columns", "clickable", "hover", "loading", "search-placeholder", "empty-text", "aria-label"])
1693
+ ]),
1694
+ _: 2
1695
+ }, [
1696
+ k.value ? {
1697
+ name: "actions",
1698
+ fn: a(() => [
1699
+ n(e(F), {
1700
+ type: "primary",
1701
+ icon: "plus",
1702
+ onClick: j
1703
+ }, {
1704
+ default: a(() => [
1705
+ g(f(e(t)("panel.new")), 1)
1706
+ ]),
1707
+ _: 1
1708
+ })
1709
+ ]),
1710
+ key: "0"
1711
+ } : void 0
1712
+ ]), 1032, ["view", "title", "views"])
1713
+ ], 512));
1714
+ }
1715
+ }), Sa = /* @__PURE__ */ ce(Ca, [["__scopeId", "data-v-0bea5efe"]]), Wa = { class: "wx-rubric-form__head" }, za = { class: "wx-rubric-form__body" }, Ra = { class: "wx-rubric-form__row" }, Ua = { class: "wx-rubric-form__row" }, Ba = { class: "wx-rubric-form__side" }, Na = {
1716
+ key: 1,
1717
+ class: "wx-rubric-form__seo"
1718
+ }, qa = { class: "wx-rubric-form__foot" }, Ma = /* @__PURE__ */ ee({
1719
+ __name: "RubricForm",
1720
+ props: {
1721
+ rubric: {},
1722
+ prefix: { default: "" },
1723
+ inline: { type: Boolean, default: !0 },
1724
+ disabled: { type: Boolean, default: !1 }
1725
+ },
1726
+ emits: ["back", "saved", "deleted", "articles"],
1727
+ setup(y, { emit: _ }) {
1728
+ const u = y, x = _, c = se(), l = ue(c), t = Ge();
1729
+ ae();
1730
+ const r = te("webx-blog"), i = me(), $ = b(() => c.types["wx-media"]?.component), T = b(() => c.types["wx-seo"]?.component), h = b(
1731
+ () => c.types["wx-seo"]?.bind?.({ id: "seo", type: "wx-seo" }) ?? {}
1732
+ ), d = z(M()), k = z({}), S = z(!1), C = z(!1);
1733
+ function M() {
1734
+ return {
1735
+ title: {},
1736
+ slug: {},
1737
+ lead: {},
1738
+ cover: null,
1739
+ is_visible: !0,
1740
+ seo: {}
1741
+ };
1742
+ }
1743
+ oe(
1744
+ () => u.rubric,
1745
+ (D) => {
1746
+ if (k.value = {}, C.value = !1, D === null) {
1747
+ d.value = M();
1748
+ return;
1749
+ }
1750
+ d.value = {
1751
+ title: { ...D.title },
1752
+ slug: { ...D.slug },
1753
+ lead: { ...D.lead },
1754
+ cover: D.cover ? { path: D.cover.path, url: D.cover.url } : null,
1755
+ is_visible: D.is_visible,
1756
+ seo: { ...D.seo }
1757
+ }, C.value = Object.keys(D.seo ?? {}).length > 0;
1758
+ },
1759
+ { immediate: !0 }
1760
+ );
1761
+ const P = b(
1762
+ () => d.value.title[t.active.value] || u.rubric?.name || r("rubric.new")
1763
+ ), U = b(() => {
1764
+ const D = d.value.slug[t.active.value] ?? "";
1765
+ return D === "" ? null : `/${[u.prefix, D].filter(Boolean).join("/")}`;
1766
+ }), R = b(() => {
1767
+ const D = u.rubric?.path;
1768
+ return typeof D == "string" && U.value !== null && U.value !== `/${D}`;
1769
+ }), W = b(() => u.rubric?.articles_count ?? 0);
1770
+ function O(D) {
1771
+ const m = Object.keys(k.value).find(
1772
+ (E) => E === D || E.startsWith(`${D}.`)
1773
+ );
1774
+ return m === void 0 ? void 0 : k.value[m]?.[0];
1775
+ }
1776
+ function A() {
1777
+ return {
1778
+ title: d.value.title,
1779
+ slug: d.value.slug,
1780
+ lead: d.value.lead,
1781
+ cover: d.value.cover === null ? null : { path: d.value.cover.path },
1782
+ is_visible: d.value.is_visible,
1783
+ // Only when it was opened: a save of the rest of the form must not empty a card nobody
1784
+ // looked at, and an untouched card is the rules being left in charge (§12).
1785
+ ...C.value ? { seo: d.value.seo } : {}
1786
+ };
1787
+ }
1788
+ async function N() {
1789
+ S.value = !0, k.value = {};
1790
+ try {
1791
+ const D = u.rubric === null ? await l.createRubric(A()) : await l.saveRubric(u.rubric.id, A());
1792
+ L.success(u.rubric === null ? r("rubric.created") : r("rubric.saved")), x("saved", D);
1793
+ } catch (D) {
1794
+ const m = D.body;
1795
+ m?.errors && (k.value = m.errors), L.danger(i(D));
1796
+ } finally {
1797
+ S.value = !1;
1798
+ }
1799
+ }
1800
+ async function H() {
1801
+ if (!(u.rubric === null || !await pe({
1802
+ title: r("rubric.delete-title", { name: u.rubric.name }),
1803
+ message: r("rubric.delete-text"),
1804
+ confirmText: r("rubric.delete"),
1805
+ cancelText: r("rubric.cancel"),
1806
+ tone: "danger"
1807
+ })))
1808
+ try {
1809
+ await l.removeRubric(u.rubric.id), L.success(r("rubric.deleted")), x("deleted");
1810
+ } catch (m) {
1811
+ L.danger(i(m));
1812
+ }
1813
+ }
1814
+ return (D, m) => (p(), K("div", {
1815
+ class: Ae(["wx-rubric-form", { "is-pane": u.inline }])
1816
+ }, [
1817
+ q("div", Wa, [
1818
+ u.inline ? I("", !0) : (p(), V(e(Re), {
1819
+ key: 0,
1820
+ icon: "arrow-left",
1821
+ title: e(r)("rubric.back"),
1822
+ onClick: m[0] || (m[0] = (E) => x("back"))
1823
+ }, null, 8, ["title"])),
1824
+ n(e(kt), {
1825
+ level: 3,
1826
+ truncate: ""
1827
+ }, {
1828
+ default: a(() => [
1829
+ g(f(P.value), 1)
1830
+ ]),
1831
+ _: 1
1832
+ }),
1833
+ u.rubric ? (p(), V(e(G), {
1834
+ key: 1,
1835
+ size: "sm",
1836
+ tone: "muted"
1837
+ }, {
1838
+ default: a(() => [
1839
+ g(f(e(r)("rubric.articles", { count: W.value })), 1)
1840
+ ]),
1841
+ _: 1
1842
+ })) : I("", !0),
1843
+ m[10] || (m[10] = q("span", { class: "wx-rubric-form__spacer" }, null, -1)),
1844
+ u.rubric && W.value > 0 ? (p(), V(e(F), {
1845
+ key: 2,
1846
+ variant: "text",
1847
+ size: "sm",
1848
+ onClick: m[1] || (m[1] = (E) => x("articles", u.rubric))
1849
+ }, {
1850
+ default: a(() => [
1851
+ g(f(e(r)("rubric.show-articles")), 1)
1852
+ ]),
1853
+ _: 1
1854
+ })) : I("", !0)
1855
+ ]),
1856
+ q("div", za, [
1857
+ q("div", Ra, [
1858
+ n(e(ge), {
1859
+ class: "wx-rubric-form__title",
1860
+ label: e(r)("rubric.field-title"),
1861
+ error: O("title"),
1862
+ required: ""
1863
+ }, {
1864
+ default: a(() => [
1865
+ n(e($e), {
1866
+ modelValue: d.value.title,
1867
+ "onUpdate:modelValue": m[2] || (m[2] = (E) => d.value.title = E),
1868
+ localized: "",
1869
+ disabled: u.disabled
1870
+ }, null, 8, ["modelValue", "disabled"])
1871
+ ]),
1872
+ _: 1
1873
+ }, 8, ["label", "error"]),
1874
+ n(e(ge), {
1875
+ class: "wx-rubric-form__slug",
1876
+ label: e(r)("rubric.field-slug"),
1877
+ error: O("slug"),
1878
+ help: U.value ?? e(r)("rubric.no-address")
1879
+ }, {
1880
+ default: a(() => [
1881
+ n(e($e), {
1882
+ modelValue: d.value.slug,
1883
+ "onUpdate:modelValue": m[3] || (m[3] = (E) => d.value.slug = E),
1884
+ localized: "",
1885
+ disabled: u.disabled
1886
+ }, null, 8, ["modelValue", "disabled"])
1887
+ ]),
1888
+ _: 1
1889
+ }, 8, ["label", "error", "help"])
1890
+ ]),
1891
+ R.value ? (p(), V(e(Se), {
1892
+ key: 0,
1893
+ type: "info",
1894
+ variant: "soft",
1895
+ description: e(r)("rubric.address-moving")
1896
+ }, null, 8, ["description"])) : I("", !0),
1897
+ n(e(ge), {
1898
+ label: e(r)("rubric.field-lead"),
1899
+ help: e(r)("rubric.lead-help"),
1900
+ wide: ""
1901
+ }, {
1902
+ default: a(() => [
1903
+ n(e($t), {
1904
+ modelValue: d.value.lead,
1905
+ "onUpdate:modelValue": m[4] || (m[4] = (E) => d.value.lead = E),
1906
+ localized: "",
1907
+ rows: 3,
1908
+ disabled: u.disabled
1909
+ }, null, 8, ["modelValue", "disabled"])
1910
+ ]),
1911
+ _: 1
1912
+ }, 8, ["label", "help"]),
1913
+ q("div", Ua, [
1914
+ $.value ? (p(), V(tt($.value), {
1915
+ key: 0,
1916
+ modelValue: d.value.cover,
1917
+ "onUpdate:modelValue": m[5] || (m[5] = (E) => d.value.cover = E),
1918
+ class: "wx-rubric-form__cover",
1919
+ label: e(r)("rubric.field-cover"),
1920
+ accept: "image",
1921
+ captions: !1,
1922
+ aspect: "16/9",
1923
+ disabled: u.disabled
1924
+ }, null, 8, ["modelValue", "label", "disabled"])) : I("", !0),
1925
+ q("div", Ba, [
1926
+ n(e(Tt), {
1927
+ modelValue: d.value.is_visible,
1928
+ "onUpdate:modelValue": m[6] || (m[6] = (E) => d.value.is_visible = E),
1929
+ label: e(r)("rubric.visible"),
1930
+ disabled: u.disabled
1931
+ }, null, 8, ["modelValue", "label", "disabled"]),
1932
+ n(e(G), {
1933
+ size: "sm",
1934
+ tone: "muted"
1935
+ }, {
1936
+ default: a(() => [
1937
+ g(f(e(r)("rubric.visible-help")), 1)
1938
+ ]),
1939
+ _: 1
1940
+ })
1941
+ ])
1942
+ ]),
1943
+ T.value ? (p(), K("div", Na, [
1944
+ C.value ? (p(), V(tt(T.value), gt({
1945
+ key: 1,
1946
+ modelValue: d.value.seo,
1947
+ "onUpdate:modelValue": m[8] || (m[8] = (E) => d.value.seo = E)
1948
+ }, h.value, {
1949
+ "structured-data": !1,
1950
+ disabled: u.disabled
1951
+ }), null, 16, ["modelValue", "disabled"])) : (p(), K(ne, { key: 0 }, [
1952
+ n(e(G), {
1953
+ size: "sm",
1954
+ weight: "medium"
1955
+ }, {
1956
+ default: a(() => [
1957
+ g(f(e(r)("rubric.seo")), 1)
1958
+ ]),
1959
+ _: 1
1960
+ }),
1961
+ n(e(G), {
1962
+ size: "sm",
1963
+ tone: "muted"
1964
+ }, {
1965
+ default: a(() => [
1966
+ g(f(e(r)("rubric.seo-help")), 1)
1967
+ ]),
1968
+ _: 1
1969
+ }),
1970
+ n(e(F), {
1971
+ variant: "text",
1972
+ size: "sm",
1973
+ disabled: u.disabled,
1974
+ onClick: m[7] || (m[7] = (E) => C.value = !0)
1975
+ }, {
1976
+ default: a(() => [
1977
+ g(f(e(r)("rubric.seo-override", { name: P.value })), 1)
1978
+ ]),
1979
+ _: 1
1980
+ }, 8, ["disabled"])
1981
+ ], 64))
1982
+ ])) : I("", !0)
1983
+ ]),
1984
+ q("div", qa, [
1985
+ u.rubric ? (p(), K(ne, { key: 0 }, [
1986
+ n(e(F), {
1987
+ variant: "outline",
1988
+ type: "danger",
1989
+ disabled: u.disabled || W.value > 0,
1990
+ onClick: H
1991
+ }, {
1992
+ icon: a(() => [
1993
+ n(e(Y), { name: "trash" })
1994
+ ]),
1995
+ default: a(() => [
1996
+ g(" " + f(e(r)("rubric.delete")), 1)
1997
+ ]),
1998
+ _: 1
1999
+ }, 8, ["disabled"]),
2000
+ W.value > 0 ? (p(), V(e(G), {
2001
+ key: 0,
2002
+ size: "sm",
2003
+ tone: "muted"
2004
+ }, {
2005
+ default: a(() => [
2006
+ g(f(e(r)("rubric.delete-blocked")), 1)
2007
+ ]),
2008
+ _: 1
2009
+ })) : I("", !0)
2010
+ ], 64)) : I("", !0),
2011
+ m[11] || (m[11] = q("span", { class: "wx-rubric-form__spacer" }, null, -1)),
2012
+ n(e(F), {
2013
+ variant: "outline",
2014
+ onClick: m[9] || (m[9] = (E) => x("back"))
2015
+ }, {
2016
+ default: a(() => [
2017
+ g(f(e(r)("rubric.cancel")), 1)
2018
+ ]),
2019
+ _: 1
2020
+ }),
2021
+ n(e(F), {
2022
+ type: "primary",
2023
+ loading: S.value,
2024
+ disabled: u.disabled,
2025
+ onClick: N
2026
+ }, {
2027
+ default: a(() => [
2028
+ g(f(e(r)("rubric.save")), 1)
2029
+ ]),
2030
+ _: 1
2031
+ }, 8, ["loading", "disabled"])
2032
+ ])
2033
+ ], 2));
2034
+ }
2035
+ }), Pa = /* @__PURE__ */ ce(Ma, [["__scopeId", "data-v-ace40cf4"]]), Da = ["onClick"], Ia = { class: "wx-rubric-row__name" }, Oa = /* @__PURE__ */ ee({
2036
+ __name: "RubricsPage",
2037
+ props: {
2038
+ base: { default: "/blog" }
2039
+ },
2040
+ setup(y) {
2041
+ const _ = y, u = se(), x = ue(u), c = qe(), l = Me();
2042
+ ae();
2043
+ const t = te("webx-blog"), r = me(), i = z([]), $ = z(""), T = z(!0), h = z(!1), d = z(!1), k = b(() => u.can("blog.taxonomy.manage")), S = b(
2044
+ () => u.state.manifest?.modules.find((m) => m.id === "rubrics")?.title ?? t("module.rubrics")
2045
+ ), C = b(() => {
2046
+ const m = c.query.rubric;
2047
+ return typeof m == "string" && m !== "" ? Number(m) : null;
2048
+ }), M = b(() => i.value.find((m) => m.id === C.value) ?? null);
2049
+ async function P() {
2050
+ T.value = !0;
2051
+ try {
2052
+ const m = await x.rubrics();
2053
+ i.value = m.data, $.value = m.prefix;
2054
+ } catch (m) {
2055
+ L.danger(r(m));
2056
+ } finally {
2057
+ T.value = !1;
2058
+ }
2059
+ }
2060
+ P(), oe(M, (m) => {
2061
+ m !== null && (h.value = !0);
2062
+ });
2063
+ function U(m) {
2064
+ d.value = !1, l.replace({ query: { ...c.query, rubric: String(m.id) } }), h.value = !0;
2065
+ }
2066
+ function R() {
2067
+ d.value = !0, W(), h.value = !0;
2068
+ }
2069
+ function W() {
2070
+ const m = { ...c.query };
2071
+ delete m.rubric, l.replace({ query: m });
2072
+ }
2073
+ async function O(m) {
2074
+ d.value = !1, await P(), l.replace({ query: { ...c.query, rubric: String(m.id) } });
2075
+ }
2076
+ async function A() {
2077
+ d.value = !1, W(), h.value = !1, await P();
2078
+ }
2079
+ function N() {
2080
+ d.value = !1, W(), h.value = !1;
2081
+ }
2082
+ function H(m) {
2083
+ l.push({ path: `${_.base}/articles`, query: { rubric: String(m.id) } });
2084
+ }
2085
+ async function D() {
2086
+ try {
2087
+ await x.sortRubrics(i.value.map((m) => m.id));
2088
+ } catch (m) {
2089
+ L.danger(r(m, t("rubric.reorder-failed"))), await P();
2090
+ }
2091
+ }
2092
+ return (m, E) => (p(), V(e(je), {
2093
+ title: S.value,
2094
+ card: !1,
2095
+ fill: ""
2096
+ }, {
2097
+ actions: a(() => [
2098
+ k.value ? (p(), V(e(F), {
2099
+ key: 0,
2100
+ type: "primary",
2101
+ onClick: R
2102
+ }, {
2103
+ icon: a(() => [
2104
+ n(e(Y), { name: "plus" })
2105
+ ]),
2106
+ default: a(() => [
2107
+ g(" " + f(e(t)("rubric.new")), 1)
2108
+ ]),
2109
+ _: 1
2110
+ })) : I("", !0)
2111
+ ]),
2112
+ default: a(() => [
2113
+ n(e(Vt), {
2114
+ class: "wx-rubrics",
2115
+ padding: "none"
2116
+ }, {
2117
+ default: a(() => [
2118
+ n(e(At), {
2119
+ open: h.value,
2120
+ "onUpdate:open": E[1] || (E[1] = (j) => h.value = j),
2121
+ class: "wx-rubrics__panes",
2122
+ "list-width": 320,
2123
+ "detail-min": 440,
2124
+ "detail-label": M.value ? M.value.name : e(t)("rubric.new")
2125
+ }, {
2126
+ list: a(() => [
2127
+ T.value ? (p(), V(e(Ue), {
2128
+ key: 0,
2129
+ class: "wx-rubrics__loading",
2130
+ rows: 5
2131
+ })) : i.value.length === 0 ? (p(), V(e(Oe), {
2132
+ key: 1,
2133
+ title: e(t)("rubric.empty"),
2134
+ description: e(t)("rubric.empty-help")
2135
+ }, null, 8, ["title", "description"])) : (p(), V(e(Je), {
2136
+ key: 2,
2137
+ modelValue: i.value,
2138
+ "onUpdate:modelValue": E[0] || (E[0] = (j) => i.value = j),
2139
+ class: "wx-rubrics__list",
2140
+ plain: "",
2141
+ size: "sm",
2142
+ "item-key": "id",
2143
+ "item-label": (j) => j.name,
2144
+ disabled: !k.value,
2145
+ title: e(t)("rubric.order"),
2146
+ onMove: D
2147
+ }, {
2148
+ default: a(({ item: j }) => [
2149
+ q("button", {
2150
+ type: "button",
2151
+ class: Ae(["wx-rubric-row", { "is-current": j.id === C.value, "is-hidden": !j.is_visible }]),
2152
+ onClick: (de) => U(j)
2153
+ }, [
2154
+ q("span", Ia, [
2155
+ n(e(G), {
2156
+ truncate: "",
2157
+ weight: "medium"
2158
+ }, {
2159
+ default: a(() => [
2160
+ g(f(j.name), 1)
2161
+ ]),
2162
+ _: 2
2163
+ }, 1024),
2164
+ j.is_visible ? I("", !0) : (p(), V(e(Ye), {
2165
+ key: 0,
2166
+ content: e(t)("rubric.hidden")
2167
+ }, {
2168
+ default: a(() => [
2169
+ n(e(Y), {
2170
+ name: "eye-off",
2171
+ size: "sm"
2172
+ })
2173
+ ]),
2174
+ _: 1
2175
+ }, 8, ["content"]))
2176
+ ]),
2177
+ n(e(G), {
2178
+ size: "sm",
2179
+ tone: "muted",
2180
+ truncate: ""
2181
+ }, {
2182
+ default: a(() => [
2183
+ g(f(j.path === null ? e(t)("rubric.no-address") : `/${j.path}`), 1)
2184
+ ]),
2185
+ _: 2
2186
+ }, 1024)
2187
+ ], 10, Da)
2188
+ ]),
2189
+ actions: a(({ item: j }) => [
2190
+ n(e(G), {
2191
+ class: "wx-rubric-row__count",
2192
+ size: "sm",
2193
+ tone: "muted"
2194
+ }, {
2195
+ default: a(() => [
2196
+ g(f(j.articles_count), 1)
2197
+ ]),
2198
+ _: 2
2199
+ }, 1024)
2200
+ ]),
2201
+ _: 1
2202
+ }, 8, ["modelValue", "item-label", "disabled", "title"]))
2203
+ ]),
2204
+ empty: a(() => [
2205
+ n(e(Oe), {
2206
+ description: e(t)("rubric.choose")
2207
+ }, null, 8, ["description"])
2208
+ ]),
2209
+ detail: a(({ inline: j, back: de }) => [
2210
+ d.value || M.value ? (p(), V(Pa, {
2211
+ key: d.value ? "new" : String(M.value?.id),
2212
+ rubric: d.value ? null : M.value,
2213
+ prefix: $.value,
2214
+ inline: j,
2215
+ disabled: !k.value,
2216
+ onBack: () => {
2217
+ de(), N();
2218
+ },
2219
+ onArticles: H,
2220
+ onSaved: O,
2221
+ onDeleted: A
2222
+ }, null, 8, ["rubric", "prefix", "inline", "disabled", "onBack"])) : I("", !0)
2223
+ ]),
2224
+ _: 1
2225
+ }, 8, ["open", "detail-label"])
2226
+ ]),
2227
+ _: 1
2228
+ })
2229
+ ]),
2230
+ _: 1
2231
+ }, 8, ["title"]));
2232
+ }
2233
+ }), Ea = /* @__PURE__ */ ee({
2234
+ __name: "TagCreateDialog",
2235
+ setup(y) {
2236
+ const { open: _, resolve: u, dismiss: x } = Ze(), c = se(), l = ue(c);
2237
+ ae();
2238
+ const t = te("webx-blog"), r = z(""), i = z(""), $ = z(!1), T = z({}), h = We("field");
2239
+ Le(async () => {
2240
+ await Ke(), h.value?.querySelector("input")?.focus();
2241
+ });
2242
+ async function d() {
2243
+ if (!(r.value.trim() === "" || $.value)) {
2244
+ $.value = !0, T.value = {};
2245
+ try {
2246
+ u(
2247
+ await l.createTag({
2248
+ title: r.value.trim(),
2249
+ ...i.value.trim() === "" ? {} : { slug: i.value.trim() }
2250
+ })
2251
+ );
2252
+ } catch (k) {
2253
+ T.value = k.body?.errors ?? {};
2254
+ } finally {
2255
+ $.value = !1;
2256
+ }
2257
+ }
2258
+ }
2259
+ return (k, S) => (p(), V(e(Qe), {
2260
+ open: e(_),
2261
+ "onUpdate:open": S[3] || (S[3] = (C) => He(_) ? _.value = C : null),
2262
+ title: e(t)("tag.new-title"),
2263
+ width: 440
2264
+ }, {
2265
+ footer: a(() => [
2266
+ n(e(Xe), { size: "sm" }, {
2267
+ default: a(() => [
2268
+ n(e(F), {
2269
+ variant: "outline",
2270
+ onClick: S[2] || (S[2] = (C) => e(x)())
2271
+ }, {
2272
+ default: a(() => [
2273
+ g(f(e(t)("tag.cancel")), 1)
2274
+ ]),
2275
+ _: 1
2276
+ }),
2277
+ n(e(F), {
2278
+ type: "primary",
2279
+ loading: $.value,
2280
+ disabled: r.value.trim() === "",
2281
+ onClick: d
2282
+ }, {
2283
+ default: a(() => [
2284
+ g(f(e(t)("tag.create")), 1)
2285
+ ]),
2286
+ _: 1
2287
+ }, 8, ["loading", "disabled"])
2288
+ ]),
2289
+ _: 1
2290
+ })
2291
+ ]),
2292
+ default: a(() => [
2293
+ n(e(ge), {
2294
+ label: e(t)("tag.field-title"),
2295
+ error: T.value.title?.[0],
2296
+ required: ""
2297
+ }, {
2298
+ default: a(() => [
2299
+ q("div", {
2300
+ ref_key: "field",
2301
+ ref: h
2302
+ }, [
2303
+ n(e($e), {
2304
+ modelValue: r.value,
2305
+ "onUpdate:modelValue": S[0] || (S[0] = (C) => r.value = C),
2306
+ "aria-label": e(t)("tag.field-title"),
2307
+ onKeyup: Ce(d, ["enter"])
2308
+ }, null, 8, ["modelValue", "aria-label"])
2309
+ ], 512)
2310
+ ]),
2311
+ _: 1
2312
+ }, 8, ["label", "error"]),
2313
+ n(e(ge), {
2314
+ label: e(t)("tag.field-slug"),
2315
+ error: T.value.slug?.[0],
2316
+ help: e(t)("tag.field-slug-help")
2317
+ }, {
2318
+ default: a(() => [
2319
+ n(e($e), {
2320
+ modelValue: i.value,
2321
+ "onUpdate:modelValue": S[1] || (S[1] = (C) => i.value = C),
2322
+ "aria-label": e(t)("tag.field-slug"),
2323
+ onKeyup: Ce(d, ["enter"])
2324
+ }, null, 8, ["modelValue", "aria-label"])
2325
+ ]),
2326
+ _: 1
2327
+ }, 8, ["label", "error", "help"])
2328
+ ]),
2329
+ _: 1
2330
+ }, 8, ["open", "title"]));
2331
+ }
2332
+ }), La = { class: "wx-tag-merge" }, Fa = { class: "wx-tag-merge__chips" }, Ka = { class: "wx-tag-merge__redirect" }, Ha = /* @__PURE__ */ ee({
2333
+ __name: "TagMergeDialog",
2334
+ props: {
2335
+ tags: {}
2336
+ },
2337
+ setup(y) {
2338
+ const _ = y, { open: u, resolve: x, dismiss: c } = Ze(), l = se(), t = ue(l);
2339
+ ae();
2340
+ const r = te("webx-blog"), i = me(), $ = z(
2341
+ [..._.tags].sort((R, W) => W.articles_count - R.articles_count)[0]?.id ?? 0
2342
+ ), T = z(!1), h = z(!0), d = z(null), k = b(
2343
+ () => _.tags.map((R) => ({ value: R.id, label: `${R.title} · ${R.articles_count}` }))
2344
+ ), S = b(() => _.tags.find((R) => R.id === $.value) ?? null), C = b(() => _.tags.filter((R) => R.id !== $.value)), M = b(() => C.value.reduce((R, W) => R + W.articles_count, 0)), P = b(() => C.value.map((R) => R.path).filter(Boolean));
2345
+ async function U() {
2346
+ if (!(S.value === null || C.value.length === 0 || T.value)) {
2347
+ T.value = !0, d.value = null;
2348
+ try {
2349
+ x(
2350
+ await t.mergeTags(
2351
+ C.value.map((R) => R.id),
2352
+ $.value,
2353
+ h.value
2354
+ )
2355
+ );
2356
+ } catch (R) {
2357
+ d.value = i(R);
2358
+ } finally {
2359
+ T.value = !1;
2360
+ }
2361
+ }
2362
+ }
2363
+ return (R, W) => (p(), V(e(Qe), {
2364
+ open: e(u),
2365
+ "onUpdate:open": W[3] || (W[3] = (O) => He(u) ? u.value = O : null),
2366
+ title: e(r)("tag.merge-title"),
2367
+ width: 520
2368
+ }, {
2369
+ footer: a(() => [
2370
+ n(e(Xe), { size: "sm" }, {
2371
+ default: a(() => [
2372
+ n(e(F), {
2373
+ variant: "outline",
2374
+ onClick: W[2] || (W[2] = (O) => e(c)())
2375
+ }, {
2376
+ default: a(() => [
2377
+ g(f(e(r)("tag.cancel")), 1)
2378
+ ]),
2379
+ _: 1
2380
+ }),
2381
+ n(e(F), {
2382
+ type: "primary",
2383
+ loading: T.value,
2384
+ disabled: C.value.length === 0,
2385
+ onClick: U
2386
+ }, {
2387
+ default: a(() => [
2388
+ g(f(e(r)("tag.merge-confirm")), 1)
2389
+ ]),
2390
+ _: 1
2391
+ }, 8, ["loading", "disabled"])
2392
+ ]),
2393
+ _: 1
2394
+ })
2395
+ ]),
2396
+ default: a(() => [
2397
+ q("div", La, [
2398
+ q("div", Fa, [
2399
+ (p(!0), K(ne, null, ze(C.value, (O) => (p(), V(e(re), {
2400
+ key: O.id,
2401
+ size: "sm",
2402
+ round: ""
2403
+ }, {
2404
+ default: a(() => [
2405
+ g(f(O.title) + " · " + f(O.articles_count), 1)
2406
+ ]),
2407
+ _: 2
2408
+ }, 1024))), 128)),
2409
+ n(e(Y), {
2410
+ name: "arrow-right",
2411
+ size: "sm"
2412
+ }),
2413
+ S.value ? (p(), V(e(re), {
2414
+ key: 0,
2415
+ type: "primary",
2416
+ size: "sm",
2417
+ round: ""
2418
+ }, {
2419
+ default: a(() => [
2420
+ g(f(S.value.title) + " · " + f(S.value.articles_count), 1)
2421
+ ]),
2422
+ _: 1
2423
+ })) : I("", !0)
2424
+ ]),
2425
+ n(e(ge), {
2426
+ label: e(r)("tag.merge-keep")
2427
+ }, {
2428
+ default: a(() => [
2429
+ n(e(be), {
2430
+ modelValue: $.value,
2431
+ "onUpdate:modelValue": W[0] || (W[0] = (O) => $.value = O),
2432
+ options: k.value,
2433
+ "aria-label": e(r)("tag.merge-keep")
2434
+ }, null, 8, ["modelValue", "options", "aria-label"])
2435
+ ]),
2436
+ _: 1
2437
+ }, 8, ["label"]),
2438
+ q("div", Ka, [
2439
+ n(e(Ct), {
2440
+ modelValue: h.value,
2441
+ "onUpdate:modelValue": W[1] || (W[1] = (O) => h.value = O),
2442
+ label: e(r)("tag.merge-redirect")
2443
+ }, null, 8, ["modelValue", "label"]),
2444
+ n(e(G), {
2445
+ size: "sm",
2446
+ tone: "muted"
2447
+ }, {
2448
+ default: a(() => [
2449
+ g(f(P.value.length === 0 ? e(r)("tag.merge-redirect-none") : e(r)("tag.merge-redirect-help", { addresses: P.value.join(", ") })), 1)
2450
+ ]),
2451
+ _: 1
2452
+ })
2453
+ ]),
2454
+ n(e(Se), {
2455
+ type: "warning",
2456
+ variant: "soft",
2457
+ description: e(r)("tag.merge-warning", {
2458
+ count: M.value,
2459
+ tag: S.value?.title ?? "",
2460
+ merged: C.value.length
2461
+ })
2462
+ }, null, 8, ["description"]),
2463
+ d.value ? (p(), V(e(Se), {
2464
+ key: 0,
2465
+ type: "danger",
2466
+ variant: "soft",
2467
+ description: d.value
2468
+ }, null, 8, ["description"])) : I("", !0)
2469
+ ])
2470
+ ]),
2471
+ _: 1
2472
+ }, 8, ["open", "title"]));
2473
+ }
2474
+ }), ja = /* @__PURE__ */ ce(Ha, [["__scopeId", "data-v-aa68b3a8"]]), Ga = { class: "wx-tags" }, Ja = { class: "wx-tags__sort" }, Za = ["title", "onClick"], Qa = { key: 2 }, Xa = /* @__PURE__ */ ee({
2475
+ __name: "TagsPage",
2476
+ props: {
2477
+ base: { default: "/blog" }
2478
+ },
2479
+ setup(y) {
2480
+ const _ = y, u = se(), x = ue(u), c = qe(), l = Me();
2481
+ ae();
2482
+ const t = te("webx-blog"), r = me(), i = z(null), $ = z(!0), T = z([]), h = z(!1), d = z(null), k = z(""), S = We("box"), C = Ee(Ea), M = Ee(ja), P = b(() => u.can("blog.taxonomy.manage")), U = b(
2483
+ () => u.state.manifest?.modules.find((o) => o.id === "tags")?.title ?? t("module.tags")
2484
+ ), R = b({
2485
+ get: () => typeof c.query.view == "string" ? c.query.view : "",
2486
+ set: (o) => {
2487
+ l.replace({
2488
+ query: { ...c.query, view: o === "" ? void 0 : String(o), page: void 0 }
2489
+ });
2490
+ }
2491
+ }), W = b(() => i.value?.filters ?? { total: 0, empty: 0, noindex: 0 }), O = b(() => [
2492
+ { value: "", label: t("tag.view-all"), badge: W.value.total },
2493
+ { value: "empty", label: t("tag.view-empty"), badge: W.value.empty },
2494
+ { value: "noindex", label: t("tag.view-noindex"), badge: W.value.noindex }
2495
+ ]), A = b(() => i.value?.data ?? []), N = b(() => A.value.filter((o) => T.value.includes(o.id))), H = b(() => [
2496
+ { key: "title", label: t("tag.column-title"), minWidth: 150 },
2497
+ // The number is what the other columns and the narrowest the title may be add up to without
2498
+ // this one: below it the address is what does not fit, and a fixed table does not shrink —
2499
+ // it scrolls sideways and takes the ··· with it (CLAUDE.md §4). Measured, not guessed: at
2500
+ // 375px the row is the word, the number and the menu, and nothing hangs off the edge.
2501
+ { key: "path", label: t("tag.column-address"), width: 180, hideBelow: 760 },
2502
+ { key: "articles_count", label: t("tag.column-articles"), width: 70, align: "right" },
2503
+ // Wide enough for the longest of the three states on one line, in every language: measured
2504
+ // at 180px of text, and a cell keeps 32 of its own. Narrower, the ruled row wrapped and
2505
+ // stood eighteen pixels taller than the ones around it.
2506
+ { key: "indexing", label: t("tag.column-indexing"), width: 230, hideBelow: 560 },
2507
+ { key: "actions", label: "", width: 56, align: "right" }
2508
+ ]);
2509
+ function D(o) {
2510
+ return {
2511
+ q: o?.search ?? (typeof c.query.q == "string" ? c.query.q : ""),
2512
+ empty: R.value === "empty",
2513
+ noindex: R.value === "noindex",
2514
+ // Only when it is not the default: most used first is what the list is, and a query
2515
+ // string that repeats the default is a link that outlives a change of mind about it.
2516
+ sort: c.query.sort === "name" ? "name" : void 0,
2517
+ page: o?.page ?? (Number(c.query.page ?? 1) || 1),
2518
+ per_page: o?.perPage
2519
+ };
2520
+ }
2521
+ async function m(o) {
2522
+ $.value = !0;
2523
+ try {
2524
+ i.value = await x.tagsPage(D(o));
2525
+ } catch (s) {
2526
+ L.danger(r(s));
2527
+ } finally {
2528
+ $.value = !1;
2529
+ }
2530
+ }
2531
+ function E(o) {
2532
+ const s = {
2533
+ ...c.query,
2534
+ q: o.search === "" ? void 0 : o.search,
2535
+ page: o.page === 1 ? void 0 : String(o.page)
2536
+ };
2537
+ l.replace({ query: s }), m(o);
2538
+ }
2539
+ oe(R, () => {
2540
+ T.value = [], m();
2541
+ }), m();
2542
+ function j(o) {
2543
+ l.replace({
2544
+ query: { ...c.query, sort: o === "articles" ? void 0 : o, page: void 0 }
2545
+ }), m();
2546
+ }
2547
+ const de = b(() => c.query.sort === "name" ? "name" : "articles");
2548
+ async function Ve() {
2549
+ await C({}) && await m();
2550
+ }
2551
+ async function ve(o) {
2552
+ d.value = o.id, k.value = o.title, await Ke(), S.value?.querySelector("input")?.focus();
2553
+ }
2554
+ function J() {
2555
+ d.value = null, k.value = "";
2556
+ }
2557
+ async function we(o) {
2558
+ const s = k.value.trim();
2559
+ if (s === "" || s === o.title) {
2560
+ J();
2561
+ return;
2562
+ }
2563
+ J(), await Q(o, { title: s }, t("tag.renamed"));
2564
+ }
2565
+ async function he(o, s) {
2566
+ await Q(o, { noindex: s }, t(s ? "tag.kept-out" : "tag.indexed"));
2567
+ }
2568
+ async function Q(o, s, w) {
2569
+ try {
2570
+ const le = await x.saveTag(o.id, s);
2571
+ i.value && (i.value = {
2572
+ ...i.value,
2573
+ data: i.value.data.map((xe) => xe.id === le.id ? le : xe)
2574
+ }), L.success(w);
2575
+ } catch (le) {
2576
+ L.danger(r(le));
2577
+ }
2578
+ }
2579
+ async function fe(o) {
2580
+ if (await pe({
2581
+ title: t("tag.delete-title", { title: o.title }),
2582
+ message: o.articles_count > 0 ? t("tag.delete-text-used", { count: o.articles_count }) : t("tag.delete-text"),
2583
+ confirmText: t("tag.delete"),
2584
+ cancelText: t("tag.cancel"),
2585
+ tone: "danger"
2586
+ }))
2587
+ try {
2588
+ await x.removeTag(o.id), L.success(t("tag.deleted")), T.value = T.value.filter((w) => w !== o.id), await m();
2589
+ } catch (w) {
2590
+ L.danger(r(w));
2591
+ }
2592
+ }
2593
+ function ye(o) {
2594
+ if (!P.value) return [];
2595
+ const s = [
2596
+ { key: "rename", icon: "edit", label: t("tag.rename"), run: () => {
2597
+ ve(o);
2598
+ } }
2599
+ ];
2600
+ return o.url && s.push({
2601
+ key: "site",
2602
+ icon: "external-link",
2603
+ label: t("tag.open-on-site"),
2604
+ href: o.url
2605
+ }), s.push({
2606
+ key: "articles",
2607
+ icon: "list",
2608
+ label: t("tag.show-articles"),
2609
+ run: () => {
2610
+ l.push({ path: `${_.base}/articles`, query: { tag: String(o.id) } });
2611
+ }
2612
+ }), s.push(
2613
+ o.noindex ? {
2614
+ key: "index",
2615
+ icon: "eye",
2616
+ label: t("tag.index"),
2617
+ run: () => {
2618
+ he(o, !1);
2619
+ }
2620
+ } : {
2621
+ key: "noindex",
2622
+ icon: "eye-off",
2623
+ label: t("tag.noindex"),
2624
+ run: () => {
2625
+ he(o, !0);
2626
+ }
2627
+ }
2628
+ ), s.push({
2629
+ key: "delete",
2630
+ icon: "trash",
2631
+ label: t("tag.delete"),
2632
+ danger: !0,
2633
+ run: () => {
2634
+ fe(o);
2635
+ }
2636
+ }), s;
2637
+ }
2638
+ function _e(o) {
2639
+ return o === "noindex" ? "muted" : "success";
2640
+ }
2641
+ async function ie() {
2642
+ if (N.value.length < 2) return;
2643
+ const o = await M({ tags: N.value });
2644
+ o && (L.success(t("tag.merged", { tag: o.tag.title, count: o.articles_count })), T.value = [], await m());
2645
+ }
2646
+ async function v(o) {
2647
+ const s = N.value.map((w) => w.id);
2648
+ if (!(s.length === 0 || h.value)) {
2649
+ if (o === "delete") {
2650
+ const w = N.value.reduce((xe, Pe) => xe + Pe.articles_count, 0);
2651
+ if (!await pe({
2652
+ title: t("tag.delete-many-title", { count: s.length }),
2653
+ message: w > 0 ? t("tag.delete-many-text-used", { count: w }) : t("tag.delete-many-text"),
2654
+ confirmText: t("tag.delete"),
2655
+ cancelText: t("tag.cancel"),
2656
+ tone: "danger"
2657
+ })) return;
2658
+ }
2659
+ h.value = !0;
2660
+ try {
2661
+ const w = await x.massTags(s, o);
2662
+ L.success(
2663
+ o === "delete" ? t("tag.deleted-many", { count: w }) : o === "index" ? t("tag.indexed-many", { count: w }) : t("tag.kept-out-many", { count: w })
2664
+ ), T.value = [], await m();
2665
+ } catch (w) {
2666
+ L.danger(r(w));
2667
+ } finally {
2668
+ h.value = !1;
2669
+ }
2670
+ }
2671
+ }
2672
+ return (o, s) => (p(), K("div", Ga, [
2673
+ n(e(je), {
2674
+ view: R.value,
2675
+ "onUpdate:view": s[2] || (s[2] = (w) => R.value = w),
2676
+ title: U.value,
2677
+ views: O.value
2678
+ }, st({
2679
+ default: a(() => [
2680
+ n(e(ut), {
2681
+ selected: T.value,
2682
+ "onUpdate:selected": s[1] || (s[1] = (w) => T.value = w),
2683
+ data: i.value,
2684
+ columns: H.value,
2685
+ "row-key": "id",
2686
+ searchable: "",
2687
+ hover: "",
2688
+ flush: "",
2689
+ layout: "fixed",
2690
+ loading: $.value,
2691
+ selectable: P.value,
2692
+ "cards-below": 0,
2693
+ "search-placeholder": e(t)("tag.search"),
2694
+ "empty-text": A.value.length === 0 && !$.value ? e(t)("tag.empty") : void 0,
2695
+ "aria-label": U.value,
2696
+ onStateChange: E
2697
+ }, {
2698
+ actions: a(() => [
2699
+ q("div", Ja, [
2700
+ (p(), K(ne, null, ze(["articles", "name"], (w) => n(e(F), {
2701
+ key: w,
2702
+ size: "sm",
2703
+ variant: de.value === w ? "outline" : "text",
2704
+ onClick: (le) => j(w)
2705
+ }, {
2706
+ default: a(() => [
2707
+ g(f(e(t)(`tag.sort-${w}`)), 1)
2708
+ ]),
2709
+ _: 2
2710
+ }, 1032, ["variant", "onClick"])), 64))
2711
+ ])
2712
+ ]),
2713
+ "cell-title": a(({ row: w }) => [
2714
+ d.value === w.id ? (p(), K("span", {
2715
+ key: 0,
2716
+ ref_key: "box",
2717
+ ref: S,
2718
+ class: "wx-tags__rename"
2719
+ }, [
2720
+ n(e($e), {
2721
+ modelValue: k.value,
2722
+ "onUpdate:modelValue": s[0] || (s[0] = (le) => k.value = le),
2723
+ size: "sm",
2724
+ "aria-label": e(t)("tag.rename"),
2725
+ onKeyup: [
2726
+ Ce((le) => we(w), ["enter"]),
2727
+ Ce(J, ["esc"])
2728
+ ],
2729
+ onBlur: (le) => we(w)
2730
+ }, null, 8, ["modelValue", "aria-label", "onKeyup", "onBlur"])
2731
+ ], 512)) : P.value ? (p(), K("button", {
2732
+ key: 1,
2733
+ type: "button",
2734
+ class: "wx-tags__name",
2735
+ title: e(t)("tag.rename"),
2736
+ onClick: (le) => ve(w)
2737
+ }, f(w.title), 9, Za)) : (p(), K("span", Qa, f(w.title), 1))
2738
+ ]),
2739
+ "cell-path": a(({ row: w }) => [
2740
+ n(e(G), {
2741
+ size: "sm",
2742
+ tone: "muted",
2743
+ mono: "",
2744
+ truncate: ""
2745
+ }, {
2746
+ default: a(() => [
2747
+ g(f(w.path ?? e(t)("tag.no-address")), 1)
2748
+ ]),
2749
+ _: 2
2750
+ }, 1024)
2751
+ ]),
2752
+ "cell-articles_count": a(({ row: w }) => [
2753
+ n(e(G), {
2754
+ tone: w.articles_count === 0 ? "muted" : "default"
2755
+ }, {
2756
+ default: a(() => [
2757
+ g(f(w.articles_count), 1)
2758
+ ]),
2759
+ _: 2
2760
+ }, 1032, ["tone"])
2761
+ ]),
2762
+ "cell-indexing": a(({ row: w }) => [
2763
+ w.indexing === "rule" ? (p(), V(e(Ye), {
2764
+ key: 0,
2765
+ content: e(t)("tag.indexing-rule-help")
2766
+ }, {
2767
+ default: a(() => [
2768
+ n(e(G), {
2769
+ size: "sm",
2770
+ tone: _e(w.indexing)
2771
+ }, {
2772
+ default: a(() => [
2773
+ g(f(e(t)("tag.indexing-rule")), 1)
2774
+ ]),
2775
+ _: 1
2776
+ }, 8, ["tone"])
2777
+ ]),
2778
+ _: 2
2779
+ }, 1032, ["content"])) : (p(), V(e(G), {
2780
+ key: 1,
2781
+ size: "sm",
2782
+ tone: _e(w.indexing)
2783
+ }, {
2784
+ default: a(() => [
2785
+ g(f(e(t)(`tag.indexing-${w.indexing}`)), 1)
2786
+ ]),
2787
+ _: 2
2788
+ }, 1032, ["tone"]))
2789
+ ]),
2790
+ "cell-actions": a(({ row: w }) => [
2791
+ n(e(Ie), {
2792
+ actions: ye(w),
2793
+ label: w.title
2794
+ }, null, 8, ["actions", "label"])
2795
+ ]),
2796
+ _: 1
2797
+ }, 8, ["selected", "data", "columns", "loading", "selectable", "search-placeholder", "empty-text", "aria-label"])
2798
+ ]),
2799
+ _: 2
2800
+ }, [
2801
+ P.value ? {
2802
+ name: "actions",
2803
+ fn: a(() => [
2804
+ n(e(F), {
2805
+ type: "primary",
2806
+ onClick: Ve
2807
+ }, {
2808
+ icon: a(() => [
2809
+ n(e(Y), { name: "plus" })
2810
+ ]),
2811
+ default: a(() => [
2812
+ g(" " + f(e(t)("tag.new")), 1)
2813
+ ]),
2814
+ _: 1
2815
+ })
2816
+ ]),
2817
+ key: "0"
2818
+ } : void 0
2819
+ ]), 1032, ["view", "title", "views"]),
2820
+ N.value.length > 0 ? (p(), V(e(ot), {
2821
+ key: 0,
2822
+ class: "wx-tags__bar",
2823
+ sticky: ""
2824
+ }, {
2825
+ default: a(() => [
2826
+ n(e(G), { weight: "medium" }, {
2827
+ default: a(() => [
2828
+ g(f(e(t)("tag.selected", { count: N.value.length })), 1)
2829
+ ]),
2830
+ _: 1
2831
+ }),
2832
+ s[7] || (s[7] = q("span", { class: "wx-tags__bar-spacer" }, null, -1)),
2833
+ n(e(F), {
2834
+ type: "primary",
2835
+ disabled: N.value.length < 2 || h.value,
2836
+ onClick: ie
2837
+ }, {
2838
+ icon: a(() => [
2839
+ n(e(Y), { name: "link" })
2840
+ ]),
2841
+ default: a(() => [
2842
+ g(" " + f(e(t)("tag.merge")), 1)
2843
+ ]),
2844
+ _: 1
2845
+ }, 8, ["disabled"]),
2846
+ n(e(F), {
2847
+ variant: "outline",
2848
+ disabled: h.value,
2849
+ onClick: s[3] || (s[3] = (w) => v("index"))
2850
+ }, {
2851
+ icon: a(() => [
2852
+ n(e(Y), { name: "eye" })
2853
+ ]),
2854
+ default: a(() => [
2855
+ g(" " + f(e(t)("tag.index")), 1)
2856
+ ]),
2857
+ _: 1
2858
+ }, 8, ["disabled"]),
2859
+ n(e(F), {
2860
+ variant: "outline",
2861
+ disabled: h.value,
2862
+ onClick: s[4] || (s[4] = (w) => v("noindex"))
2863
+ }, {
2864
+ icon: a(() => [
2865
+ n(e(Y), { name: "eye-off" })
2866
+ ]),
2867
+ default: a(() => [
2868
+ g(" " + f(e(t)("tag.noindex")), 1)
2869
+ ]),
2870
+ _: 1
2871
+ }, 8, ["disabled"]),
2872
+ n(e(F), {
2873
+ variant: "outline",
2874
+ type: "danger",
2875
+ disabled: h.value,
2876
+ onClick: s[5] || (s[5] = (w) => v("delete"))
2877
+ }, {
2878
+ icon: a(() => [
2879
+ n(e(Y), { name: "trash" })
2880
+ ]),
2881
+ default: a(() => [
2882
+ g(" " + f(e(t)("tag.delete")), 1)
2883
+ ]),
2884
+ _: 1
2885
+ }, 8, ["disabled"]),
2886
+ n(e(F), {
2887
+ variant: "text",
2888
+ "aria-label": e(t)("tag.clear"),
2889
+ onClick: s[6] || (s[6] = (w) => T.value = [])
2890
+ }, {
2891
+ icon: a(() => [
2892
+ n(e(Y), { name: "close" })
2893
+ ]),
2894
+ _: 1
2895
+ }, 8, ["aria-label"])
2896
+ ]),
2897
+ _: 1
2898
+ })) : I("", !0)
2899
+ ]));
2900
+ }
2901
+ }), Ya = /* @__PURE__ */ ce(Xa, [["__scopeId", "data-v-7ccee45f"]]);
2902
+ function nl(y = {}) {
2903
+ const _ = y.path ?? "/blog";
2904
+ return [
2905
+ {
2906
+ id: "articles",
2907
+ path: `${_}/articles`,
2908
+ routes: [
2909
+ // The section's own path travels as a prop, so a panel that mounted the blog somewhere
2910
+ // else still links between its screens correctly.
2911
+ {
2912
+ path: `${_}/articles`,
2913
+ name: "webx.blog.articles",
2914
+ component: Sa,
2915
+ props: { base: _ }
2916
+ },
2917
+ {
2918
+ path: `${_}/articles/:id(\\d+)`,
2919
+ name: "webx.blog.articles.edit",
2920
+ component: Ht,
2921
+ props: { base: _ }
2922
+ }
2923
+ ],
2924
+ /*
2925
+ * The parts of `blog.article-form` that only this module can draw.
2926
+ *
2927
+ * The editor is a described screen so that a module can add a tab to it with a patch, and
2928
+ * the price of that is that everything on it has to be a node type. Five of these are
2929
+ * fields — the value is ids, and the control over them is a list that can be dragged or a
2930
+ * box that makes a tag — and two only draw. Each reads the article from the editor above
2931
+ * it rather than from the description, because a screen is a description and not a
2932
+ * binding.
2933
+ */
2934
+ types: {
2935
+ "wx-article-address": { component: Nt, kind: "display" },
2936
+ "wx-article-author": { component: qt, kind: "field" },
2937
+ "wx-article-rubrics": { component: ra, kind: "field" },
2938
+ "wx-article-tags": { component: pa, kind: "field" },
2939
+ "wx-article-related": { component: la, kind: "field" },
2940
+ "wx-article-history": { component: Qt, kind: "display" }
2941
+ }
2942
+ },
2943
+ {
2944
+ id: "rubrics",
2945
+ path: `${_}/rubrics`,
2946
+ routes: [
2947
+ {
2948
+ path: `${_}/rubrics`,
2949
+ name: "webx.blog.rubrics",
2950
+ component: Oa,
2951
+ props: { base: _ }
2952
+ }
2953
+ ]
2954
+ },
2955
+ {
2956
+ id: "tags",
2957
+ path: `${_}/tags`,
2958
+ routes: [
2959
+ {
2960
+ path: `${_}/tags`,
2961
+ name: "webx.blog.tags",
2962
+ component: Ya,
2963
+ props: { base: _ }
2964
+ }
2965
+ ]
2966
+ }
2967
+ ];
2968
+ }
2969
+ export {
2970
+ Nt as WxArticleAddress,
2971
+ qt as WxArticleAuthorField,
2972
+ ma as WxArticleCreateDialog,
2973
+ Ht as WxArticleEditorPage,
2974
+ Qt as WxArticleHistory,
2975
+ la as WxArticleRelated,
2976
+ ra as WxArticleRubrics,
2977
+ pa as WxArticleTags,
2978
+ Sa as WxArticlesPage,
2979
+ Pa as WxRubricForm,
2980
+ Oa as WxRubricsPage,
2981
+ Ea as WxTagCreateDialog,
2982
+ ja as WxTagMergeDialog,
2983
+ Ya as WxTagsPage,
2984
+ dt as articleEditorKey,
2985
+ nl as blog,
2986
+ Rt as blogMessages,
2987
+ ue as createBlogApi,
2988
+ zt as provideArticleEditor,
2989
+ Te as useArticleEditor
2990
+ };
2991
+ //# sourceMappingURL=index.js.map