@webx-ui/module-catalog-landings 0.1.12 → 0.2.1
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/LandingEditorPage-Dt1xmQXl.js +292 -0
- package/dist/LandingEditorPage-Dt1xmQXl.js.map +1 -0
- package/dist/LandingsPage-BAIQAJv2.js +864 -0
- package/dist/LandingsPage-BAIQAJv2.js.map +1 -0
- package/dist/index-DEreqbgG.js +768 -0
- package/dist/index-DEreqbgG.js.map +1 -0
- package/dist/index.d.ts +14 -2
- package/dist/index.js +19 -1896
- package/dist/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { defineComponent as re, computed as r, ref as d, watch as ue, onMounted as oe, onBeforeUnmount as se, openBlock as v, createElementBlock as A, Fragment as R, createVNode as i, unref as l, withCtx as u, createSlots as ie, createTextVNode as m, toDisplayString as y, createBlock as N, createCommentVNode as q } from "vue";
|
|
2
|
+
import { useRoute as ce, useRouter as de, onBeforeRouteLeave as ve } from "vue-router";
|
|
3
|
+
import { useLocales as fe, localizedValue as pe, confirm as H, WxSkeleton as I, WxCard as ge, WxBreadcrumb as me, WxBreadcrumbItem as U, WxBadge as F, WxAlert as ye, WxActionBar as be, WxButton as we, toast as s } from "@webx-ui/core";
|
|
4
|
+
import { useAdmin as he, useTranslate as _e, useErrorText as ke, provideHistorySubject as xe, useBodyKeys as Se, WxScreenHead as Be, WxScreen as We, WxSaveState as Le } from "@webx-ui/module-admin";
|
|
5
|
+
import { c as Ee, u as Ne, N as Ce, p as Ve, f as Te, a as Ae, _ as Ke } from "./index-DEreqbgG.js";
|
|
6
|
+
const Me = /* @__PURE__ */ re({
|
|
7
|
+
name: "WxCatalogLandingEditor",
|
|
8
|
+
__name: "LandingEditorPage",
|
|
9
|
+
props: {
|
|
10
|
+
base: { default: "/catalog" }
|
|
11
|
+
},
|
|
12
|
+
setup(G) {
|
|
13
|
+
const Q = G, C = he(), f = Ee(C), b = ce(), V = de(), X = fe();
|
|
14
|
+
Ne();
|
|
15
|
+
const a = _e(Ce), w = ke(), p = r(() => `${Q.base}/landings`), h = r(() => b.params.id === void 0 || b.params.id === "new"), _ = r(() => h.value ? null : Number(b.params.id)), n = d(null), o = d({}), k = d(""), Y = d({}), B = d(!0), g = d(!1), W = d({}), x = r(() => C.can("catalog.manage")), L = r(() => (n.value?.deleted_at ?? null) !== null), K = r(() => !x.value || g.value || L.value), M = r(() => JSON.stringify(o.value)), S = r(() => k.value !== "" && M.value !== k.value), Z = r(() => g.value ? "saving" : S.value || h.value ? "unsaved" : "saved"), O = r(
|
|
16
|
+
() => C.state.manifest?.modules.find((e) => e.id === "catalog-landings")?.title ?? a("module.title")
|
|
17
|
+
), T = r(() => {
|
|
18
|
+
const e = o.value.name;
|
|
19
|
+
return pe(e, X.active.value, "") || a("panel.untitled");
|
|
20
|
+
}), ee = r(() => {
|
|
21
|
+
const e = n.value;
|
|
22
|
+
if (e)
|
|
23
|
+
return [e.category ?? a("landing.whole-catalog"), e.url ?? ""].filter(Boolean).join(" · ");
|
|
24
|
+
});
|
|
25
|
+
Ve({ landing: n, values: o, locked: K, suggested: Y, list: p.value }), xe({ id: r(() => n.value?.id ?? null) });
|
|
26
|
+
function E(e) {
|
|
27
|
+
n.value = e, o.value = Te(e), k.value = JSON.stringify(o.value);
|
|
28
|
+
}
|
|
29
|
+
function ae() {
|
|
30
|
+
n.value = null, o.value = {
|
|
31
|
+
category_id: b.query.category ? Number(b.query.category) : null,
|
|
32
|
+
filters: {},
|
|
33
|
+
name: {},
|
|
34
|
+
slug: {},
|
|
35
|
+
h1: {},
|
|
36
|
+
text_above: {},
|
|
37
|
+
text_below: {},
|
|
38
|
+
sort: null,
|
|
39
|
+
on_category: !1,
|
|
40
|
+
position: 0,
|
|
41
|
+
recommended: [],
|
|
42
|
+
seo: {}
|
|
43
|
+
}, k.value = JSON.stringify(o.value);
|
|
44
|
+
}
|
|
45
|
+
async function $() {
|
|
46
|
+
if (W.value = {}, _.value === null) {
|
|
47
|
+
ae(), B.value = !1;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
B.value = !0;
|
|
51
|
+
try {
|
|
52
|
+
E(await f.get(_.value));
|
|
53
|
+
} catch (e) {
|
|
54
|
+
s.danger(w(e)), V.push(p.value);
|
|
55
|
+
} finally {
|
|
56
|
+
B.value = !1;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function j() {
|
|
60
|
+
return { ...o.value, filters: Ae(o.value.filters) };
|
|
61
|
+
}
|
|
62
|
+
async function z() {
|
|
63
|
+
if (!(g.value || !x.value)) {
|
|
64
|
+
g.value = !0, W.value = {};
|
|
65
|
+
try {
|
|
66
|
+
if (_.value === null) {
|
|
67
|
+
const e = await f.create(j());
|
|
68
|
+
E(e), s.success(a("panel.created")), await V.replace(`${p.value}/${e.id}`);
|
|
69
|
+
} else
|
|
70
|
+
E(await f.save(_.value, j())), s.success(a("panel.saved"));
|
|
71
|
+
} catch (e) {
|
|
72
|
+
const t = e.body;
|
|
73
|
+
t?.errors && Object.keys(t.errors).length > 0 ? (W.value = t.errors, s.danger(a("panel.save-failed"))) : s.danger(w(e));
|
|
74
|
+
} finally {
|
|
75
|
+
g.value = !1;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function D(e) {
|
|
80
|
+
const t = n.value;
|
|
81
|
+
if (t)
|
|
82
|
+
try {
|
|
83
|
+
const c = await f.publish(t.id, e);
|
|
84
|
+
n.value = { ...t, ...c }, s.success(a(e ? "panel.published-toast" : "panel.unpublished-toast"));
|
|
85
|
+
} catch (c) {
|
|
86
|
+
s.danger(w(c));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function te() {
|
|
90
|
+
const e = n.value;
|
|
91
|
+
if (!(!e || !await H({
|
|
92
|
+
title: a("panel.delete-title", { name: T.value }),
|
|
93
|
+
message: a("panel.delete-text"),
|
|
94
|
+
confirmText: a("panel.delete"),
|
|
95
|
+
cancelText: a("panel.cancel"),
|
|
96
|
+
tone: "danger"
|
|
97
|
+
})))
|
|
98
|
+
try {
|
|
99
|
+
await f.remove(e.id), s.success(a("panel.deleted")), k.value = M.value, V.push(p.value);
|
|
100
|
+
} catch (c) {
|
|
101
|
+
s.danger(w(c));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async function le() {
|
|
105
|
+
const e = n.value;
|
|
106
|
+
if (e)
|
|
107
|
+
try {
|
|
108
|
+
E(await f.restore(e.id)), s.success(a("panel.restored"));
|
|
109
|
+
} catch (t) {
|
|
110
|
+
s.danger(w(t));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function J(e) {
|
|
114
|
+
S.value && e.preventDefault();
|
|
115
|
+
}
|
|
116
|
+
function P(e) {
|
|
117
|
+
(e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "s" && (e.preventDefault(), (S.value || h.value) && z());
|
|
118
|
+
}
|
|
119
|
+
Se(P), ue(_, (e, t) => {
|
|
120
|
+
t === null && e !== null && n.value?.id === e || $();
|
|
121
|
+
}), oe(() => {
|
|
122
|
+
$(), window.addEventListener("beforeunload", J);
|
|
123
|
+
}), se(() => {
|
|
124
|
+
window.removeEventListener("beforeunload", J);
|
|
125
|
+
}), ve(async () => !S.value || !x.value ? !0 : await H({
|
|
126
|
+
title: a("panel.leave-title"),
|
|
127
|
+
message: a("panel.leave-text"),
|
|
128
|
+
confirmText: a("panel.leave"),
|
|
129
|
+
cancelText: a("panel.cancel"),
|
|
130
|
+
tone: "danger"
|
|
131
|
+
}));
|
|
132
|
+
const ne = r(() => {
|
|
133
|
+
const e = n.value;
|
|
134
|
+
if (!e || !x.value) return [];
|
|
135
|
+
if (L.value)
|
|
136
|
+
return [
|
|
137
|
+
{ key: "restore", label: a("panel.restore"), icon: "refresh", run: () => {
|
|
138
|
+
le();
|
|
139
|
+
} }
|
|
140
|
+
];
|
|
141
|
+
const t = [];
|
|
142
|
+
return e.url && t.push({
|
|
143
|
+
key: "site",
|
|
144
|
+
label: a("panel.open-site"),
|
|
145
|
+
icon: "external-link",
|
|
146
|
+
run: () => {
|
|
147
|
+
window.open(e.url ?? "", "_blank", "noopener");
|
|
148
|
+
}
|
|
149
|
+
}), t.push(
|
|
150
|
+
e.is_published ? {
|
|
151
|
+
key: "unpublish",
|
|
152
|
+
label: a("panel.unpublish"),
|
|
153
|
+
icon: "eye-off",
|
|
154
|
+
run: () => {
|
|
155
|
+
D(!1);
|
|
156
|
+
}
|
|
157
|
+
} : { key: "publish", label: a("panel.publish"), icon: "eye", run: () => {
|
|
158
|
+
D(!0);
|
|
159
|
+
} },
|
|
160
|
+
{
|
|
161
|
+
key: "delete",
|
|
162
|
+
label: a("panel.delete"),
|
|
163
|
+
icon: "trash",
|
|
164
|
+
danger: !0,
|
|
165
|
+
menu: !0,
|
|
166
|
+
run: () => {
|
|
167
|
+
te();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
), t;
|
|
171
|
+
});
|
|
172
|
+
return (e, t) => (v(), A("div", {
|
|
173
|
+
class: "wx-catalog-landing-editor",
|
|
174
|
+
onKeydown: P
|
|
175
|
+
}, [
|
|
176
|
+
B.value ? (v(), A(R, { key: 0 }, [
|
|
177
|
+
i(l(I), {
|
|
178
|
+
class: "wx-catalog-landing-editor__ghost",
|
|
179
|
+
title: "",
|
|
180
|
+
rows: 1
|
|
181
|
+
}),
|
|
182
|
+
i(l(ge), null, {
|
|
183
|
+
default: u(() => [
|
|
184
|
+
i(l(I), { rows: 6 })
|
|
185
|
+
]),
|
|
186
|
+
_: 1
|
|
187
|
+
})
|
|
188
|
+
], 64)) : (v(), A(R, { key: 1 }, [
|
|
189
|
+
i(l(Be), {
|
|
190
|
+
divider: "",
|
|
191
|
+
back: p.value,
|
|
192
|
+
"back-label": O.value,
|
|
193
|
+
title: T.value,
|
|
194
|
+
subtitle: ee.value,
|
|
195
|
+
actions: ne.value
|
|
196
|
+
}, ie({
|
|
197
|
+
trail: u(() => [
|
|
198
|
+
i(l(me), {
|
|
199
|
+
size: "sm",
|
|
200
|
+
label: l(a)("panel.trail")
|
|
201
|
+
}, {
|
|
202
|
+
default: u(() => [
|
|
203
|
+
i(l(U), {
|
|
204
|
+
as: "router-link",
|
|
205
|
+
to: p.value
|
|
206
|
+
}, {
|
|
207
|
+
default: u(() => [
|
|
208
|
+
m(y(O.value), 1)
|
|
209
|
+
]),
|
|
210
|
+
_: 1
|
|
211
|
+
}, 8, ["to"]),
|
|
212
|
+
i(l(U), { current: "" }, {
|
|
213
|
+
default: u(() => [
|
|
214
|
+
m(y(T.value), 1)
|
|
215
|
+
]),
|
|
216
|
+
_: 1
|
|
217
|
+
})
|
|
218
|
+
]),
|
|
219
|
+
_: 1
|
|
220
|
+
}, 8, ["label"])
|
|
221
|
+
]),
|
|
222
|
+
_: 2
|
|
223
|
+
}, [
|
|
224
|
+
n.value ? {
|
|
225
|
+
name: "title-after",
|
|
226
|
+
fn: u(() => [
|
|
227
|
+
L.value ? (v(), N(l(F), {
|
|
228
|
+
key: 0,
|
|
229
|
+
dot: ""
|
|
230
|
+
}, {
|
|
231
|
+
default: u(() => [
|
|
232
|
+
m(y(l(a)("panel.in-bin")), 1)
|
|
233
|
+
]),
|
|
234
|
+
_: 1
|
|
235
|
+
})) : (v(), N(l(F), {
|
|
236
|
+
key: 1,
|
|
237
|
+
type: n.value.is_published ? "success" : "default",
|
|
238
|
+
dot: "",
|
|
239
|
+
size: "sm"
|
|
240
|
+
}, {
|
|
241
|
+
default: u(() => [
|
|
242
|
+
m(y(l(a)(n.value.is_published ? "panel.published" : "panel.unpublished")), 1)
|
|
243
|
+
]),
|
|
244
|
+
_: 1
|
|
245
|
+
}, 8, ["type"]))
|
|
246
|
+
]),
|
|
247
|
+
key: "0"
|
|
248
|
+
} : void 0
|
|
249
|
+
]), 1032, ["back", "back-label", "title", "subtitle", "actions"]),
|
|
250
|
+
n.value?.attention ? (v(), N(l(ye), {
|
|
251
|
+
key: 0,
|
|
252
|
+
type: "warning"
|
|
253
|
+
}, {
|
|
254
|
+
default: u(() => [
|
|
255
|
+
m(y(l(a)(`landing.attention-${n.value.attention}`)), 1)
|
|
256
|
+
]),
|
|
257
|
+
_: 1
|
|
258
|
+
})) : q("", !0),
|
|
259
|
+
i(l(We), {
|
|
260
|
+
modelValue: o.value,
|
|
261
|
+
"onUpdate:modelValue": t[0] || (t[0] = (c) => o.value = c),
|
|
262
|
+
name: "catalog.landing-form",
|
|
263
|
+
errors: W.value,
|
|
264
|
+
disabled: K.value
|
|
265
|
+
}, null, 8, ["modelValue", "errors", "disabled"]),
|
|
266
|
+
x.value && !L.value ? (v(), N(l(be), { key: 1 }, {
|
|
267
|
+
state: u(() => [
|
|
268
|
+
i(l(Le), { state: Z.value }, null, 8, ["state"])
|
|
269
|
+
]),
|
|
270
|
+
default: u(() => [
|
|
271
|
+
i(l(we), {
|
|
272
|
+
type: "primary",
|
|
273
|
+
loading: g.value,
|
|
274
|
+
disabled: !S.value && !h.value,
|
|
275
|
+
onClick: z
|
|
276
|
+
}, {
|
|
277
|
+
default: u(() => [
|
|
278
|
+
m(y(l(a)(h.value ? "panel.create" : "panel.save")), 1)
|
|
279
|
+
]),
|
|
280
|
+
_: 1
|
|
281
|
+
}, 8, ["loading", "disabled"])
|
|
282
|
+
]),
|
|
283
|
+
_: 1
|
|
284
|
+
})) : q("", !0)
|
|
285
|
+
], 64))
|
|
286
|
+
], 32));
|
|
287
|
+
}
|
|
288
|
+
}), Je = /* @__PURE__ */ Ke(Me, [["__scopeId", "data-v-0d735844"]]);
|
|
289
|
+
export {
|
|
290
|
+
Je as default
|
|
291
|
+
};
|
|
292
|
+
//# sourceMappingURL=LandingEditorPage-Dt1xmQXl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LandingEditorPage-Dt1xmQXl.js","sources":["../src/LandingEditorPage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'\nimport {\n confirm,\n localizedValue,\n toast,\n useLocales,\n WxActionBar,\n WxAlert,\n WxBadge,\n WxBreadcrumb,\n WxBreadcrumbItem,\n WxButton,\n WxCard,\n WxSkeleton,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport {\n provideHistorySubject,\n useAdmin,\n useBodyKeys,\n useErrorText,\n useTranslate,\n WxSaveState,\n WxScreen,\n WxScreenHead,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport type { ScreenModel } from '@webx-ui/schema'\nimport { cleanSet, createLandingsApi, formValues } from './api'\nimport { provideLandingEditor } from './editor'\nimport { NAMESPACE, useCatalogLandingsMessages } from './i18n'\nimport type { LandingDetail, LandingFilters } from './types'\n\n/**\n * One landing (§8.2 of the landings spec): a head, `catalog.landing-form` under it — base, set,\n * address, texts, order, recommended, SEO, history — and one button. A new landing is the same\n * page at `…/landings/new`: its first save creates it and the address moves to its id.\n */\ndefineOptions({ name: 'WxCatalogLandingEditor' })\n\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/catalog' })\n\nconst admin = useAdmin()\nconst api = createLandingsApi(admin)\nconst route = useRoute()\nconst router = useRouter()\nconst locales = useLocales()\nuseCatalogLandingsMessages()\n\nconst t = useTranslate(NAMESPACE)\nconst message = useErrorText()\n\nconst list = computed(() => `${props.base}/landings`)\nconst creating = computed(() => route.params.id === undefined || route.params.id === 'new')\nconst id = computed(() => (creating.value ? null : Number(route.params.id)))\n\nconst landing = ref<LandingDetail | null>(null)\nconst values = ref<ScreenModel>({})\nconst snapshot = ref('')\nconst suggested = ref<Record<string, string>>({})\n\nconst loading = ref(true)\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\n\nconst canManage = computed(() => admin.can('catalog.manage'))\nconst trashed = computed(() => (landing.value?.deleted_at ?? null) !== null)\nconst locked = computed(() => !canManage.value || saving.value || trashed.value)\n\nconst current = computed(() => JSON.stringify(values.value))\nconst dirty = computed(() => snapshot.value !== '' && current.value !== snapshot.value)\n\nconst state = computed<'saving' | 'unsaved' | 'saved'>(() => {\n if (saving.value) return 'saving'\n\n return dirty.value || creating.value ? 'unsaved' : 'saved'\n})\n\nconst section = computed(\n () =>\n admin.state.manifest?.modules.find((module) => module.id === 'catalog-landings')?.title ??\n t('module.title'),\n)\n\n/** The name follows the field: a rename shows at the top as it is typed. */\nconst title = computed(() => {\n const written = values.value.name as LocalizedValue | string | null | undefined\n\n return localizedValue(written, locales.active.value, '') || t('panel.untitled')\n})\n\nconst subtitle = computed(() => {\n const row = landing.value\n\n if (!row) return undefined\n\n return [row.category ?? t('landing.whole-catalog'), row.url ?? ''].filter(Boolean).join(' · ')\n})\n\nprovideLandingEditor({ landing, values, locked, suggested, list: list.value })\nprovideHistorySubject({ id: computed(() => landing.value?.id ?? null) })\n\nfunction take(detail: LandingDetail): void {\n landing.value = detail\n values.value = formValues(detail)\n snapshot.value = JSON.stringify(values.value)\n}\n\nfunction blank(): void {\n landing.value = null\n values.value = {\n category_id: route.query.category ? Number(route.query.category) : null,\n filters: {},\n name: {},\n slug: {},\n h1: {},\n text_above: {},\n text_below: {},\n sort: null,\n on_category: false,\n position: 0,\n recommended: [],\n seo: {},\n }\n snapshot.value = JSON.stringify(values.value)\n}\n\nasync function load(): Promise<void> {\n errors.value = {}\n\n if (id.value === null) {\n blank()\n loading.value = false\n\n return\n }\n\n loading.value = true\n\n try {\n take(await api.get(id.value))\n } catch (error) {\n toast.danger(message(error))\n void router.push(list.value)\n } finally {\n loading.value = false\n }\n}\n\n/** What a save sends: the form's fields, the set without its half-built facets. */\nfunction payload(): Record<string, unknown> {\n return { ...values.value, filters: cleanSet(values.value.filters as LandingFilters) }\n}\n\nasync function save(): Promise<void> {\n if (saving.value || !canManage.value) return\n\n saving.value = true\n errors.value = {}\n\n try {\n if (id.value === null) {\n const created = await api.create(payload())\n\n take(created)\n toast.success(t('panel.created'))\n await router.replace(`${list.value}/${created.id}`)\n } else {\n take(await api.save(id.value, payload()))\n toast.success(t('panel.saved'))\n }\n } catch (error) {\n const body = (error as { body?: { errors?: Record<string, string[]> } }).body\n\n if (body?.errors && Object.keys(body.errors).length > 0) {\n errors.value = body.errors\n toast.danger(t('panel.save-failed'))\n } else {\n toast.danger(message(error))\n }\n } finally {\n saving.value = false\n }\n}\n\nasync function publish(on: boolean): Promise<void> {\n const row = landing.value\n\n if (!row) return\n\n try {\n const answer = await api.publish(row.id, on)\n\n // Only the state: what is being typed in the form stays.\n landing.value = { ...row, ...answer }\n toast.success(t(on ? 'panel.published-toast' : 'panel.unpublished-toast'))\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nasync function remove(): Promise<void> {\n const row = landing.value\n\n if (!row) return\n\n const agreed = await confirm({\n title: t('panel.delete-title', { name: title.value }),\n message: t('panel.delete-text'),\n confirmText: t('panel.delete'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.remove(row.id)\n toast.success(t('panel.deleted'))\n snapshot.value = current.value\n void router.push(list.value)\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nasync function restore(): Promise<void> {\n const row = landing.value\n\n if (!row) return\n\n try {\n take(await api.restore(row.id))\n toast.success(t('panel.restored'))\n } catch (error) {\n toast.danger(message(error))\n }\n}\n\nfunction leaveGuard(event: BeforeUnloadEvent): void {\n if (dirty.value) event.preventDefault()\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 's') {\n event.preventDefault()\n if (dirty.value || creating.value) void save()\n }\n}\n\nuseBodyKeys(onKeydown)\n\nwatch(id, (next, previous) => {\n // The first save of a new landing moves the address to its id — nothing to read again.\n if (previous === null && next !== null && landing.value?.id === next) return\n\n void load()\n})\n\nonMounted(() => {\n void load()\n window.addEventListener('beforeunload', leaveGuard)\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('beforeunload', leaveGuard)\n})\n\nonBeforeRouteLeave(async () => {\n if (!dirty.value || !canManage.value) return true\n\n return await confirm({\n title: t('panel.leave-title'),\n message: t('panel.leave-text'),\n confirmText: t('panel.leave'),\n cancelText: t('panel.cancel'),\n tone: 'danger',\n })\n})\n\nconst actions = computed<ScreenAction[]>(() => {\n const row = landing.value\n\n if (!row || !canManage.value) return []\n\n if (trashed.value) {\n return [\n { key: 'restore', label: t('panel.restore'), icon: 'refresh', run: () => void restore() },\n ]\n }\n\n const leads: ScreenAction[] = []\n\n if (row.url) {\n leads.push({\n key: 'site',\n label: t('panel.open-site'),\n icon: 'external-link',\n run: () => void window.open(row.url ?? '', '_blank', 'noopener'),\n })\n }\n\n leads.push(\n row.is_published\n ? {\n key: 'unpublish',\n label: t('panel.unpublish'),\n icon: 'eye-off',\n run: () => void publish(false),\n }\n : { key: 'publish', label: t('panel.publish'), icon: 'eye', run: () => void publish(true) },\n {\n key: 'delete',\n label: t('panel.delete'),\n icon: 'trash',\n danger: true,\n menu: true,\n run: () => void remove(),\n },\n )\n\n return leads\n})\n</script>\n\n<template>\n <div class=\"wx-catalog-landing-editor\" @keydown=\"onKeydown\">\n <template v-if=\"loading\">\n <wx-skeleton class=\"wx-catalog-landing-editor__ghost\" title :rows=\"1\" />\n <wx-card><wx-skeleton :rows=\"6\" /></wx-card>\n </template>\n\n <template v-else>\n <wx-screen-head\n divider\n :back=\"list\"\n :back-label=\"section\"\n :title=\"title\"\n :subtitle=\"subtitle\"\n :actions=\"actions\"\n >\n <template #trail>\n <wx-breadcrumb size=\"sm\" :label=\"t('panel.trail')\">\n <wx-breadcrumb-item :as=\"'router-link'\" :to=\"list\">{{ section }}</wx-breadcrumb-item>\n <wx-breadcrumb-item current>{{ title }}</wx-breadcrumb-item>\n </wx-breadcrumb>\n </template>\n\n <template v-if=\"landing\" #title-after>\n <wx-badge v-if=\"trashed\" dot>{{ t('panel.in-bin') }}</wx-badge>\n <wx-badge v-else :type=\"landing.is_published ? 'success' : 'default'\" dot size=\"sm\">\n {{ t(landing.is_published ? 'panel.published' : 'panel.unpublished') }}\n </wx-badge>\n </template>\n </wx-screen-head>\n\n <wx-alert v-if=\"landing?.attention\" type=\"warning\">\n {{ t(`landing.attention-${landing.attention}`) }}\n </wx-alert>\n\n <wx-screen v-model=\"values\" name=\"catalog.landing-form\" :errors=\"errors\" :disabled=\"locked\" />\n\n <wx-action-bar v-if=\"canManage && !trashed\">\n <template #state>\n <wx-save-state :state=\"state\" />\n </template>\n\n <wx-button type=\"primary\" :loading=\"saving\" :disabled=\"!dirty && !creating\" @click=\"save\">\n {{ t(creating ? 'panel.create' : 'panel.save') }}\n </wx-button>\n </wx-action-bar>\n </template>\n </div>\n</template>\n\n<style scoped>\n.wx-catalog-landing-editor {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n container-type: inline-size;\n}\n\n.wx-catalog-landing-editor__ghost {\n max-width: 420px;\n}\n</style>\n"],"names":["props","__props","admin","useAdmin","api","createLandingsApi","route","useRoute","router","useRouter","locales","useLocales","useCatalogLandingsMessages","t","useTranslate","NAMESPACE","message","useErrorText","list","computed","creating","id","landing","ref","values","snapshot","suggested","loading","saving","errors","canManage","trashed","locked","current","dirty","state","section","module","title","written","localizedValue","subtitle","row","provideLandingEditor","provideHistorySubject","take","detail","formValues","blank","load","error","toast","payload","cleanSet","save","created","body","publish","on","answer","remove","confirm","restore","leaveGuard","event","onKeydown","useBodyKeys","watch","next","previous","onMounted","onBeforeUnmount","onBeforeRouteLeave","actions","leads","_createElementBlock","_Fragment","_createVNode","_unref","WxSkeleton","WxCard","WxScreenHead","WxBreadcrumb","WxBreadcrumbItem","_createBlock","WxBadge","WxAlert","WxScreen","$event","WxActionBar","WxSaveState","WxButton","_createTextVNode","_toDisplayString"],"mappings":";;;;;;;;;;;;AA0CA,UAAMA,IAAQC,GAERC,IAAQC,GAAA,GACRC,IAAMC,GAAkBH,CAAK,GAC7BI,IAAQC,GAAA,GACRC,IAASC,GAAA,GACTC,IAAUC,GAAA;AAChB,IAAAC,GAAA;AAEA,UAAMC,IAAIC,GAAaC,EAAS,GAC1BC,IAAUC,GAAA,GAEVC,IAAOC,EAAS,MAAM,GAAGnB,EAAM,IAAI,WAAW,GAC9CoB,IAAWD,EAAS,MAAMb,EAAM,OAAO,OAAO,UAAaA,EAAM,OAAO,OAAO,KAAK,GACpFe,IAAKF,EAAS,MAAOC,EAAS,QAAQ,OAAO,OAAOd,EAAM,OAAO,EAAE,CAAE,GAErEgB,IAAUC,EAA0B,IAAI,GACxCC,IAASD,EAAiB,EAAE,GAC5BE,IAAWF,EAAI,EAAE,GACjBG,IAAYH,EAA4B,EAAE,GAE1CI,IAAUJ,EAAI,EAAI,GAClBK,IAASL,EAAI,EAAK,GAClBM,IAASN,EAA8B,EAAE,GAEzCO,IAAYX,EAAS,MAAMjB,EAAM,IAAI,gBAAgB,CAAC,GACtD6B,IAAUZ,EAAS,OAAOG,EAAQ,OAAO,cAAc,UAAU,IAAI,GACrEU,IAASb,EAAS,MAAM,CAACW,EAAU,SAASF,EAAO,SAASG,EAAQ,KAAK,GAEzEE,IAAUd,EAAS,MAAM,KAAK,UAAUK,EAAO,KAAK,CAAC,GACrDU,IAAQf,EAAS,MAAMM,EAAS,UAAU,MAAMQ,EAAQ,UAAUR,EAAS,KAAK,GAEhFU,IAAQhB,EAAyC,MACjDS,EAAO,QAAc,WAElBM,EAAM,SAASd,EAAS,QAAQ,YAAY,OACpD,GAEKgB,IAAUjB;AAAA,MACd,MACEjB,EAAM,MAAM,UAAU,QAAQ,KAAK,CAACmC,MAAWA,EAAO,OAAO,kBAAkB,GAAG,SAClFxB,EAAE,cAAc;AAAA,IAAA,GAIdyB,IAAQnB,EAAS,MAAM;AAC3B,YAAMoB,IAAUf,EAAO,MAAM;AAE7B,aAAOgB,GAAeD,GAAS7B,EAAQ,OAAO,OAAO,EAAE,KAAKG,EAAE,gBAAgB;AAAA,IAChF,CAAC,GAEK4B,KAAWtB,EAAS,MAAM;AAC9B,YAAMuB,IAAMpB,EAAQ;AAEpB,UAAKoB;AAEL,eAAO,CAACA,EAAI,YAAY7B,EAAE,uBAAuB,GAAG6B,EAAI,OAAO,EAAE,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK;AAAA,IAC/F,CAAC;AAED,IAAAC,GAAqB,EAAE,SAAArB,GAAS,QAAAE,GAAQ,QAAAQ,GAAQ,WAAAN,GAAW,MAAMR,EAAK,OAAO,GAC7E0B,GAAsB,EAAE,IAAIzB,EAAS,MAAMG,EAAQ,OAAO,MAAM,IAAI,GAAG;AAEvE,aAASuB,EAAKC,GAA6B;AACzC,MAAAxB,EAAQ,QAAQwB,GAChBtB,EAAO,QAAQuB,GAAWD,CAAM,GAChCrB,EAAS,QAAQ,KAAK,UAAUD,EAAO,KAAK;AAAA,IAC9C;AAEA,aAASwB,KAAc;AACrB,MAAA1B,EAAQ,QAAQ,MAChBE,EAAO,QAAQ;AAAA,QACb,aAAalB,EAAM,MAAM,WAAW,OAAOA,EAAM,MAAM,QAAQ,IAAI;AAAA,QACnE,SAAS,CAAA;AAAA,QACT,MAAM,CAAA;AAAA,QACN,MAAM,CAAA;AAAA,QACN,IAAI,CAAA;AAAA,QACJ,YAAY,CAAA;AAAA,QACZ,YAAY,CAAA;AAAA,QACZ,MAAM;AAAA,QACN,aAAa;AAAA,QACb,UAAU;AAAA,QACV,aAAa,CAAA;AAAA,QACb,KAAK,CAAA;AAAA,MAAC,GAERmB,EAAS,QAAQ,KAAK,UAAUD,EAAO,KAAK;AAAA,IAC9C;AAEA,mBAAeyB,IAAsB;AAGnC,UAFApB,EAAO,QAAQ,CAAA,GAEXR,EAAG,UAAU,MAAM;AACrB,QAAA2B,GAAA,GACArB,EAAQ,QAAQ;AAEhB;AAAA,MACF;AAEA,MAAAA,EAAQ,QAAQ;AAEhB,UAAI;AACF,QAAAkB,EAAK,MAAMzC,EAAI,IAAIiB,EAAG,KAAK,CAAC;AAAA,MAC9B,SAAS6B,GAAO;AACd,QAAAC,EAAM,OAAOnC,EAAQkC,CAAK,CAAC,GACtB1C,EAAO,KAAKU,EAAK,KAAK;AAAA,MAC7B,UAAA;AACE,QAAAS,EAAQ,QAAQ;AAAA,MAClB;AAAA,IACF;AAGA,aAASyB,IAAmC;AAC1C,aAAO,EAAE,GAAG5B,EAAO,OAAO,SAAS6B,GAAS7B,EAAO,MAAM,OAAyB,EAAA;AAAA,IACpF;AAEA,mBAAe8B,IAAsB;AACnC,UAAI,EAAA1B,EAAO,SAAS,CAACE,EAAU,QAE/B;AAAA,QAAAF,EAAO,QAAQ,IACfC,EAAO,QAAQ,CAAA;AAEf,YAAI;AACF,cAAIR,EAAG,UAAU,MAAM;AACrB,kBAAMkC,IAAU,MAAMnD,EAAI,OAAOgD,GAAS;AAE1C,YAAAP,EAAKU,CAAO,GACZJ,EAAM,QAAQtC,EAAE,eAAe,CAAC,GAChC,MAAML,EAAO,QAAQ,GAAGU,EAAK,KAAK,IAAIqC,EAAQ,EAAE,EAAE;AAAA,UACpD;AACE,YAAAV,EAAK,MAAMzC,EAAI,KAAKiB,EAAG,OAAO+B,EAAA,CAAS,CAAC,GACxCD,EAAM,QAAQtC,EAAE,aAAa,CAAC;AAAA,QAElC,SAASqC,GAAO;AACd,gBAAMM,IAAQN,EAA2D;AAEzE,UAAIM,GAAM,UAAU,OAAO,KAAKA,EAAK,MAAM,EAAE,SAAS,KACpD3B,EAAO,QAAQ2B,EAAK,QACpBL,EAAM,OAAOtC,EAAE,mBAAmB,CAAC,KAEnCsC,EAAM,OAAOnC,EAAQkC,CAAK,CAAC;AAAA,QAE/B,UAAA;AACE,UAAAtB,EAAO,QAAQ;AAAA,QACjB;AAAA;AAAA,IACF;AAEA,mBAAe6B,EAAQC,GAA4B;AACjD,YAAMhB,IAAMpB,EAAQ;AAEpB,UAAKoB;AAEL,YAAI;AACF,gBAAMiB,IAAS,MAAMvD,EAAI,QAAQsC,EAAI,IAAIgB,CAAE;AAG3C,UAAApC,EAAQ,QAAQ,EAAE,GAAGoB,GAAK,GAAGiB,EAAA,GAC7BR,EAAM,QAAQtC,EAAE6C,IAAK,0BAA0B,yBAAyB,CAAC;AAAA,QAC3E,SAASR,GAAO;AACd,UAAAC,EAAM,OAAOnC,EAAQkC,CAAK,CAAC;AAAA,QAC7B;AAAA,IACF;AAEA,mBAAeU,KAAwB;AACrC,YAAMlB,IAAMpB,EAAQ;AAYpB,UAVI,GAACoB,KAUD,CARW,MAAMmB,EAAQ;AAAA,QAC3B,OAAOhD,EAAE,sBAAsB,EAAE,MAAMyB,EAAM,OAAO;AAAA,QACpD,SAASzB,EAAE,mBAAmB;AAAA,QAC9B,aAAaA,EAAE,cAAc;AAAA,QAC7B,YAAYA,EAAE,cAAc;AAAA,QAC5B,MAAM;AAAA,MAAA,CACP;AAID,YAAI;AACF,gBAAMT,EAAI,OAAOsC,EAAI,EAAE,GACvBS,EAAM,QAAQtC,EAAE,eAAe,CAAC,GAChCY,EAAS,QAAQQ,EAAQ,OACpBzB,EAAO,KAAKU,EAAK,KAAK;AAAA,QAC7B,SAASgC,GAAO;AACd,UAAAC,EAAM,OAAOnC,EAAQkC,CAAK,CAAC;AAAA,QAC7B;AAAA,IACF;AAEA,mBAAeY,KAAyB;AACtC,YAAMpB,IAAMpB,EAAQ;AAEpB,UAAKoB;AAEL,YAAI;AACF,UAAAG,EAAK,MAAMzC,EAAI,QAAQsC,EAAI,EAAE,CAAC,GAC9BS,EAAM,QAAQtC,EAAE,gBAAgB,CAAC;AAAA,QACnC,SAASqC,GAAO;AACd,UAAAC,EAAM,OAAOnC,EAAQkC,CAAK,CAAC;AAAA,QAC7B;AAAA,IACF;AAEA,aAASa,EAAWC,GAAgC;AAClD,MAAI9B,EAAM,SAAO8B,EAAM,eAAA;AAAA,IACzB;AAEA,aAASC,EAAUD,GAA4B;AAC7C,OAAKA,EAAM,WAAWA,EAAM,YAAYA,EAAM,IAAI,YAAA,MAAkB,QAClEA,EAAM,eAAA,IACF9B,EAAM,SAASd,EAAS,UAAYkC,EAAA;AAAA,IAE5C;AAEA,IAAAY,GAAYD,CAAS,GAErBE,GAAM9C,GAAI,CAAC+C,GAAMC,MAAa;AAE5B,MAAIA,MAAa,QAAQD,MAAS,QAAQ9C,EAAQ,OAAO,OAAO8C,KAE3DnB,EAAA;AAAA,IACP,CAAC,GAEDqB,GAAU,MAAM;AACd,MAAKrB,EAAA,GACL,OAAO,iBAAiB,gBAAgBc,CAAU;AAAA,IACpD,CAAC,GAEDQ,GAAgB,MAAM;AACpB,aAAO,oBAAoB,gBAAgBR,CAAU;AAAA,IACvD,CAAC,GAEDS,GAAmB,YACb,CAACtC,EAAM,SAAS,CAACJ,EAAU,QAAc,KAEtC,MAAM+B,EAAQ;AAAA,MACnB,OAAOhD,EAAE,mBAAmB;AAAA,MAC5B,SAASA,EAAE,kBAAkB;AAAA,MAC7B,aAAaA,EAAE,aAAa;AAAA,MAC5B,YAAYA,EAAE,cAAc;AAAA,MAC5B,MAAM;AAAA,IAAA,CACP,CACF;AAED,UAAM4D,KAAUtD,EAAyB,MAAM;AAC7C,YAAMuB,IAAMpB,EAAQ;AAEpB,UAAI,CAACoB,KAAO,CAACZ,EAAU,cAAc,CAAA;AAErC,UAAIC,EAAQ;AACV,eAAO;AAAA,UACL,EAAE,KAAK,WAAW,OAAOlB,EAAE,eAAe,GAAG,MAAM,WAAW,KAAK,MAAA;AAAM,YAAKiD;YAAQ;AAAA,QAAE;AAI5F,YAAMY,IAAwB,CAAA;AAE9B,aAAIhC,EAAI,OACNgC,EAAM,KAAK;AAAA,QACT,KAAK;AAAA,QACL,OAAO7D,EAAE,iBAAiB;AAAA,QAC1B,MAAM;AAAA,QACN,KAAK,MAAA;AAAM,UAAK,OAAO,KAAK6B,EAAI,OAAO,IAAI,UAAU,UAAU;AAAA;AAAA,MAAA,CAChE,GAGHgC,EAAM;AAAA,QACJhC,EAAI,eACA;AAAA,UACE,KAAK;AAAA,UACL,OAAO7B,EAAE,iBAAiB;AAAA,UAC1B,MAAM;AAAA,UACN,KAAK,MAAA;AAAM,YAAK4C,EAAQ,EAAK;AAAA;AAAA,QAAA,IAE/B,EAAE,KAAK,WAAW,OAAO5C,EAAE,eAAe,GAAG,MAAM,OAAO,KAAK,MAAA;AAAM,UAAK4C,EAAQ,EAAI;AAAA,UAAA;AAAA,QAC1F;AAAA,UACE,KAAK;AAAA,UACL,OAAO5C,EAAE,cAAc;AAAA,UACvB,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,KAAK,MAAA;AAAM,YAAK+C,GAAA;AAAA;AAAA,QAAO;AAAA,MACzB,GAGKc;AAAA,IACT,CAAC;2BAICC,EA8CM,OAAA;AAAA,MA9CD,OAAM;AAAA,MAA6B,WAAAV;AAAA,IAAA;MACtBtC,EAAA,cAAhBgD,EAGWC,GAAA,EAAA,KAAA,KAAA;AAAA,QAFTC,EAAwEC,EAAAC,CAAA,GAAA;AAAA,UAA3D,OAAM;AAAA,UAAmC,OAAA;AAAA,UAAO,MAAM;AAAA,QAAA;QACnEF,EAA4CC,EAAAE,EAAA,GAAA,MAAA;AAAA,qBAAnC,MAAyB;AAAA,YAAzBH,EAAyBC,EAAAC,CAAA,GAAA,EAAX,MAAM,GAAC;AAAA,UAAA;;;sBAGhCJ,EAuCWC,GAAA,EAAA,KAAA,KAAA;AAAA,QAtCTC,EAqBiBC,EAAAG,EAAA,GAAA;AAAA,UApBf,SAAA;AAAA,UACC,MAAM/D,EAAA;AAAA,UACN,cAAYkB,EAAA;AAAA,UACZ,OAAOE,EAAA;AAAA,UACP,UAAUG,GAAA;AAAA,UACV,SAASgC,GAAA;AAAA,QAAA;UAEC,SACT,MAGgB;AAAA,YAHhBI,EAGgBC,EAAAI,EAAA,GAAA;AAAA,cAHD,MAAK;AAAA,cAAM,OAAOJ,EAAAjE,CAAA,EAAC,aAAA;AAAA,YAAA;yBAChC,MAAqF;AAAA,gBAArFgE,EAAqFC,EAAAK,CAAA,GAAA;AAAA,kBAAhE,IAAI;AAAA,kBAAgB,IAAIjE,EAAA;AAAA,gBAAA;6BAAM,MAAa;AAAA,wBAAVkB,EAAA,KAAO,GAAA,CAAA;AAAA,kBAAA;;;gBAC7DyC,EAA4DC,EAAAK,CAAA,GAAA,EAAxC,SAAA,MAAO;AAAA,6BAAC,MAAW;AAAA,wBAAR7C,EAAA,KAAK,GAAA,CAAA;AAAA,kBAAA;;;;;;;;;UAIxBhB,EAAA;kBAAU;AAAA,kBACxB,MAA+D;AAAA,cAA/CS,EAAA,cAAhBqD,EAA+DN,EAAAO,CAAA,GAAA;AAAA;gBAAtC,KAAA;AAAA,cAAA;2BAAI,MAAuB;AAAA,sBAApBP,EAAAjE,CAAA,EAAC,cAAA,CAAA,GAAA,CAAA;AAAA,gBAAA;;0BACjCuE,EAEWN,EAAAO,CAAA,GAAA;AAAA;gBAFO,MAAM/D,EAAA,MAAQ,eAAY,YAAA;AAAA,gBAA0B,KAAA;AAAA,gBAAI,MAAK;AAAA,cAAA;2BAC7E,MAAuE;AAAA,sBAApEwD,EAAAjE,CAAA,EAAES,EAAA,MAAQ,eAAY,oBAAA,mBAAA,CAAA,GAAA,CAAA;AAAA,gBAAA;;;;;;;QAKfA,EAAA,OAAS,kBAAzB8D,EAEWN,EAAAQ,EAAA,GAAA;AAAA;UAFyB,MAAK;AAAA,QAAA;qBACvC,MAAiD;AAAA,gBAA9CR,EAAAjE,CAAA,EAAC,qBAAsBS,EAAA,MAAQ,SAAS,EAAA,CAAA,GAAA,CAAA;AAAA,UAAA;;;QAG7CuD,EAA8FC,EAAAS,EAAA,GAAA;AAAA,sBAA1E/D,EAAA;AAAA,wDAAAA,EAAM,QAAAgE;AAAA,UAAE,MAAK;AAAA,UAAwB,QAAQ3D,EAAA;AAAA,UAAS,UAAUG,EAAA;AAAA,QAAA;QAE/DF,EAAA,UAAcC,EAAA,cAAnCqD,EAQgBN,EAAAW,EAAA,GAAA,EAAA,KAAA,KAAA;AAAA,UAPH,SACT,MAAgC;AAAA,YAAhCZ,EAAgCC,EAAAY,EAAA,GAAA,EAAhB,OAAOvD,EAAA,SAAK,MAAA,GAAA,CAAA,OAAA,CAAA;AAAA,UAAA;qBAG9B,MAEY;AAAA,YAFZ0C,EAEYC,EAAAa,EAAA,GAAA;AAAA,cAFD,MAAK;AAAA,cAAW,SAAS/D,EAAA;AAAA,cAAS,UAAQ,CAAGM,EAAA,SAAK,CAAKd,EAAA;AAAA,cAAW,SAAOkC;AAAA,YAAA;yBAClF,MAAiD;AAAA,gBAA9CsC,EAAAC,EAAAf,EAAAjE,CAAA,EAAEO,EAAA,QAAQ,iBAAA,YAAA,CAAA,GAAA,CAAA;AAAA,cAAA;;;;;;;;;;"}
|