@webx-ui/module-banners 0.3.2 → 0.3.3
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/{BannerEditorPage-j7WlEaek.js → BannerEditorPage-B8e-IHkN.js} +2 -2
- package/dist/{BannerEditorPage-j7WlEaek.js.map → BannerEditorPage-B8e-IHkN.js.map} +1 -1
- package/dist/BannersPage-D7hpUcBn.js +607 -0
- package/dist/BannersPage-D7hpUcBn.js.map +1 -0
- package/dist/{index-3RALKrkh.js → index-QnpLuOX2.js} +552 -528
- package/dist/index-QnpLuOX2.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/style.css +1 -1
- package/dist/types.d.ts +2 -0
- package/package.json +5 -5
- package/dist/BannersPage-Dl_BCozz.js +0 -591
- package/dist/BannersPage-Dl_BCozz.js.map +0 -1
- package/dist/index-3RALKrkh.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BannersPage-D7hpUcBn.js","sources":["../src/PlaceDialog.vue","../src/PlacePane.vue","../src/BannersPage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { nextTick, onMounted, ref, useTemplateRef } from 'vue'\nimport {\n useLocales,\n useModal,\n WxButton,\n WxDialog,\n WxFormItem,\n WxInput,\n WxSpace,\n type LocalizedValue,\n} from '@webx-ui/core'\nimport { useAdmin, useTranslate } from '@webx-ui/module-admin'\nimport { createBannersApi } from './api'\nimport { useBannersMessages } from './i18n'\nimport type { PlaceRow } from './types'\n\n/**\n * A place of somebody's own: a name, and a key when it is new (§5.4).\n *\n * The key does not follow the name the way a page's address follows its title: it is typed into\n * `banners('…')` by hand, and a key that quietly became `promo-2` would be a template asking for\n * a place that is not there. For the same reason a rename never touches it.\n *\n * The name is translated, and required in the default language — which is what the list falls\n * back on in a panel open in a language nobody named the place in.\n */\ndefineOptions({ name: 'WxBannerPlaceDialog' })\n\nconst props = withDefaults(defineProps<{ place?: PlaceRow | null }>(), { place: null })\n\nconst { open, resolve, dismiss } = useModal<PlaceRow>()\n\nconst api = createBannersApi(useAdmin())\nconst locales = useLocales()\nuseBannersMessages()\n\nconst t = useTranslate('webx-banners')\n\nconst editing = props.place !== null\n\n/*\n * Every language when the server sent them (`titles`), the one the list shows otherwise — filed\n * under the default language, which is where a place with one name has it.\n */\nfunction initial(): LocalizedValue {\n if (props.place === null) return {}\n if (props.place.titles) return { ...props.place.titles }\n\n const first = locales.list.value[0]?.code\n\n return first === undefined ? {} : { [first]: props.place.title }\n}\n\nconst key = ref(props.place?.key ?? '')\nconst title = ref<LocalizedValue>(initial())\nconst saving = ref(false)\nconst errors = ref<Record<string, string[]>>({})\nconst field = useTemplateRef<HTMLElement>('field')\n\nonMounted(async () => {\n await nextTick()\n field.value?.querySelector('input')?.focus()\n})\n\n/** Something written in at least one language: the server says which one it needs. */\nfunction written(): boolean {\n return Object.values(title.value).some((words) => words.trim() !== '')\n}\n\n/** The first line of a refusal under a field that may be named by language: `title.en`. */\nfunction errorOf(name: string): string | undefined {\n const found = Object.keys(errors.value).find((one) => one === name || one.startsWith(`${name}.`))\n\n return found === undefined ? undefined : errors.value[found]?.[0]\n}\n\nasync function submit(): Promise<void> {\n if (!written() || saving.value) return\n\n saving.value = true\n errors.value = {}\n\n try {\n resolve(\n editing && props.place !== null\n ? await api.renamePlace(props.place.key, title.value)\n : await api.createPlace({ key: key.value.trim(), title: title.value }),\n )\n } catch (error) {\n // Refused under its own field: a key that is taken or spelled in a way no template could\n // write, a name missing in the default language.\n errors.value = (error as { body?: { errors?: Record<string, string[]> } }).body?.errors ?? {}\n } finally {\n saving.value = false\n }\n}\n</script>\n\n<template>\n <wx-dialog\n v-model:open=\"open\"\n :title=\"editing ? t('places.rename-title') : t('places.new-title')\"\n :width=\"440\"\n >\n <wx-form-item :label=\"t('places.field-title')\" :error=\"errorOf('title')\" required>\n <div ref=\"field\">\n <wx-input\n v-model=\"title\"\n localized\n :aria-label=\"t('places.field-title')\"\n @keyup.enter=\"submit\"\n />\n </div>\n </wx-form-item>\n\n <wx-form-item\n :label=\"t('places.field-key')\"\n :error=\"errorOf('key')\"\n :help=\"editing ? undefined : t('places.key-help')\"\n required\n >\n <wx-input\n v-model=\"key\"\n :disabled=\"editing\"\n :aria-label=\"t('places.field-key')\"\n autocomplete=\"off\"\n @keyup.enter=\"submit\"\n />\n </wx-form-item>\n\n <template #footer>\n <wx-space size=\"sm\">\n <wx-button variant=\"outline\" @click=\"dismiss()\">{{ t('places.cancel') }}</wx-button>\n <wx-button\n type=\"primary\"\n :loading=\"saving\"\n :disabled=\"!written() || key.trim() === ''\"\n @click=\"submit\"\n >\n {{ editing ? t('places.save') : t('places.create') }}\n </wx-button>\n </wx-space>\n </template>\n </wx-dialog>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport {\n confirm,\n toast,\n WxAlert,\n WxBadge,\n WxEmpty,\n WxIcon,\n WxSegmented,\n WxSkeleton,\n WxSortableList,\n WxTooltip,\n type SegmentedValue,\n} from '@webx-ui/core'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxPreviewThumb,\n WxRowMenu,\n WxScreenHead,\n type RowAction,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport { createBannersApi } from './api'\nimport { useBannersMessages } from './i18n'\nimport type { BannerRow, PlaceRow } from './types'\n\n/**\n * The banners of one place: the right-hand half of the section, and the whole screen on a phone.\n *\n * The order here is the order on the site, and a place is small, so the list is the whole place\n * and a drag writes it whole (`reorder`). The bin is the same list turned over: nothing to drag,\n * and a banner in it opens nothing — it can only come back.\n *\n * The way back is drawn here and not by the pane around it: the drawer a narrow screen opens this\n * in has no close of its own on purpose (CLAUDE.md §4).\n */\ndefineOptions({ name: 'WxBannerPlacePane' })\n\nconst props = withDefaults(\n defineProps<{\n place: PlaceRow\n base: string\n /** False in the drawer a narrow screen opens this in. */\n inline?: boolean\n }>(),\n { inline: true },\n)\n\nconst emit = defineEmits<{\n back: []\n /** Something moved in or out of the place: the count beside its name is stale. */\n changed: []\n}>()\n\nconst admin = useAdmin()\nconst api = createBannersApi(admin)\nconst route = useRoute()\nconst router = useRouter()\nuseBannersMessages()\n\nconst t = useTranslate('webx-banners')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst rows = ref<BannerRow[]>([])\nconst loading = ref(true)\n\nconst canManage = computed(() => admin.can('banners.manage'))\n\n/* The bin is in the address with the place, so coming back from a banner lands where one was. */\nconst view = computed<SegmentedValue>({\n get: () => (route.query.view === 'trashed' ? 'trashed' : 'live'),\n set: (value) => {\n void router.replace({\n query: { ...route.query, view: value === 'trashed' ? 'trashed' : undefined },\n })\n },\n})\n\nconst inBin = computed(() => view.value === 'trashed')\n\nconst views = computed(() => [\n { value: 'live', label: t('banner.all') },\n { value: 'trashed', label: t('banner.trashed'), icon: 'trash' as const },\n])\n\nconst sortable = computed(() => canManage.value && !inBin.value && rows.value.length > 1)\n\nconst layout = computed(() => {\n const known = ['single', 'random', 'slider']\n\n return known.includes(props.place.layout) ? t(`places.layout-${props.place.layout}`) : ''\n})\n\n/*\n * The pictures of the place, large: a click on one opens them all, the full pictures, in the\n * order the place shows them (`useLightbox`).\n */\nconst pictured = computed(() => rows.value.filter((row) => row.thumb))\nconst pictures = computed(() =>\n pictured.value.map((row) => ({\n src: row.image ?? row.thumb!,\n thumb: row.thumb!,\n alt: row.title,\n caption: row.title,\n })),\n)\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n rows.value = await api.list(props.place.key, inBin.value)\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nwatch(inBin, () => void load())\nvoid load()\n\nfunction edit(row: BannerRow): string {\n return `${props.base}/${row.id}`\n}\n\nfunction add(): void {\n void router.push({ path: `${props.base}/new`, query: { place: props.place.key } })\n}\n\n/**\n * The order on screen, written whole. The list is already in its new order (`WxSortableList`\n * reorders the model before it says so), so a failure has to put it back rather than leave the\n * screen disagreeing with the database.\n */\nasync function reorder(): Promise<void> {\n try {\n await api.reorder(\n props.place.key,\n rows.value.map((row) => row.id),\n )\n } catch (error) {\n toast.danger(message(error, t('banner.reorder-failed')))\n await load()\n }\n}\n\n/*\n * On and off from the list, through the form's own door: there is no switch of its own in the\n * API, and a second way to write a banner would be a second set of rules to keep in step. What\n * the form would refuse — a look the config dropped since — is refused here the same way.\n */\nasync function toggle(row: BannerRow): Promise<void> {\n try {\n const detail = await api.get(row.id)\n\n await api.save(row.id, { ...detail.values, enabled: !row.enabled })\n toast.success(row.enabled ? t('banner.switched-off') : t('banner.switched-on'))\n } catch (error) {\n toast.danger(message(error))\n } finally {\n await load()\n }\n}\n\nasync function remove(row: BannerRow): Promise<void> {\n const agreed = await confirm({\n title: t('banner.delete-title', { name: row.title }),\n message: t('banner.delete-text'),\n confirmText: t('banner.delete'),\n cancelText: t('banner.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.remove(row.id)\n toast.success(t('banner.deleted'))\n emit('changed')\n } catch (error) {\n toast.danger(message(error))\n } finally {\n await load()\n }\n}\n\nasync function restore(row: BannerRow): Promise<void> {\n try {\n await api.restore(row.id)\n toast.success(t('banner.restored'))\n emit('changed')\n } catch (error) {\n toast.danger(message(error))\n } finally {\n await load()\n }\n}\n\nfunction actionsFor(row: BannerRow): RowAction[] {\n if (inBin.value) {\n return canManage.value\n ? [\n {\n key: 'restore',\n icon: 'refresh',\n label: t('banner.restore'),\n run: () => void restore(row),\n },\n ]\n : []\n }\n\n const open: RowAction = {\n key: 'open',\n icon: 'edit',\n label: t('banner.open'),\n run: () => void router.push(edit(row)),\n }\n\n if (!canManage.value) return [open]\n\n return [\n open,\n {\n key: 'toggle',\n icon: row.enabled ? 'eye-off' : 'eye',\n label: row.enabled ? t('banner.disable') : t('banner.enable'),\n run: () => void toggle(row),\n },\n {\n key: 'delete',\n icon: 'trash',\n label: t('banner.delete'),\n danger: true,\n run: () => void remove(row),\n },\n ]\n}\n\n/* The one thing this pane exists for, in its head; on a narrow pane it stays a button. */\nconst actions = computed<ScreenAction[]>(() =>\n canManage.value && !inBin.value\n ? [{ key: 'new', label: t('banner.new'), icon: 'plus', primary: true, run: add }]\n : [],\n)\n</script>\n\n<template>\n <div class=\"wx-banner-place\">\n <wx-screen-head\n :level=\"3\"\n :back=\"!props.inline\"\n :back-label=\"t('places.places')\"\n :title=\"place.title\"\n :actions=\"actions\"\n :collapse-below=\"420\"\n @back=\"emit('back')\"\n >\n <template v-if=\"place.declared\" #title-after>\n <wx-tooltip :content=\"t('places.declared-help')\">\n <span class=\"wx-banner-place__lock\" tabindex=\"0\" :aria-label=\"t('places.declared')\">\n <wx-icon name=\"lock\" size=\"sm\" />\n </span>\n </wx-tooltip>\n </template>\n </wx-screen-head>\n\n <!--\n How a template asks for this place, where somebody writing one will look for it: the key\n is the whole contract between the panel and the site (decision 7).\n -->\n <p class=\"wx-banner-place__usage\">\n <span>{{ t('places.usage') }}</span>\n <code>banners('{{ place.key }}')</code>\n <span v-if=\"layout\" class=\"wx-banner-place__layout\">· {{ layout }}</span>\n </p>\n\n <wx-segmented\n v-model=\"view\"\n class=\"wx-banner-place__views\"\n size=\"sm\"\n :options=\"views\"\n :aria-label=\"t('banner.all')\"\n />\n\n <wx-skeleton v-if=\"loading && rows.length === 0\" :rows=\"4\" />\n\n <wx-empty\n v-else-if=\"rows.length === 0\"\n :title=\"inBin ? t('banner.empty-bin') : t('banner.empty')\"\n :description=\"inBin ? undefined : t('banner.empty-help')\"\n />\n\n <template v-else>\n <!-- A grip and not the whole row: the row opens a banner, and a row that both opens and\n drags is one where one of the two happens by accident. -->\n <wx-sortable-list\n v-model=\"rows\"\n class=\"wx-banner-place__list\"\n hoverable\n :class=\"{ 'is-loading': loading }\"\n plain\n item-key=\"id\"\n :handle=\"sortable ? 'grip' : 'row'\"\n :item-label=\"(item: BannerRow) => item.title\"\n :disabled=\"!sortable\"\n @move=\"reorder\"\n >\n <template #default=\"{ item }\">\n <component\n :is=\"inBin ? 'div' : 'router-link'\"\n :to=\"inBin ? undefined : edit(item)\"\n class=\"wx-banner-row\"\n :class=\"{ 'is-off': !item.enabled && !inBin }\"\n >\n <span class=\"wx-banner-row__thumb\">\n <wx-preview-thumb\n v-if=\"item.thumb\"\n fill\n :items=\"pictures\"\n :start=\"pictured.indexOf(item)\"\n >\n <img :src=\"item.thumb\" alt=\"\" loading=\"lazy\" />\n </wx-preview-thumb>\n <wx-icon v-else name=\"image\" size=\"sm\" :aria-label=\"t('banner.no-picture')\" />\n </span>\n\n <span class=\"wx-banner-row__body\">\n <span class=\"wx-banner-row__title\">{{ item.title }}</span>\n\n <span v-if=\"item.video || (!item.enabled && !inBin)\" class=\"wx-banner-row__facts\">\n <wx-badge v-if=\"item.video\" size=\"sm\" type=\"info\">{{ t('banner.video') }}</wx-badge>\n <wx-badge v-if=\"!item.enabled && !inBin\" dot size=\"sm\">{{\n t('banner.disabled')\n }}</wx-badge>\n </span>\n </span>\n </component>\n </template>\n\n <template #actions=\"{ item }\">\n <wx-row-menu :actions=\"actionsFor(item)\" :label=\"item.title\" />\n </template>\n </wx-sortable-list>\n\n <!-- What a drag does here, said once under the list. -->\n <wx-alert\n v-if=\"sortable\"\n class=\"wx-banner-place__note\"\n type=\"info\"\n :description=\"t('banner.order')\"\n />\n </template>\n </div>\n</template>\n\n<style scoped>\n.wx-banner-place {\n display: flex;\n flex-direction: column;\n gap: var(--wx-space-12);\n min-width: 0;\n padding: var(--wx-gap, var(--wx-space-16));\n}\n\n.wx-banner-place__lock {\n display: inline-flex;\n color: var(--wx-text-muted);\n}\n\n.wx-banner-place__usage {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--wx-space-6);\n margin: 0;\n color: var(--wx-text-muted);\n font-size: var(--wx-font-size-sm);\n}\n\n.wx-banner-place__usage code {\n padding: 0 var(--wx-space-4);\n border-radius: var(--wx-radius-xs);\n background: var(--wx-bg-subtle);\n color: var(--wx-text-default);\n font-family: var(--wx-font-family-mono);\n /* Copied whole, as somebody writing a template would: a click selects all of it. */\n user-select: all;\n}\n\n.wx-banner-place__views {\n align-self: flex-start;\n}\n\n.wx-banner-place__list.is-loading {\n opacity: 0.6;\n}\n\n.wx-banner-place__list :deep(.wx-sortable-list__row) {\n gap: var(--wx-space-4);\n padding-inline: var(--wx-space-4);\n}\n\n.wx-banner-row {\n display: flex;\n align-items: center;\n gap: var(--wx-space-12);\n /* The row is the target: a short title should not leave half the line dead. */\n flex: 1 1 auto;\n width: 100%;\n min-width: 0;\n padding-block: var(--wx-space-8);\n color: inherit;\n text-decoration: none;\n}\n\n/* Off is not gone: still here, still in its place, just quieter than what is on the site. */\n.wx-banner-row.is-off .wx-banner-row__thumb,\n.wx-banner-row.is-off .wx-banner-row__title {\n opacity: 0.55;\n}\n\n.wx-banner-row__thumb {\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 80px;\n aspect-ratio: 16 / 9;\n overflow: hidden;\n border-radius: var(--wx-radius-xs);\n background: var(--wx-bg-fill);\n color: var(--wx-text-muted);\n}\n\n.wx-banner-row__thumb img {\n width: 100%;\n height: 100%;\n /* A thumbnail wider than its frame would otherwise hold the row open (CLAUDE.md §4). */\n min-width: 0;\n object-fit: cover;\n}\n\n.wx-banner-row__body {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--wx-space-4);\n min-width: 0;\n}\n\n.wx-banner-row__title {\n min-width: 0;\n overflow: hidden;\n font-weight: var(--wx-font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\na.wx-banner-row:hover .wx-banner-row__title {\n color: var(--wx-color-primary);\n}\n\n.wx-banner-row__facts {\n display: flex;\n flex-wrap: wrap;\n gap: var(--wx-space-4);\n}\n\n.wx-banner-place__note {\n margin-top: var(--wx-space-4);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useRoute, useRouter, type LocationQueryRaw } from 'vue-router'\nimport {\n confirm,\n createModal,\n toast,\n WxCard,\n WxEmpty,\n WxIcon,\n WxIndicator,\n WxListDetail,\n WxSkeleton,\n WxText,\n} from '@webx-ui/core'\nimport {\n useAdmin,\n useErrorText,\n useTranslate,\n WxListScreen,\n WxRowMenu,\n type RowAction,\n type ScreenAction,\n} from '@webx-ui/module-admin'\nimport { createBannersApi } from './api'\nimport { useBannersMessages } from './i18n'\nimport PlaceDialog from './PlaceDialog.vue'\nimport PlacePane from './PlacePane.vue'\nimport type { PlaceRow } from './types'\n\n/**\n * The section: the places of the site on the left, the banners of one of them on the right\n * (§5.4) — the shape of the menus, for the same reason: somebody who opens this is arranging one\n * place, not choosing between them, so the first one opens by itself where there is room for it.\n * On a phone it does not: there the same line would raise a panel over a list nobody touched.\n *\n * A declared place is on the list before anything was ever saved into it (decision 1) — its row\n * in the table is made by its first banner — so places are named by key throughout, not by id.\n */\nconst props = withDefaults(defineProps<{ base?: string }>(), { base: '/banners' })\n\nconst admin = useAdmin()\nconst api = createBannersApi(admin)\nconst route = useRoute()\nconst router = useRouter()\nuseBannersMessages()\n\nconst t = useTranslate('webx-banners')\n/* Not the server's `message`: the panel says how a request failed in its own words. */\nconst message = useErrorText()\n\nconst places = ref<PlaceRow[]>([])\nconst loading = ref(true)\nconst open = ref(false)\nconst detailInline = ref(true)\n\nconst canManage = computed(() => admin.can('banners.manage'))\n\nconst edit = createModal<PlaceRow, { place?: PlaceRow | null }>(PlaceDialog)\n\nconst title = computed(\n () =>\n admin.state.manifest?.modules.find((module) => module.id === 'banners')?.title ??\n t('module.banners'),\n)\n\n/** Which place is open, kept in the address — so \"back\" from a banner lands on its place. */\nconst current = computed<string | null>(() => {\n const asked = route.query.place\n\n return typeof asked === 'string' && asked !== '' ? asked : null\n})\n\nconst chosen = computed(() => places.value.find((place) => place.key === current.value) ?? null)\n\nasync function load(): Promise<void> {\n loading.value = true\n\n try {\n places.value = await api.places()\n } catch (error) {\n toast.danger(message(error))\n } finally {\n loading.value = false\n }\n}\n\nvoid load()\n\n/*\n * The first place, where there is a column to draw it in — only once the width is measured\n * (`detail-inline` says so), so a phone does not get a drawer over a list it never touched.\n */\nwatch([places, chosen, detailInline], () => {\n if (!detailInline.value || places.value.length === 0 || chosen.value !== null) return\n\n void router.replace({ query: { ...route.query, place: places.value[0]!.key } })\n})\n\nwatch(chosen, (place) => {\n if (place !== null && detailInline.value) open.value = true\n})\n\n/* Coming back from a banner on a phone lands on its place, and that is the drawer, open. */\nif (current.value !== null) open.value = true\n\nfunction choose(place: PlaceRow): void {\n const query: LocationQueryRaw = { ...route.query, place: place.key }\n\n // The bin of one place is not the bin of the next.\n delete query.view\n void router.replace({ query })\n open.value = true\n}\n\nasync function add(): Promise<void> {\n const made = await edit({ place: null })\n\n if (!made) return\n\n toast.success(t('places.created'))\n await load()\n choose(made)\n}\n\nasync function rename(place: PlaceRow): Promise<void> {\n const saved = await edit({ place })\n\n if (!saved) return\n\n toast.success(t('places.renamed'))\n await load()\n}\n\nasync function remove(place: PlaceRow): Promise<void> {\n const agreed = await confirm({\n title: t('places.delete-title', { place: place.title }),\n message: t('places.delete-text'),\n confirmText: t('places.delete'),\n cancelText: t('places.cancel'),\n tone: 'danger',\n })\n\n if (!agreed) return\n\n try {\n await api.removePlace(place.key)\n toast.success(t('places.deleted'))\n\n if (current.value === place.key) {\n const rest = { ...route.query }\n\n delete rest.place\n delete rest.view\n void router.replace({ query: rest })\n open.value = false\n }\n } catch (error) {\n // The one refusal worth its own words: something is still in it — perhaps only in the bin,\n // which the count beside the name does not show (§5.6).\n toast.danger(message(error))\n } finally {\n await load()\n }\n}\n\nfunction actionsFor(place: PlaceRow): RowAction[] {\n if (!canManage.value || place.declared) return []\n\n return [\n { key: 'rename', icon: 'edit', label: t('places.rename'), run: () => void rename(place) },\n {\n key: 'delete',\n icon: 'trash',\n // Said in the line itself, since a switched-off line cannot carry a tooltip: an empty\n // place is the only kind that goes (decision 1).\n label: place.count > 0 ? t('places.delete-empty-first') : t('places.delete'),\n danger: true,\n disabled: place.count > 0,\n run: () => void remove(place),\n },\n ]\n}\n\nconst actions = computed<ScreenAction[]>(() =>\n canManage.value\n ? [{ key: 'new-place', label: t('places.new'), icon: 'plus', run: () => void add() }]\n : [],\n)\n</script>\n\n<template>\n <wx-list-screen :title=\"title\" :actions=\"actions\" :card=\"false\">\n <wx-card class=\"wx-banners\" padding=\"none\">\n <wx-list-detail\n v-model:open=\"open\"\n class=\"wx-banners__panes\"\n :list-width=\"300\"\n :detail-min=\"440\"\n :detail-label=\"t('places.places')\"\n @detail-inline=\"detailInline = $event\"\n >\n <template #list>\n <wx-skeleton\n v-if=\"loading && places.length === 0\"\n class=\"wx-banners__loading\"\n :rows=\"3\"\n />\n\n <wx-empty\n v-else-if=\"places.length === 0\"\n :title=\"t('places.empty')\"\n :description=\"t('places.empty-help')\"\n />\n\n <ul v-else class=\"wx-banners__list\">\n <li v-for=\"place in places\" :key=\"place.key\" class=\"wx-banners__row\">\n <button\n type=\"button\"\n class=\"wx-banners__open\"\n :class=\"{ 'is-current': place.key === current }\"\n @click=\"choose(place)\"\n >\n <span class=\"wx-banners__name\">\n <wx-text truncate weight=\"medium\">{{ place.title }}</wx-text>\n <wx-icon\n v-if=\"place.declared\"\n class=\"wx-banners__lock\"\n name=\"lock\"\n size=\"sm\"\n :aria-label=\"t('places.declared')\"\n />\n <wx-indicator\n class=\"wx-banners__count\"\n type=\"neutral\"\n :value=\"place.count\"\n :label=\"t('places.count')\"\n />\n </span>\n\n <wx-text size=\"sm\" tone=\"muted\" mono truncate>banners('{{ place.key }}')</wx-text>\n </button>\n\n <wx-row-menu\n v-if=\"actionsFor(place).length > 0\"\n :actions=\"actionsFor(place)\"\n :label=\"place.title\"\n />\n </li>\n </ul>\n </template>\n\n <template #detail=\"{ inline, back }\">\n <place-pane\n v-if=\"chosen\"\n :key=\"chosen.key\"\n :place=\"chosen\"\n :base=\"props.base\"\n :inline=\"inline\"\n @back=\"back\"\n @changed=\"load\"\n />\n </template>\n\n <template #empty>\n <wx-empty :title=\"t('places.choose')\" :description=\"t('places.choose-help')\" />\n </template>\n </wx-list-detail>\n </wx-card>\n </wx-list-screen>\n</template>\n\n<style>\n/*\n * What scrolls here is the page, the way it does on every other list of the panel. `clip`, not\n * `hidden`: `hidden` would make this a scroll container, and everything sticky inside would pin\n * itself to a box that never moves (CLAUDE.md §4).\n */\n.wx-banners > .wx-card__body {\n display: flex;\n flex-direction: column;\n overflow: clip;\n border-radius: inherit;\n}\n</style>\n\n<style scoped>\n.wx-banners__loading {\n padding: var(--wx-space-16);\n}\n\n.wx-banners__list {\n margin: 0;\n padding: var(--wx-space-8);\n list-style: none;\n}\n\n.wx-banners__row {\n display: flex;\n align-items: center;\n gap: var(--wx-space-4);\n margin: 0;\n padding-inline: var(--wx-space-8);\n border-radius: var(--wx-radius-sm);\n}\n\n.wx-banners__row:has(.is-current) {\n background: var(--wx-bg-subtle);\n}\n\n.wx-banners__open {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: var(--wx-space-2);\n flex: 1 1 auto;\n min-width: 0;\n padding-block: var(--wx-space-8);\n padding-inline: 0;\n border: 0;\n background: none;\n font: inherit;\n color: inherit;\n text-align: start;\n cursor: pointer;\n}\n\n.wx-banners__open.is-current {\n color: var(--wx-color-primary);\n}\n\n.wx-banners__name {\n display: flex;\n align-items: center;\n gap: var(--wx-space-6);\n min-width: 0;\n max-width: 100%;\n}\n\n.wx-banners__lock {\n flex: none;\n color: var(--wx-text-muted);\n}\n\n.wx-banners__count {\n flex: 0 0 auto;\n}\n</style>\n"],"names":["props","__props","open","resolve","dismiss","useModal","api","createBannersApi","useAdmin","locales","useLocales","useBannersMessages","t","useTranslate","editing","initial","first","key","ref","title","saving","errors","field","useTemplateRef","onMounted","nextTick","written","words","errorOf","name","found","one","submit","error","_createBlock","_unref","WxDialog","$event","_createVNode","WxSpace","WxButton","WxFormItem","_createElementVNode","WxInput","emit","__emit","admin","route","useRoute","router","useRouter","message","useErrorText","rows","loading","canManage","computed","view","value","inBin","views","sortable","layout","pictured","row","pictures","load","toast","watch","edit","add","reorder","toggle","detail","remove","confirm","restore","actionsFor","actions","_openBlock","_createElementBlock","_hoisted_1","WxScreenHead","WxTooltip","WxIcon","_hoisted_3","_toDisplayString","_hoisted_4","WxSegmented","WxSkeleton","WxEmpty","_Fragment","WxSortableList","_normalizeClass","item","_withCtx","_resolveDynamicComponent","_hoisted_5","WxPreviewThumb","_hoisted_7","_hoisted_8","_hoisted_9","WxBadge","WxRowMenu","WxAlert","places","detailInline","createModal","PlaceDialog","module","current","asked","chosen","place","choose","query","made","rename","rest","WxListScreen","WxCard","WxListDetail","_cache","_renderList","WxText","_createTextVNode","WxIndicator","inline","back","PlacePane"],"mappings":"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"}
|