@bobbykim/manguito-cms-admin 0.6.1 → 0.6.2

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.
Files changed (46) hide show
  1. package/dist/assets/{ChangePasswordView-Cu5tB24J.js → ChangePasswordView-2g4WN8W1.js} +1 -1
  2. package/dist/assets/ConfirmDialog-_23g_1zv.js +1 -0
  3. package/dist/assets/ContentFormView-BtRp4dKL.js +1 -0
  4. package/dist/assets/ContentListView-Dqeigsd6.js +1 -0
  5. package/dist/assets/ContentSettingsView-DXBl-Sgl.js +1 -0
  6. package/dist/assets/LoginView-bDYuN8s-.js +1 -0
  7. package/dist/assets/MediaDetailView-Bvikhn1E.js +1 -0
  8. package/dist/assets/{MediaLibraryView-Ss0vIfJ1.js → MediaLibraryView-Db4Ne4kw.js} +1 -1
  9. package/dist/assets/{MediaThumbnail-Ckiw3oQ9.js → MediaThumbnail-B1j3EJAS.js} +1 -1
  10. package/dist/assets/Pagination-Bi7I6pas.js +1 -0
  11. package/dist/assets/{RolesView-DO-Tb2Yr.js → RolesView-UWBl91JE.js} +1 -1
  12. package/dist/assets/TaxonomyFormView-FTESoS4u.js +1 -0
  13. package/dist/assets/TaxonomyListView-WriH284W.js +1 -0
  14. package/dist/assets/UserFormView-BRMjuvR2.js +1 -0
  15. package/dist/assets/{UserListView-CZukprIO.js → UserListView-f37clqgU.js} +1 -1
  16. package/dist/assets/{content--2XYr_UQ.js → content-BbyFohW5.js} +1 -1
  17. package/dist/assets/form-state-BWi4MQBH.js +97 -0
  18. package/dist/assets/index-DLFCFdeR.js +2 -0
  19. package/dist/assets/{index-BYJBLBFc.css → index-HRIgzrKA.css} +1 -1
  20. package/dist/assets/{media-DvQfZD4o.js → media-3GZT7Q_i.js} +1 -1
  21. package/dist/assets/{schema-B-RKX_ep.js → schema-DGpYmX9j.js} +1 -1
  22. package/dist/assets/{taxonomy-DC-6wyg3.js → taxonomy-C_3USBAZ.js} +1 -1
  23. package/dist/assets/{useNotification-Cmvg0Rzg.js → useNotification-CmqzkyhR.js} +1 -1
  24. package/dist/assets/{useTabIndicator-CvEsGBJh.js → useTabIndicator-CQE2dO2W.js} +1 -1
  25. package/dist/assets/{users-DVibZ_HD.js → users-DyKJ5vRI.js} +1 -1
  26. package/dist/index.html +3 -3
  27. package/package.json +1 -1
  28. package/src/components/fields/ParagraphEmbed.vue +90 -10
  29. package/src/components/fields/__tests__/ParagraphEmbed.test.ts +154 -2
  30. package/src/utils/__tests__/{taxonomy-form.test.ts → form-state.test.ts} +5 -5
  31. package/src/utils/form-state.ts +20 -0
  32. package/src/views/content/ContentFormView.vue +3 -12
  33. package/src/views/taxonomy/TaxonomyFormView.vue +2 -2
  34. package/dist/assets/ConfirmDialog-B7nxdDge.js +0 -1
  35. package/dist/assets/ContentFormView-CFQEZZid.js +0 -1
  36. package/dist/assets/ContentListView-BftGcgU1.js +0 -1
  37. package/dist/assets/ContentSettingsView-DLYsyUlu.js +0 -1
  38. package/dist/assets/LoginView-CozTK_GW.js +0 -1
  39. package/dist/assets/MediaDetailView-ByqqmxcZ.js +0 -1
  40. package/dist/assets/Pagination-BIf7mQy7.js +0 -1
  41. package/dist/assets/TaxonomyFormView-D8FV6n4a.js +0 -1
  42. package/dist/assets/TaxonomyListView-C-VzXAxl.js +0 -1
  43. package/dist/assets/UserFormView-CGEqYM-x.js +0 -1
  44. package/dist/assets/field-defaults-Coq6Ej9B.js +0 -97
  45. package/dist/assets/index-BaJYEgrK.js +0 -2
  46. package/src/utils/taxonomy-form.ts +0 -20
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect } from 'vitest'
2
- import { mount } from '@vue/test-utils'
3
- import { defineComponent, h } from 'vue'
2
+ import { mount, flushPromises } from '@vue/test-utils'
3
+ import { defineComponent, h, ref, type Ref } from 'vue'
4
4
  import type { ParsedField } from '@bobbykim/manguito-cms-core'
5
5
  import ParagraphEmbed from '../ParagraphEmbed.vue'
6
6
 
@@ -62,3 +62,155 @@ describe('ParagraphEmbed, one-to-many (unchanged)', () => {
62
62
  expect(w.emitted('update:modelValue')?.[0]).toEqual([[{ order: 0 }]])
63
63
  })
64
64
  })
65
+
66
+ describe('ParagraphEmbed, one-to-many reordering', () => {
67
+ const three = () => [{ order: 0, url: 'a' }, { order: 1, url: 'b' }, { order: 2, url: 'c' }]
68
+ const btn = (w: ReturnType<typeof mountWith>, label: string) => w.find(`button[aria-label="${label}"]`)
69
+
70
+ it('moves an item earlier or later, renumbering order', async () => {
71
+ // MUTATION: emit the list unchanged, or skip renumbering order.
72
+ const w = mountWith('one-to-many', three())
73
+ await btn(w, 'Move item 2 earlier').trigger('click')
74
+ expect(w.emitted('update:modelValue')?.[0]).toEqual([
75
+ [{ order: 0, url: 'b' }, { order: 1, url: 'a' }, { order: 2, url: 'c' }],
76
+ ])
77
+ await btn(w, 'Move item 2 later').trigger('click')
78
+ expect(w.emitted('update:modelValue')?.[1]).toEqual([
79
+ [{ order: 0, url: 'a' }, { order: 1, url: 'c' }, { order: 2, url: 'b' }],
80
+ ])
81
+ })
82
+
83
+ it('offers no move past either end', () => {
84
+ // MUTATION: render both buttons on every item.
85
+ const w = mountWith('one-to-many', three())
86
+ expect(btn(w, 'Move item 1 earlier').exists()).toBe(false)
87
+ expect(btn(w, 'Move item 1 later').exists()).toBe(true)
88
+ expect(btn(w, 'Move item 3 later').exists()).toBe(false)
89
+ const single = mountWith('one-to-many', [{ order: 0 }])
90
+ expect(single.findAll('button[aria-label^="Move item"]')).toHaveLength(0)
91
+ })
92
+
93
+ it('keeps focus on the moved item, on its other button at an end', async () => {
94
+ // MUTATION: drop the focus step in moveParagraph. Focus falls to <body>
95
+ // after each move.
96
+ const Parent = defineComponent({
97
+ setup() {
98
+ const items = ref<Record<string, unknown>[]>(three())
99
+ return () => h(ParagraphEmbed, {
100
+ field: field('one-to-many'), formComponent: StubForm, modelValue: items.value,
101
+ 'onUpdate:modelValue': (v: unknown) => { items.value = v as Record<string, unknown>[] },
102
+ })
103
+ },
104
+ })
105
+ const w = mount(Parent, { attachTo: document.body })
106
+ const press = async (label: string) => {
107
+ const b = w.get(`button[aria-label="${label}"]`)
108
+ ;(b.element as HTMLElement).focus()
109
+ await b.trigger('click')
110
+ await flushPromises()
111
+ }
112
+ const focused = () => document.activeElement?.getAttribute('aria-label')
113
+ await press('Move item 3 earlier')
114
+ expect(focused()).toBe('Move item 2 earlier')
115
+ await press('Move item 2 earlier')
116
+ expect(focused()).toBe('Move item 1 later')
117
+ await press('Move item 1 later')
118
+ expect(focused()).toBe('Move item 2 later')
119
+ await press('Move item 2 later') // last: no later button
120
+ expect(focused()).toBe('Move item 3 earlier')
121
+ w.unmount()
122
+ })
123
+
124
+ it('moves focus within its own list when items hold nested paragraph lists', async () => {
125
+ // MUTATION: look the item and its button up with unscoped descendant
126
+ // selectors. Item 0's nested list also has data-item-index="1", so focus
127
+ // lands on a nested button instead of the outer item.
128
+ const NestedForm = defineComponent({
129
+ props: { modelValue: { type: Object, default: null }, disabled: Boolean },
130
+ setup(p) {
131
+ return () => (p.modelValue as { nested?: unknown[] } | null)?.nested
132
+ ? h(ParagraphEmbed, { field: field('one-to-many'), modelValue: (p.modelValue as { nested: unknown[] }).nested, formComponent: StubForm })
133
+ : h('span')
134
+ },
135
+ })
136
+ const Parent = defineComponent({
137
+ setup() {
138
+ const items = ref<Record<string, unknown>[]>([
139
+ { order: 0, nested: [{ order: 0 }, { order: 1 }, { order: 2 }] }, { order: 1 }, { order: 2 },
140
+ ])
141
+ return () => h(ParagraphEmbed, {
142
+ field: field('one-to-many'), formComponent: NestedForm, modelValue: items.value,
143
+ 'onUpdate:modelValue': (v: unknown) => { items.value = v as Record<string, unknown>[] },
144
+ })
145
+ },
146
+ })
147
+ const w = mount(Parent, { attachTo: document.body })
148
+ const outer = (i: number) => (w.element as HTMLElement).querySelector<HTMLElement>(`:scope > .mt-1 > [data-item-index="${i}"]`)!
149
+ const b = outer(2).querySelector<HTMLElement>('[data-move="earlier"]')!
150
+ b.focus()
151
+ await b.click()
152
+ await flushPromises()
153
+ expect(document.activeElement?.closest('[data-item-index]')).toBe(outer(1))
154
+ expect(document.activeElement?.getAttribute('data-move')).toBe('earlier')
155
+ w.unmount()
156
+ })
157
+
158
+ // Captures its item's url on mount, as MediaUpload loads its preview and
159
+ // ReferenceSelect its labels.
160
+ const CaptureForm = defineComponent({
161
+ props: { modelValue: { type: Object, default: null }, disabled: Boolean },
162
+ setup(p) {
163
+ const captured = (p.modelValue as { url?: string } | null)?.url ?? 'new'
164
+ return () => h('span', { class: 'captured' }, captured)
165
+ },
166
+ })
167
+ // A parent bound with v-model, as the form views are, over `items`.
168
+ const mountBound = (items: Ref<Record<string, unknown>[]>) =>
169
+ mount(defineComponent({
170
+ setup() {
171
+ return () => h(ParagraphEmbed, {
172
+ field: field('one-to-many'), formComponent: CaptureForm, modelValue: items.value,
173
+ 'onUpdate:modelValue': (v: unknown) => { items.value = v as Record<string, unknown>[] },
174
+ })
175
+ },
176
+ }))
177
+ const shown = (w: ReturnType<typeof mountBound>) => w.findAll('.captured').map((c) => c.text())
178
+ const click = async (w: ReturnType<typeof mountBound>, label: string) => {
179
+ await w.get(`button[aria-label="${label}"]`).trigger('click')
180
+ await flushPromises()
181
+ }
182
+
183
+ it("keeps each item's field state with the item through a move, a remove and an add", async () => {
184
+ // MUTATION: key by index. Each position then keeps the child mounted for
185
+ // the item that was there, showing the old item's captured url.
186
+ const w = mountBound(ref(three()))
187
+ await click(w, 'Move item 2 earlier')
188
+ expect(shown(w)).toEqual(['b', 'a', 'c'])
189
+ await click(w, 'Remove item 1')
190
+ expect(shown(w)).toEqual(['a', 'c'])
191
+ await click(w, 'Move item 1 later')
192
+ expect(shown(w)).toEqual(['c', 'a'])
193
+ await w.findAll('button').find((b) => b.text().includes('Add Link'))!.trigger('click')
194
+ await flushPromises()
195
+ expect(shown(w)).toEqual(['c', 'a', 'new'])
196
+ })
197
+
198
+ it('keys a list loaded from outside, so its items move', async () => {
199
+ // MUTATION: never resync the keys from the model. A list loaded after
200
+ // mount (an edit read) then has no keys to move, and the move does nothing.
201
+ const items = ref<Record<string, unknown>[]>([])
202
+ const w = mountBound(items)
203
+ items.value = [{ order: 0, url: 'x' }, { order: 1, url: 'y' }]
204
+ await flushPromises()
205
+ await click(w, 'Move item 2 earlier')
206
+ expect(shown(w)).toEqual(['y', 'x'])
207
+ })
208
+
209
+ it('hides the move buttons when disabled', () => {
210
+ // MUTATION: render them regardless of disabled (Remove is already hidden when disabled).
211
+ const w = mount(ParagraphEmbed, {
212
+ props: { field: field('one-to-many'), modelValue: three(), formComponent: StubForm, disabled: true },
213
+ })
214
+ expect(w.findAll('button[aria-label^="Move item"]')).toHaveLength(0)
215
+ })
216
+ })
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect } from 'vitest'
2
2
  import type { ParsedField } from '@bobbykim/manguito-cms-core'
3
- import { initialTaxonomyForm } from '../taxonomy-form'
3
+ import { initialFormState } from '../form-state'
4
4
 
5
5
  const base = { label: 'X', required: false, nullable: true, order: 0, validation: { required: false } }
6
6
 
@@ -38,18 +38,18 @@ const fields: ParsedField[] = [
38
38
  },
39
39
  ] as unknown as ParsedField[]
40
40
 
41
- describe('initialTaxonomyForm', () => {
41
+ describe('initialFormState', () => {
42
42
  it('includes relation fields, from the source or their empty default', () => {
43
43
  // MUTATION: keep leaving paragraph and many-to-many fields out (before
44
44
  // #55). The taxonomy form then cannot show or edit them, although the
45
45
  // edit read now returns them.
46
- const form = initialTaxonomyForm(fields, {
46
+ const form = initialFormState(fields, {
47
47
  name: 'Tag', parent: 'p-1', blocks: [{ title: 'b' }], hero: { title: 'h' }, related: ['t-2'],
48
48
  })
49
49
  expect(form).toMatchObject({ blocks: [{ title: 'b' }], hero: { title: 'h' }, related: ['t-2'] })
50
50
 
51
51
  // Empty defaults follow cardinality: a list for "many", null for "one".
52
- expect(initialTaxonomyForm(fields)).toEqual({
52
+ expect(initialFormState(fields)).toEqual({
53
53
  name: '', parent: null, blocks: [], hero: null, related: [],
54
54
  })
55
55
  })
@@ -57,6 +57,6 @@ describe('initialTaxonomyForm', () => {
57
57
  it('leaves programmatic fields out: they are computed and never saved', () => {
58
58
  // MUTATION: put programmatic fields into the form. Save would then send a
59
59
  // computed value back to the api.
60
- expect(initialTaxonomyForm(fields, { name: 'Tag', computed: 'x' })).not.toHaveProperty('computed')
60
+ expect(initialFormState(fields, { name: 'Tag', computed: 'x' })).not.toHaveProperty('computed')
61
61
  })
62
62
  })
@@ -0,0 +1,20 @@
1
+ import type { ParsedField } from '@bobbykim/manguito-cms-core'
2
+ import { defaultForField } from './field-defaults'
3
+
4
+ // A content or taxonomy form's starting state, which is also what Save sends.
5
+ // Every field the edit read returns is included, relation fields too: the read
6
+ // loads paragraph fields and many-to-many link ids (#55). A field with no stored
7
+ // value starts at its empty default (null for a 'one' relation, [] for a 'many'
8
+ // one). Programmatic fields are computed at read time and never submitted, so
9
+ // they stay out.
10
+ export function initialFormState(
11
+ fields: ParsedField[],
12
+ source?: Record<string, unknown>
13
+ ): Record<string, unknown> {
14
+ const form: Record<string, unknown> = {}
15
+ for (const field of fields) {
16
+ if (field.field_type === 'programmatic') continue
17
+ form[field.name] = source?.[field.name] ?? defaultForField(field)
18
+ }
19
+ return form
20
+ }
@@ -12,7 +12,7 @@ import { useContentStore } from '../../stores/content'
12
12
  import ConfirmDialog from '../../components/shared/ConfirmDialog.vue'
13
13
  import { useTabIndicator } from '../../composables/useTabIndicator'
14
14
  import { componentFor, fieldExtraProps } from '../../components/fields/field-registry'
15
- import { defaultForField } from '../../utils/field-defaults'
15
+ import { initialFormState } from '../../utils/form-state'
16
16
 
17
17
  const route = useRoute()
18
18
  const router = useRouter()
@@ -83,17 +83,8 @@ const slugChanged = computed(
83
83
  // ── Form helpers ──────────────────────────────────────────────────────────────
84
84
 
85
85
  function initForm(source?: Record<string, unknown>) {
86
- const f: Record<string, unknown> = {}
87
- if (!isSingleton.value) {
88
- f.slug = source?.slug ?? ''
89
- }
90
- for (const field of allFields.value) {
91
- // Programmatic fields are computed at read time — never edited or submitted,
92
- // so they stay out of the form state (and therefore the save payload).
93
- if (field.field_type === 'programmatic') continue
94
- f[field.name] = source?.[field.name] ?? defaultForField(field)
95
- }
96
- form.value = f
86
+ const state = initialFormState(allFields.value, source)
87
+ form.value = isSingleton.value ? state : { slug: source?.slug ?? '', ...state }
97
88
  isPublished.value = source?.published === true
98
89
  if (source?.slug) originalSlug.value = String(source.slug)
99
90
  }
@@ -8,7 +8,7 @@ import { useFormValidation } from '../../composables/useFormValidation'
8
8
  import { useNotification } from '../../composables/useNotification'
9
9
  import { useSchemaStore } from '../../stores/schema'
10
10
  import { useTaxonomyStore } from '../../stores/taxonomy'
11
- import { initialTaxonomyForm } from '../../utils/taxonomy-form'
11
+ import { initialFormState } from '../../utils/form-state'
12
12
  import { componentFor, fieldExtraProps } from '../../components/fields/field-registry'
13
13
  import ConfirmDialog from '../../components/shared/ConfirmDialog.vue'
14
14
 
@@ -44,7 +44,7 @@ const showDeleteConfirm = ref(false)
44
44
  // ── Form helpers ──────────────────────────────────────────────────────────────
45
45
 
46
46
  function initForm(source?: Record<string, unknown>) {
47
- form.value = initialTaxonomyForm(allFields.value, source)
47
+ form.value = initialFormState(allFields.value, source)
48
48
  }
49
49
 
50
50
  function updateField(name: string, value: unknown) {
@@ -1 +0,0 @@
1
- import{E as e,a as t,c as n,g as r,l as i,ut as a}from"./schema-B-RKX_ep.js";var o={class:`fixed inset-0 z-50 flex items-center justify-center bg-black/50`,role:`dialog`,"aria-modal":`true`},s={class:`mx-4 w-full max-w-sm rounded-lg bg-white p-6 shadow-xl`},c={class:`text-sm text-gray-700`},l={class:`mt-6 flex justify-end gap-3`},u=r({__name:`ConfirmDialog`,props:{message:{},onConfirm:{type:Function},onCancel:{type:Function}},setup(r){return(u,d)=>(e(),i(t,{to:`body`},[n(`div`,o,[n(`div`,s,[n(`p`,c,a(r.message),1),n(`div`,l,[n(`button`,{type:`button`,class:`rounded-md px-4 py-2 text-sm font-medium text-gray-700 ring-1 ring-inset ring-gray-300 hover:bg-gray-50`,onClick:d[0]||=(...e)=>r.onCancel&&r.onCancel(...e)},` Cancel `),n(`button`,{type:`button`,class:`rounded-md bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700`,onClick:d[1]||=(...e)=>r.onConfirm&&r.onConfirm(...e)},` Confirm `)])])])]))}});export{u as t};
@@ -1 +0,0 @@
1
- import{A as e,B as t,E as n,O as r,P as ee,W as i,c as a,ct as o,d as s,g as c,i as l,j as te,l as u,lt as d,m as ne,s as f,t as re,u as p,ut as m,w as ie,x as ae}from"./schema-B-RKX_ep.js";import{c as oe,n as se,s as h,t as ce,u as le}from"./index-BaJYEgrK.js";import{a as ue,i as de,n as fe,r as pe,t as me}from"./field-defaults-Coq6Ej9B.js";import{t as he}from"./useNotification-Cmvg0Rzg.js";import{t as ge}from"./content--2XYr_UQ.js";import{t as g}from"./ConfirmDialog-B7nxdDge.js";import{t as _e}from"./useTabIndicator-CvEsGBJh.js";var ve={key:0,class:`flex items-center justify-center py-20`},ye={key:1,class:`py-12 text-center text-sm text-gray-500`},be={key:2},xe={class:`mb-[22px] flex flex-wrap items-start justify-between gap-4`},Se={class:`mb-1.5 text-[11px] font-bold uppercase tracking-[.06em] text-faint`},Ce={class:`text-[25px] font-bold tracking-tight text-ink`},we={class:`flex shrink-0 flex-wrap items-center gap-[9px]`},Te=[`disabled`],Ee=[`disabled`],De=[`disabled`],Oe=[`disabled`],ke={key:0,class:`mb-[18px] rounded-2xl border border-card-border bg-white p-5 shadow-[0_1px_2px_rgba(24,24,48,0.04),0_8px_22px_rgba(24,24,48,0.04)]`},Ae={class:`mt-2 flex flex-wrap items-center gap-[10px]`},_=[`disabled`],v={key:0,class:`mt-[9px] text-[12.5px] text-[#D9913C]`},y={key:1,class:`mt-1 text-sm text-red-600`,role:`alert`},b=[`data-tab`,`onClick`],x={class:`space-y-5`},S={key:2,class:`mt-4 text-sm text-red-600`,role:`alert`},C=c({__name:`ContentFormView`,setup(c){let C=h(),w=oe(),T=ce(),{can:E}=se(),{errors:D,validate:O,mergeServerErrors:je,clearErrors:Me,setError:Ne}=de(),Pe=he(),Fe=re(),k=ge(),A=f(()=>C.params.type),j=f(()=>C.params.id),M=f(()=>Fe.contentTypes[A.value]),N=f(()=>M.value?.fields??[]),P=f(()=>M.value?.ui.tabs??[]),F=f(()=>M.value?.only_one===!0),I=f(()=>F.value?`singleton`:j.value?`edit`:`create`),L=t(null),R=t({}),z=t(!1),B=t(``),V=t(!1),H=t(!0),U=t(!1),W=t(``),G=t(!1),K=t(!1),q=t(null),J=t(0),Ie=f(()=>P.value[J.value]?.name??``),Y=t(null),{left:Le,width:Re}=_e(Y,Ie),ze=f(()=>{if(P.value.length===0)return N.value;let e=P.value[J.value];return e?e.fields.map(e=>N.value.find(t=>t.name===e)).filter(e=>e!==void 0):N.value}),X=f(()=>I.value===`edit`&&z.value&&R.value.slug!==B.value);function Z(e){let t={};F.value||(t.slug=e?.slug??``);for(let n of N.value)n.field_type!==`programmatic`&&(t[n.name]=e?.[n.name]??me(n));R.value=t,z.value=e?.published===!0,e?.slug&&(B.value=String(e.slug))}function Be(e,t){R.value[e]=t}async function Q(e){let t=await T.get(`/content/${A.value}/${e}`);t.ok?(L.value=t.data,Z(t.data)):W.value=t.error.message}ie(async()=>{if(!M.value){H.value=!1;return}I.value===`edit`&&j.value||I.value===`singleton`&&j.value?await Q(j.value):Z(),H.value=!1}),te(j,async(e,t)=>{e!==t&&(H.value=!0,V.value=!1,Me(),e?await Q(e):(L.value=null,Z()),H.value=!1)});async function $(e){U.value=!0,W.value=``;let t={...R.value};e!==void 0&&(t.published=e);let n;if(n=I.value===`create`?await T.post(`/content/${A.value}`,t):I.value===`singleton`?await T.put(`/content/${A.value}`,t):await T.patch(`/content/${A.value}/${j.value}`,t),U.value=!1,!n.ok){let e=n.error;if((e.code===`PUBLISH_VALIDATION_ERROR`||e.code===`VALIDATION_ERROR`)&&e.details){let{fieldErrors:t,other:n}=ue(e.details,N.value.map(e=>e.name));je(t),n.length>0&&(W.value=[e.message,...n].join(` `))}else e.code===`SLUG_CONFLICT`?Ne(`slug`,`This slug is already taken.`):W.value=e.message;return}L.value=n.data,z.value=n.data.published===!0,B.value=String(n.data.slug??``),V.value=!1,k.invalidate(A.value),Pe.success(`Saved.`),I.value===`create`&&w.replace({name:`content-edit`,params:{type:A.value,id:String(n.data.id)}})}function Ve(){if(O(N.value,R.value)){if(X.value){q.value=()=>$(),G.value=!0;return}$()}}function He(){if(O(N.value,R.value,!0)){if(X.value){q.value=()=>$(!0),G.value=!0;return}$(!0)}}function Ue(){$(!1)}function We(){G.value=!1,q.value&&=(q.value(),null)}function Ge(){G.value=!1,q.value=null}async function Ke(){K.value=!1,U.value=!0;let e=await T.del(`/content/${A.value}/${j.value}`);if(U.value=!1,!e.ok){W.value=e.error.message;return}k.invalidate(A.value),w.push({name:`content-list`,params:{type:A.value}})}let qe=f(()=>{if(I.value===`create`)return`New ${M.value?.label??``}`;if(I.value===`singleton`)return M.value?.label??``;let e=N.value.find(e=>e.field_type===`text/plain`);return(e?String(L.value?.[e.name]??``):``)||(M.value?.label??``)});return(t,c)=>H.value?(n(),s(`div`,ve,[...c[3]||=[a(`span`,{class:`inline-block h-6 w-6 animate-spin rounded-full border-2 border-indigo-600 border-t-transparent`,"aria-hidden":`true`},null,-1)]])):M.value?(n(),s(`div`,be,[a(`div`,xe,[a(`div`,null,[a(`p`,Se,m(M.value.label),1),a(`h1`,Ce,m(qe.value),1)]),a(`div`,we,[i(E)(`content:delete`)&&I.value===`edit`?(n(),s(`button`,{key:0,type:`button`,disabled:U.value,class:`inline-flex items-center gap-1.5 rounded-[10px] border border-[#F3D2D7] bg-white px-[15px] py-2.5 text-[13px] font-semibold text-[#E1495B] transition-colors hover:bg-[#FDF2F4] disabled:cursor-not-allowed disabled:opacity-50`,onClick:c[0]||=e=>K.value=!0},` Delete `,8,Te)):p(``,!0),i(E)(`content:edit`)?(n(),s(l,{key:1},[z.value?(n(),s(`button`,{key:0,type:`button`,disabled:U.value,class:`rounded-[10px] border border-[#E4E3EE] bg-white px-4 py-2.5 text-[13px] font-semibold text-[#3D3D52] transition-colors hover:bg-surface disabled:cursor-not-allowed disabled:opacity-50`,onClick:Ue},` Unpublish `,8,Ee)):(n(),s(`button`,{key:1,type:`button`,disabled:U.value,class:`rounded-[10px] border border-[#E4E3EE] bg-white px-4 py-2.5 text-[13px] font-semibold text-[#3D3D52] transition-colors hover:bg-surface disabled:cursor-not-allowed disabled:opacity-50`,onClick:He},` Publish `,8,De)),a(`button`,{type:`button`,disabled:U.value,class:`inline-flex items-center gap-1.5 rounded-[10px] bg-indigo-600 px-4 py-2.5 text-[13px] font-semibold text-white shadow-[0_3px_10px_rgba(91,87,232,0.3)] transition-all hover:bg-indigo-700 hover:shadow-[0_6px_18px_rgba(91,87,232,0.4)] disabled:cursor-not-allowed disabled:opacity-50`,onClick:Ve},m(U.value?`Saving…`:`Save draft`),9,Oe)],64)):p(``,!0)])]),F.value?p(``,!0):(n(),s(`div`,ke,[c[4]||=a(`label`,{for:`slug-field`,class:`block text-[13px] font-semibold text-[#3D3D52]`},[ne(` Slug `),a(`span`,{class:`ml-0.5 text-red-500`,"aria-hidden":`true`},`*`)],-1),a(`div`,Ae,[ee(a(`input`,{id:`slug-field`,"onUpdate:modelValue":c[1]||=e=>R.value.slug=e,type:`text`,disabled:U.value||z.value&&!V.value,class:o([`block min-w-[180px] flex-1 rounded-[10px] border px-[13px] py-[11px] font-mono text-sm focus:outline-none focus:ring-2`,i(D).slug?`border-red-300 focus:border-red-400 focus:ring-red-200`:`border-[#E4E3EE] bg-surface focus:border-indigo-400 focus:ring-indigo-200`,(U.value||z.value&&!V.value)&&`cursor-not-allowed bg-gray-100 opacity-70`]),placeholder:`url-slug`},null,10,_),[[le,R.value.slug]]),z.value&&!V.value?(n(),s(`button`,{key:0,type:`button`,class:`shrink-0 rounded-[10px] border border-[#E4E3EE] bg-white px-4 py-2.5 text-sm font-semibold text-[#3D3D52] transition-colors hover:bg-surface`,onClick:c[2]||=e=>V.value=!0},` Edit slug `)):p(``,!0)]),z.value?(n(),s(`p`,v,` Changing this slug will break existing links. `)):p(``,!0),i(D).slug?(n(),s(`p`,y,m(i(D).slug),1)):p(``,!0)])),P.value.length>1?(n(),s(`div`,{key:1,ref_key:`tabBarRef`,ref:Y,class:`relative mb-[22px] flex gap-0 overflow-x-auto border-b border-card-border`},[(n(!0),s(l,null,r(P.value,(e,t)=>(n(),s(`button`,{key:e.name,"data-tab":e.name,type:`button`,class:o([`mr-6 whitespace-nowrap bg-none px-0.5 py-[11px] text-sm transition-colors`,J.value===t?`font-semibold text-indigo-600`:`font-medium text-faint hover:text-[#8A8A9E]`]),onClick:e=>J.value=t},m(e.label),11,b))),128)),a(`div`,{class:`absolute -bottom-px h-0.5 rounded-full bg-indigo-600 transition-[left,width] duration-300`,style:d({left:`${i(Le)}px`,width:`${i(Re)}px`})},null,4)],512)):p(``,!0),a(`div`,x,[(n(!0),s(l,null,r(ze.value,t=>(n(),u(e(i(fe)(t)),ae({key:t.name,field:t,"model-value":R.value[t.name],error:i(D)[t.name],disabled:U.value},{ref_for:!0},i(pe)(t),{"onUpdate:modelValue":e=>Be(t.name,e)}),null,16,[`field`,`model-value`,`error`,`disabled`,`onUpdate:modelValue`]))),128))]),W.value?(n(),s(`p`,S,m(W.value),1)):p(``,!0),G.value?(n(),u(g,{key:3,message:`This item is published. Changing its slug will break existing links. Continue?`,"on-confirm":We,"on-cancel":Ge})):p(``,!0),K.value?(n(),u(g,{key:4,message:`Are you sure you want to delete this item? This action cannot be undone.`,"on-confirm":Ke,"on-cancel":()=>K.value=!1},null,8,[`on-cancel`])):p(``,!0)])):(n(),s(`div`,ye,` Content type not found. `))}});export{C as default};
@@ -1 +0,0 @@
1
- import{B as e,E as t,O as n,P as r,W as i,c as a,ct as o,d as s,g as c,h as l,i as u,j as d,m as ee,s as f,t as te,u as p,ut as m,w as h}from"./schema-B-RKX_ep.js";import{a as g,c as _,n as v,s as ne,t as y,u as b}from"./index-BaJYEgrK.js";import{t as x}from"./content--2XYr_UQ.js";import{t as S}from"./Pagination-BIf7mQy7.js";var re=c({__name:`StatusBadge`,props:{published:{type:Boolean}},setup(e){return(n,r)=>(t(),s(`span`,{class:o([`inline-flex items-center rounded-full px-[11px] py-1 text-xs font-semibold`,e.published?`bg-[#E7F6EC] text-[#1E8E4E]`:`bg-[#FBF1DF] text-[#B5790E]`])},m(e.published?`Published`:`Draft`),3))}}),ie={key:0},ae={key:1},oe={class:`mb-[22px] flex flex-wrap items-center justify-between gap-4`},se={class:`text-[26px] font-bold tracking-tight text-ink`},ce={class:`mb-4 flex h-[38px] items-center gap-2 rounded-[10px] border border-card-border bg-[#FBFBFD] px-[11px] text-[13px] transition-colors focus-within:border-indigo-400`},C=[`placeholder`],w={key:0,class:`space-y-2`},T={key:1,class:`rounded-[16px] border border-dashed border-gray-300 p-12 text-center`},E={class:`text-sm text-muted`},D={key:2,class:`overflow-hidden rounded-[16px] border border-card-border bg-white shadow-[0_1px_2px_rgba(24,24,48,0.04),0_10px_28px_rgba(24,24,48,0.04)]`},O={class:`w-full text-sm`},k={class:`divide-y divide-[#F4F3F9]`},A=[`onClick`],j={class:`px-[22px] py-4 text-[14.5px] font-semibold text-ink`},M={class:`px-[22px] py-4 font-mono text-[12.5px] text-muted`},N={class:`px-[22px] py-4`},P={class:`px-[22px] py-4 text-[13px] text-faint`},F={key:3,class:`mt-4 flex justify-center`},I=c({__name:`ContentListView`,setup(o){let c=ne(),I=_(),L=y(),{can:R}=v(),z=te(),B=x(),V=f(()=>c.params.type),H=f(()=>z.contentTypes[V.value]),U=f(()=>H.value?.only_one===!0),W=f(()=>H.value?.fields.find(e=>e.field_type===`text/plain`)?.name??`id`),G=e([]),K=e(0),q=e(1),J=e(!1),Y=e(``);function le(e){return typeof e!=`string`||!e?`—`:new Date(e).toLocaleDateString(void 0,{year:`numeric`,month:`short`,day:`numeric`})}async function X(e){J.value=!0;let t=Y.value.trim();if(t===``){let t=B.getPage(V.value,e,50);if(t){G.value=t,K.value=B.total,J.value=!1;return}}let n=t===``?``:`&search=${encodeURIComponent(t)}`,r=await L.get(`/content/${V.value}?page=${e}&per_page=50${n}`);J.value=!1,r.ok&&(G.value=r.data,K.value=r.meta?.total??r.data.length,t===``&&(B.total=K.value,B.setPage(V.value,e,50,r.data)))}let Z=g(()=>{q.value=1,X(1)},300);async function Q(){let e=await L.get(`/content/${V.value}`),t=e.ok?e.data[0]:void 0;t?I.replace({name:`content-edit`,params:{type:V.value,id:String(t.id)}}):I.replace({name:`content-new`,params:{type:V.value}})}h(async()=>{if(H.value){if(U.value){await Q();return}await X(q.value)}}),d(V,async()=>{if(q.value=1,G.value=[],H.value){if(U.value){await Q();return}await X(1)}});function ue(e){q.value=e,X(e)}function de(e){I.push({name:`content-edit`,params:{type:V.value,id:String(e.id)}})}function $(){I.push({name:`content-new`,params:{type:V.value}})}return(e,o)=>U.value||!H.value?(t(),s(`div`,ie)):(t(),s(`div`,ae,[a(`div`,oe,[a(`h1`,se,m(H.value.label),1),i(R)(`content:create`)?(t(),s(`button`,{key:0,type:`button`,class:`inline-flex items-center gap-[7px] rounded-[11px] bg-indigo-600 px-4 py-2.5 text-[13.5px] font-semibold text-white shadow-[0_3px_10px_rgba(91,87,232,0.3)] transition-all hover:bg-indigo-700 hover:shadow-[0_6px_18px_rgba(91,87,232,0.4)]`,onClick:$},[o[2]||=a(`svg`,{width:`17`,height:`17`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`},[a(`path`,{d:`M12 5v14`}),a(`path`,{d:`M5 12h14`})],-1),ee(` New `+m(H.value.label),1)])):p(``,!0)]),a(`div`,ce,[o[3]||=a(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.8`,"stroke-linecap":`round`,"stroke-linejoin":`round`,class:`shrink-0 text-faint`},[a(`path`,{d:`M21 21l-4.3-4.3`}),a(`path`,{d:`M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z`})],-1),r(a(`input`,{"onUpdate:modelValue":o[0]||=e=>Y.value=e,type:`text`,placeholder:`Search ${H.value.label.toLowerCase()}…`,class:`w-full bg-transparent text-ink outline-none placeholder:text-faint`,onInput:o[1]||=(...e)=>i(Z)&&i(Z)(...e)},null,40,C),[[b,Y.value]])]),J.value?(t(),s(`div`,w,[(t(),s(u,null,n(8,e=>a(`div`,{key:e,class:`h-12 animate-pulse rounded-[10px] bg-gray-100`})),64))])):G.value.length===0?(t(),s(`div`,T,[a(`p`,E,m(Y.value.trim()===``?`No ${H.value.label} items yet.`:`No results for “${Y.value.trim()}”.`),1),i(R)(`content:create`)&&Y.value.trim()===``?(t(),s(`button`,{key:0,type:`button`,class:`mt-3 text-sm font-medium text-indigo-600 hover:text-indigo-800`,onClick:$},` Create the first one → `)):p(``,!0)])):(t(),s(`div`,D,[a(`table`,O,[o[4]||=a(`thead`,{class:`text-[11.5px] font-bold uppercase tracking-[.06em] text-faint`},[a(`tr`,{class:`border-b border-divider`},[a(`th`,{class:`px-[22px] py-3.5 text-left`},`Title`),a(`th`,{class:`px-[22px] py-3.5 text-left`},`Slug`),a(`th`,{class:`px-[22px] py-3.5 text-left`},`Status`),a(`th`,{class:`px-[22px] py-3.5 text-left`},`Updated`)])],-1),a(`tbody`,k,[(t(!0),s(u,null,n(G.value,e=>(t(),s(`tr`,{key:String(e.id),class:`cursor-pointer transition-colors hover:bg-[#FAFAFE]`,onClick:t=>de(e)},[a(`td`,j,m(e[W.value]??`—`),1),a(`td`,M,m(e.slug??`—`),1),a(`td`,N,[l(re,{published:e.published===!0},null,8,[`published`])]),a(`td`,P,m(le(e.updated_at)),1)],8,A))),128))])])])),!J.value&&K.value>i(50)?(t(),s(`div`,F,[l(S,{total:K.value,page:q.value,"per-page":i(50),"onUpdate:page":ue},null,8,[`total`,`page`,`per-page`])])):p(``,!0)]))}});export{I as default};
@@ -1 +0,0 @@
1
- import{B as e,E as t,O as n,P as r,c as i,d as a,g as o,i as s,s as c,t as l,u,ut as d,w as f}from"./schema-B-RKX_ep.js";import{d as p,l as m,s as h,t as g,u as _}from"./index-BaJYEgrK.js";import{t as v}from"./useNotification-Cmvg0Rzg.js";var y={class:`max-w-lg`},b={class:`mb-6`},x={class:`text-[26px] font-bold tracking-tight text-ink`},S={key:0,class:`space-y-2`},C=[`disabled`],w=[`value`],T=[`disabled`],E={key:0,class:`text-sm text-red-600`,role:`alert`},D=[`disabled`],O=o({__name:`ContentSettingsView`,setup(o){let O=h(),k=g(),A=v(),j=l(),M=c(()=>O.params.type),N=c(()=>j.contentTypes[M.value]),P=e([]),F=e(``),I=e(!0),L=e(!1),R=e(``);f(async()=>{F.value=N.value?.default_base_path??``;let e=await k.get(`/routes`);I.value=!1,e.ok?(P.value=e.data,F.value&&!P.value.includes(F.value)&&(P.value=[F.value,...P.value])):P.value=[]});async function z(){if(!F.value.trim())return;L.value=!0,R.value=``;let e=await k.patch(`/content/${M.value}/settings`,{base_path:F.value.trim()});if(L.value=!1,!e.ok){R.value=e.error.message;return}A.success(`Settings saved.`)}return(e,o)=>(t(),a(`div`,y,[i(`div`,b,[i(`h1`,x,d(N.value?.label??M.value)+` — Settings `,1),o[2]||=i(`p`,{class:`mt-1 text-sm text-gray-500`},` Change the base path for this content type. This does not modify schema files. `,-1)]),I.value?(t(),a(`div`,S,[...o[3]||=[i(`div`,{class:`h-8 w-48 animate-pulse rounded bg-gray-100`},null,-1),i(`div`,{class:`h-10 animate-pulse rounded bg-gray-100`},null,-1)]])):(t(),a(`form`,{key:1,class:`space-y-4`,onSubmit:p(z,[`prevent`])},[i(`div`,null,[o[4]||=i(`label`,{for:`base-path`,class:`block text-[13px] font-semibold text-[#3D3D52]`},` Base path `,-1),P.value.length>0?r((t(),a(`select`,{key:0,id:`base-path`,"onUpdate:modelValue":o[0]||=e=>F.value=e,disabled:L.value,class:`mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-400 focus:outline-none focus:ring-2 focus:ring-indigo-200 disabled:cursor-not-allowed disabled:opacity-60`},[(t(!0),a(s,null,n(P.value,e=>(t(),a(`option`,{key:e,value:e},d(e),9,w))),128))],8,C)),[[m,F.value]]):r((t(),a(`input`,{key:1,id:`base-path`,"onUpdate:modelValue":o[1]||=e=>F.value=e,type:`text`,disabled:L.value,placeholder:`/my-route`,class:`mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 font-mono text-sm shadow-sm focus:border-indigo-400 focus:outline-none focus:ring-2 focus:ring-indigo-200 disabled:cursor-not-allowed disabled:opacity-60`},null,8,T)),[[_,F.value]])]),R.value?(t(),a(`p`,E,d(R.value),1)):u(``,!0),i(`button`,{type:`submit`,disabled:L.value||!F.value.trim(),class:`rounded-[11px] bg-indigo-600 px-4 py-2.5 text-[13.5px] font-semibold text-white shadow-[0_3px_10px_rgba(91,87,232,0.3)] transition-all hover:bg-indigo-700 hover:shadow-[0_6px_18px_rgba(91,87,232,0.4)] disabled:cursor-not-allowed disabled:opacity-50`},d(L.value?`Saving…`:`Save`),9,D)],32))]))}});export{O as default};
@@ -1 +0,0 @@
1
- import{B as e,E as t,P as n,T as r,W as i,c as a,d as o,g as s,p as c,s as l,u,ut as d}from"./schema-B-RKX_ep.js";import{c as f,d as p,o as m,r as h,s as g,u as _}from"./index-BaJYEgrK.js";var v={class:`flex min-h-screen bg-surface`},y={class:`hidden lg:flex lg:w-80 lg:shrink-0 lg:flex-col lg:items-start lg:justify-between bg-gradient-to-br from-[#1C1C30] to-[#121220] px-10 py-12 text-white`},b={class:`mt-8 text-[28px] font-bold leading-tight tracking-tight`},x={class:`flex flex-1 flex-col items-center justify-center px-6 py-12`},S={class:`mb-8 flex flex-col items-center lg:hidden`},C={class:`mt-4 text-lg font-bold text-ink`},w={class:`w-full max-w-sm rounded-[20px] border border-card-border bg-white px-8 py-10 shadow-[0_10px_40px_rgba(24,24,48,0.1)]`},T=[`disabled`],E=[`disabled`],D={key:0,class:`rounded-[10px] bg-red-50 px-3 py-2 text-sm text-red-600`,role:`alert`},O=[`disabled`],k=s({__name:`LoginView`,setup(s){let k=f(),A=g(),j=m(),M=h(),N=e(``),P=e(``),F=e(!1),I=e(``),L=e(0),R=null,z=l(()=>F.value||L.value>0);function B(){I.value=`Too many attempts. Try again in ${Math.ceil(L.value/60)} minutes.`}function V(e){L.value=e,B(),R&&clearInterval(R),R=setInterval(()=>{--L.value,L.value<=0?(clearInterval(R),R=null,L.value=0,I.value=``):B()},1e3)}r(()=>{R&&clearInterval(R)});async function H(){if(z.value)return;F.value=!0,I.value=``;let e;try{e=await fetch(`/admin/api/auth/login`,{method:`POST`,credentials:`include`,headers:{"Content-Type":`application/json`},body:JSON.stringify({email:N.value,password:P.value})})}catch{I.value=`Something went wrong. Please try again.`,F.value=!1;return}let t=await e.json();if(!t.ok){let n=t.error?.code??``;if(n===`INVALID_CREDENTIALS`)I.value=`Invalid email or password.`;else if(n===`RATE_LIMITED`){let t=parseInt(e.headers.get(`Retry-After`)??`60`,10);V(isNaN(t)?60:t)}else I.value=`Something went wrong. Please try again.`;F.value=!1;return}let n=t.data;if(j.setUser({id:n.id,email:n.email,role:n.role,mustChangePassword:n.must_change_password}),n.must_change_password)k.push(`/admin/change-password`);else{let e=A.query.redirect;k.push(typeof e==`string`?e:`/admin/media`)}}return(e,r)=>(t(),o(`div`,v,[a(`div`,y,[a(`div`,null,[r[2]||=c(`<div class="flex h-[42px] w-[42px] items-center justify-center rounded-[13px] bg-gradient-to-br from-[#6D5EF0] to-indigo-600 shadow-[0_6px_18px_rgba(91,87,232,0.5)]"><svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.1" stroke-linecap="round" aria-hidden="true"><path d="M4 7h16"></path><path d="M4 12h10"></path><path d="M4 17h13"></path></svg></div>`,1),a(`h1`,b,d(i(M).cmsName),1),r[3]||=a(`p`,{class:`mt-3.5 max-w-[300px] text-[15px] leading-relaxed text-white/60`},` Schema-driven headless CMS — manage your content with confidence. `,-1)]),r[4]||=a(`p`,{class:`text-xs text-white/40`},`Self-hosted & open source`,-1)]),a(`div`,x,[a(`div`,S,[r[5]||=a(`div`,{class:`flex h-10 w-10 items-center justify-center rounded-[11px] bg-gradient-to-br from-[#6D5EF0] to-indigo-600 shadow-[0_4px_12px_rgba(91,87,232,0.36)]`},[a(`svg`,{xmlns:`http://www.w3.org/2000/svg`,class:`h-5 w-5 text-white`,fill:`none`,viewBox:`0 0 24 24`,stroke:`currentColor`,"stroke-width":`2`,"aria-hidden":`true`},[a(`path`,{"stroke-linecap":`round`,"stroke-linejoin":`round`,d:`M4 6h16M4 10h16M4 14h10M4 18h6`})])],-1),a(`h1`,C,d(i(M).cmsName),1)]),a(`div`,w,[r[8]||=a(`h2`,{class:`mb-1 text-[21px] font-bold tracking-tight text-ink`},`Sign in`,-1),r[9]||=a(`p`,{class:`mb-6 text-sm text-muted`},`Enter your credentials to continue.`,-1),a(`form`,{class:`space-y-[18px]`,novalidate:``,onSubmit:p(H,[`prevent`])},[a(`div`,null,[r[6]||=a(`label`,{for:`email`,class:`block text-[13px] font-semibold text-[#3D3D52]`},`Email`,-1),n(a(`input`,{id:`email`,"onUpdate:modelValue":r[0]||=e=>N.value=e,type:`email`,required:``,autocomplete:`email`,disabled:F.value,class:`mt-[7px] block w-full rounded-[11px] border border-[#E4E3EE] bg-[#FBFBFD] px-3.5 py-3 text-sm text-ink placeholder-faint transition-colors focus:border-indigo-400 focus:bg-white focus:outline-none focus:ring-[3px] focus:ring-indigo-50 disabled:cursor-not-allowed disabled:opacity-60`},null,8,T),[[_,N.value]])]),a(`div`,null,[r[7]||=a(`label`,{for:`password`,class:`block text-[13px] font-semibold text-[#3D3D52]`},`Password`,-1),n(a(`input`,{id:`password`,"onUpdate:modelValue":r[1]||=e=>P.value=e,type:`password`,required:``,autocomplete:`current-password`,disabled:F.value,class:`mt-[7px] block w-full rounded-[11px] border border-[#E4E3EE] bg-[#FBFBFD] px-3.5 py-3 text-sm text-ink placeholder-faint transition-colors focus:border-indigo-400 focus:bg-white focus:outline-none focus:ring-[3px] focus:ring-indigo-50 disabled:cursor-not-allowed disabled:opacity-60`},null,8,E),[[_,P.value]])]),I.value?(t(),o(`p`,D,d(I.value),1)):u(``,!0),a(`button`,{type:`submit`,disabled:z.value,class:`w-full rounded-[11px] bg-indigo-600 px-4 py-[13px] text-sm font-semibold text-white shadow-[0_4px_14px_rgba(91,87,232,0.34)] transition-colors hover:bg-indigo-700 hover:shadow-[0_8px_22px_rgba(91,87,232,0.44)] focus:outline-none focus:ring-2 focus:ring-indigo-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50`},d(F.value?`Signing in…`:`Sign in`),9,O)],32)])])]))}});export{k as default};
@@ -1 +0,0 @@
1
- import{B as e,E as t,P as n,W as r,c as i,d as a,g as o,l as s,m as c,s as l,u,ut as d,w as f}from"./schema-B-RKX_ep.js";import{c as p,n as m,s as h,t as ee,u as te}from"./index-BaJYEgrK.js";import{t as ne}from"./useNotification-Cmvg0Rzg.js";import{t as re}from"./ConfirmDialog-B7nxdDge.js";import{t as ie}from"./media-DvQfZD4o.js";var ae={key:0,class:`flex items-center justify-center py-20`},oe={key:1,class:`py-12 text-center text-sm text-gray-500`},se={key:2,class:`mx-auto max-w-2xl space-y-6`},g={class:`overflow-hidden rounded-2xl border border-card-border shadow-[0_1px_2px_rgba(24,24,48,0.04),0_8px_22px_rgba(24,24,48,0.04)] bg-white`},_=[`src`,`alt`],v=[`src`],y={key:2,class:`flex h-48 flex-col items-center justify-center gap-3`},b=[`href`],x={class:`rounded-2xl border border-card-border shadow-[0_1px_2px_rgba(24,24,48,0.04),0_8px_22px_rgba(24,24,48,0.04)] bg-white p-5`},S={class:`grid grid-cols-2 gap-x-6 gap-y-3 text-sm`},C={class:`mt-0.5 font-medium text-gray-800`},w={class:`mt-0.5 font-medium text-gray-800`},T={key:0},E={class:`mt-0.5 font-medium text-gray-800`},D={key:1},O={class:`mt-0.5 font-medium text-gray-800`},k={class:`mt-0.5 font-medium text-gray-800`},A={class:`mt-0.5 font-medium text-gray-800`},j={class:`rounded-2xl border border-card-border shadow-[0_1px_2px_rgba(24,24,48,0.04),0_8px_22px_rgba(24,24,48,0.04)] bg-white p-5`},M=[`disabled`],N={class:`mt-3 flex justify-end`},P=[`disabled`],F={key:0,class:`rounded-lg border border-red-200 bg-white p-5`},ce=[`title`],I=[`disabled`],L={key:0,class:`mt-2 text-xs text-gray-400`},R=o({__name:`MediaDetailView`,setup(o){let R=h(),z=p(),B=ee(),{can:V}=m(),H=ne(),U=ie(),W=l(()=>R.params.id),G=e(null),K=e(!0),q=e(``),J=e(!1),Y=e(!1),X=e(!1),le=l(()=>G.value?.mime_type===`application/pdf`);function ue(e){return e>=1e6?`${(e/1e6).toFixed(1)} MB`:e>=1e3?`${Math.round(e/1e3)} KB`:`${e} B`}function de(e){return e?new Date(String(e)).toLocaleString(void 0,{year:`numeric`,month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`}):`—`}f(async()=>{let e=U.items.get(W.value);if(e){G.value=e,q.value=e.alt??``,K.value=!1;return}let t=await B.get(`/media/${W.value}`);K.value=!1,t.ok&&(G.value=t.data,q.value=t.data.alt??``,U.setItem(t.data))});async function Z(){if(!G.value)return;J.value=!0;let e=await B.patch(`/media/${G.value.id}`,{alt:q.value.trim()});J.value=!1,e.ok?(G.value=e.data,U.setItem(e.data),H.success(`Alt text saved.`)):H.error(e.error.message)}async function fe(){if(!G.value)return;X.value=!1,Y.value=!0;let e=await B.del(`/media/${G.value.id}`);if(Y.value=!1,!e.ok){H.error(e.error.message);return}U.removeItem(G.value.id),z.push({name:`media-library`})}let Q=l(()=>G.value!==null&&G.value.reference_count===0),$=l(()=>Q.value?void 0:`This file is referenced by ${G.value?.reference_count??0} item${(G.value?.reference_count??0)===1?``:`s`} and cannot be deleted.`);return(e,o)=>K.value?(t(),a(`div`,ae,[...o[3]||=[i(`span`,{class:`inline-block h-6 w-6 animate-spin rounded-full border-2 border-indigo-600 border-t-transparent`,"aria-hidden":`true`},null,-1)]])):G.value?(t(),a(`div`,se,[i(`button`,{type:`button`,class:`text-sm text-indigo-600 hover:text-indigo-800`,onClick:o[0]||=e=>r(z).back()},` ← Back to library `),i(`div`,g,[G.value.type===`image`?(t(),a(`img`,{key:0,src:G.value.url,alt:G.value.alt??``,class:`max-h-96 w-full object-contain`},null,8,_)):G.value.type===`video`?(t(),a(`video`,{key:1,src:G.value.url,controls:``,preload:`metadata`,class:`max-h-96 w-full bg-black object-contain`},` Your browser cannot play this video. `,8,v)):(t(),a(`div`,y,[o[5]||=i(`div`,{class:`text-6xl text-gray-300`,"aria-hidden":`true`},`📄`,-1),i(`a`,{href:G.value.url,target:`_blank`,rel:`noopener noreferrer`,class:`inline-flex items-center gap-1.5 rounded-md border border-indigo-200 bg-indigo-50 px-3 py-1.5 text-sm font-medium text-indigo-700 hover:border-indigo-300 hover:bg-indigo-100`},[c(d(le.value?`Open PDF in new tab`:`Open file in new tab`)+` `,1),o[4]||=i(`span`,{"aria-hidden":`true`},`↗`,-1)],8,b)]))]),i(`div`,x,[o[12]||=i(`h2`,{class:`mb-4 text-sm font-semibold uppercase tracking-wide text-gray-500`},`Metadata`,-1),i(`dl`,S,[i(`div`,null,[o[6]||=i(`dt`,{class:`text-gray-500`},`Type`,-1),i(`dd`,C,d(G.value.mime_type),1)]),i(`div`,null,[o[7]||=i(`dt`,{class:`text-gray-500`},`Size`,-1),i(`dd`,w,d(ue(G.value.file_size)),1)]),G.value.width&&G.value.height?(t(),a(`div`,T,[o[8]||=i(`dt`,{class:`text-gray-500`},`Dimensions`,-1),i(`dd`,E,d(G.value.width)+` × `+d(G.value.height)+`px`,1)])):u(``,!0),G.value.duration?(t(),a(`div`,D,[o[9]||=i(`dt`,{class:`text-gray-500`},`Duration`,-1),i(`dd`,O,d(G.value.duration)+`s`,1)])):u(``,!0),i(`div`,null,[o[10]||=i(`dt`,{class:`text-gray-500`},`Uploaded`,-1),i(`dd`,k,d(de(G.value.created_at)),1)]),i(`div`,null,[o[11]||=i(`dt`,{class:`text-gray-500`},`References`,-1),i(`dd`,A,d(G.value.reference_count)+` content item`+d(G.value.reference_count===1?``:`s`),1)])])]),i(`div`,j,[o[13]||=i(`h2`,{class:`mb-3 text-sm font-semibold uppercase tracking-wide text-gray-500`},`Alt text`,-1),n(i(`textarea`,{"onUpdate:modelValue":o[1]||=e=>q.value=e,rows:`3`,disabled:J.value,placeholder:`Describe this file for screen readers and SEO`,class:`block w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-400 focus:outline-none focus:ring-2 focus:ring-indigo-200 disabled:cursor-not-allowed disabled:opacity-60`},null,8,M),[[te,q.value]]),i(`div`,N,[i(`button`,{type:`button`,disabled:J.value,class:`rounded-[11px] bg-indigo-600 px-4 py-2.5 text-[13.5px] font-semibold text-white shadow-[0_3px_10px_rgba(91,87,232,0.3)] transition-all hover:bg-indigo-700 hover:shadow-[0_6px_18px_rgba(91,87,232,0.4)] disabled:cursor-not-allowed disabled:opacity-50`,onClick:Z},d(J.value?`Saving…`:`Save alt text`),9,P)])]),r(V)(`media:delete`)?(t(),a(`div`,F,[o[14]||=i(`h2`,{class:`mb-1 text-sm font-semibold uppercase tracking-wide text-red-500`},`Danger zone`,-1),o[15]||=i(`p`,{class:`mb-3 text-sm text-gray-500`},` Permanently deletes this file from storage. This cannot be undone. `,-1),i(`span`,{title:$.value},[i(`button`,{type:`button`,disabled:!Q.value||Y.value,class:`rounded-md bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700 disabled:cursor-not-allowed disabled:opacity-50`,onClick:o[2]||=e=>X.value=!0},d(Y.value?`Deleting…`:`Delete file`),9,I)],8,ce),Q.value?u(``,!0):(t(),a(`p`,L,d($.value),1))])):u(``,!0),X.value?(t(),s(re,{key:1,message:`Permanently delete this file? This action cannot be undone.`,"on-confirm":fe,"on-cancel":()=>X.value=!1},null,8,[`on-cancel`])):u(``,!0)])):(t(),a(`div`,oe,` Media item not found. `))}});export{R as default};
@@ -1 +0,0 @@
1
- import{E as e,O as t,c as n,ct as r,d as i,g as a,i as o,s,u as c,ut as l}from"./schema-B-RKX_ep.js";var u={key:0,class:`flex items-center gap-1`,"aria-label":`Pagination`},d=[`disabled`],f={key:0,class:`px-1.5 py-1.5 text-sm text-gray-400`,"aria-hidden":`true`},p=[`aria-label`,`aria-current`,`onClick`],m=[`disabled`],h=a({__name:`Pagination`,props:{total:{},page:{},perPage:{}},emits:[`update:page`],setup(a,{emit:h}){let g=a,_=h,v=s(()=>Math.max(1,Math.ceil(g.total/g.perPage))),y=s(()=>{let e=v.value,t=g.page;if(e<=7)return Array.from({length:e},(e,t)=>t+1);let n=[1];t>3&&n.push(null);let r=Math.max(2,t-1),i=Math.min(e-1,t+1);for(let e=r;e<=i;e++)n.push(e);return t<e-2&&n.push(null),n.push(e),n});function b(e){e<1||e>v.value||e===g.page||_(`update:page`,e)}return(s,h)=>v.value>1?(e(),i(`nav`,u,[n(`button`,{type:`button`,class:`rounded-md px-2.5 py-1.5 text-sm font-medium text-gray-600 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-40`,disabled:a.page===1,"aria-label":`Previous page`,onClick:h[0]||=e=>b(a.page-1)},` ‹ `,8,d),(e(!0),i(o,null,t(y.value,(t,n)=>(e(),i(o,{key:n},[t===null?(e(),i(`span`,f,` … `)):(e(),i(`button`,{key:1,type:`button`,"aria-label":`Page ${t}`,"aria-current":t===a.page?`page`:void 0,class:r([`min-w-8 rounded-md px-2.5 py-1.5 text-sm font-medium`,t===a.page?`bg-indigo-600 text-white`:`text-gray-600 hover:bg-gray-100`]),onClick:e=>b(t)},l(t),11,p))],64))),128)),n(`button`,{type:`button`,class:`rounded-md px-2.5 py-1.5 text-sm font-medium text-gray-600 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-40`,disabled:a.page===v.value,"aria-label":`Next page`,onClick:h[1]||=e=>b(a.page+1)},` › `,8,m)])):c(``,!0)}});export{h as t};
@@ -1 +0,0 @@
1
- import{A as e,B as t,E as n,O as r,W as i,c as a,d as o,g as s,i as c,j as l,l as u,s as d,t as ee,u as f,ut as p,w as m,x as h}from"./schema-B-RKX_ep.js";import{c as te,n as g,s as _,t as v}from"./index-BaJYEgrK.js";import{a as y,i as b,n as ne,r as re,t as x}from"./field-defaults-Coq6Ej9B.js";import{t as ie}from"./useNotification-Cmvg0Rzg.js";import{t as ae}from"./ConfirmDialog-B7nxdDge.js";import{t as oe}from"./taxonomy-DC-6wyg3.js";function se(e,t){let n={};for(let r of e)r.field_type!==`programmatic`&&(n[r.name]=t?.[r.name]??x(r));return n}var ce={key:0,class:`flex items-center justify-center py-20`},le={key:1,class:`py-12 text-center text-sm text-gray-500`},S={key:2},C={class:`mb-6 flex items-start justify-between gap-4`},w={class:`text-xs font-medium uppercase tracking-wide text-gray-400`},T={class:`text-[26px] font-bold tracking-tight text-ink`},E={class:`flex shrink-0 items-center gap-2`},D=[`disabled`],O=[`disabled`],k={class:`space-y-5`},A={key:0,class:`mt-4 text-sm text-red-600`,role:`alert`},j=s({__name:`TaxonomyFormView`,setup(s){let x=_(),j=te(),M=v(),{can:N}=g(),{errors:P,validate:F,mergeServerErrors:I,clearErrors:ue,setError:L}=b(),R=ie(),z=ee(),B=oe(),V=d(()=>x.params.type),H=d(()=>x.params.id),U=d(()=>!!H.value),W=d(()=>z.taxonomyTypes[V.value]),G=d(()=>W.value?.fields??[]),K=t(null),q=t({}),J=t(!0),Y=t(!1),X=t(``),Z=t(!1);function Q(e){q.value=se(G.value,e)}function de(e,t){q.value[e]=t}async function $(e){let t=await M.get(`/taxonomy/${V.value}/${e}`);t.ok?(K.value=t.data,Q(t.data)):X.value=t.error.message}m(async()=>{if(!W.value){J.value=!1;return}U.value&&H.value?await $(H.value):Q(),J.value=!1}),l(H,async(e,t)=>{e!==t&&(J.value=!0,ue(),e?await $(e):(K.value=null,Q()),J.value=!1)});async function fe(){if(!F(G.value,q.value))return;Y.value=!0,X.value=``;let e=U.value?await M.patch(`/taxonomy/${V.value}/${H.value}`,q.value):await M.post(`/taxonomy/${V.value}`,q.value);if(Y.value=!1,!e.ok){let t=e.error;if((t.code===`PUBLISH_VALIDATION_ERROR`||t.code===`VALIDATION_ERROR`)&&t.details){let{fieldErrors:e,other:n}=y(t.details,G.value.map(e=>e.name));I(e),n.length>0&&(X.value=[t.message,...n].join(` `))}else t.code===`SLUG_CONFLICT`?L(`slug`,`This slug is already taken.`):X.value=t.message;return}K.value=e.data,B.invalidate(V.value),R.success(`Saved.`),U.value||j.replace({name:`taxonomy-edit`,params:{type:V.value,id:String(e.data.id)}})}async function pe(){Z.value=!1,Y.value=!0;let e=await M.del(`/taxonomy/${V.value}/${H.value}`);if(Y.value=!1,!e.ok){X.value=e.error.message;return}B.invalidate(V.value),j.push({name:`taxonomy-list`,params:{type:V.value}})}let me=d(()=>{if(!U.value)return`New ${W.value?.label??``}`;let e=G.value.find(e=>e.field_type===`text/plain`);return e?String(K.value?.[e.name]??``):W.value?.label??``});return(t,s)=>J.value?(n(),o(`div`,ce,[...s[1]||=[a(`span`,{class:`inline-block h-6 w-6 animate-spin rounded-full border-2 border-indigo-600 border-t-transparent`,"aria-hidden":`true`},null,-1)]])):W.value?(n(),o(`div`,S,[a(`div`,C,[a(`div`,null,[a(`p`,w,p(W.value.label),1),a(`h1`,T,p(me.value),1)]),a(`div`,E,[i(N)(`taxonomy:delete`)&&U.value?(n(),o(`button`,{key:0,type:`button`,disabled:Y.value,class:`rounded-md px-3 py-2 text-sm font-medium text-red-600 ring-1 ring-inset ring-red-300 hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-50`,onClick:s[0]||=e=>Z.value=!0},` Delete `,8,D)):f(``,!0),(U.value?i(N)(`taxonomy:edit`):i(N)(`taxonomy:create`))?(n(),o(`button`,{key:1,type:`button`,disabled:Y.value,class:`rounded-[11px] bg-indigo-600 px-4 py-2.5 text-[13.5px] font-semibold text-white shadow-[0_3px_10px_rgba(91,87,232,0.3)] transition-all hover:bg-indigo-700 hover:shadow-[0_6px_18px_rgba(91,87,232,0.4)] disabled:cursor-not-allowed disabled:opacity-50`,onClick:fe},p(Y.value?`Saving…`:`Save`),9,O)):f(``,!0)])]),a(`div`,k,[(n(!0),o(c,null,r(G.value,t=>(n(),u(e(i(ne)(t)),h({key:t.name,field:t,"model-value":q.value[t.name],error:i(P)[t.name],disabled:Y.value},{ref_for:!0},i(re)(t),{"onUpdate:modelValue":e=>de(t.name,e)}),null,16,[`field`,`model-value`,`error`,`disabled`,`onUpdate:modelValue`]))),128))]),X.value?(n(),o(`p`,A,p(X.value),1)):f(``,!0),Z.value?(n(),u(ae,{key:1,message:`Are you sure you want to delete this term? This action cannot be undone.`,"on-confirm":pe,"on-cancel":()=>Z.value=!1},null,8,[`on-cancel`])):f(``,!0)])):(n(),o(`div`,le,` Taxonomy type not found. `))}});export{j as default};
@@ -1 +0,0 @@
1
- import{B as e,E as t,O as n,P as r,W as i,c as a,d as o,g as s,h as c,i as l,j as u,m as d,s as f,t as p,u as m,ut as h,w as g}from"./schema-B-RKX_ep.js";import{a as _,c as v,n as y,s as b,t as x,u as S}from"./index-BaJYEgrK.js";import{t as C}from"./Pagination-BIf7mQy7.js";import{t as w}from"./taxonomy-DC-6wyg3.js";var T={class:`mb-5.5 flex flex-wrap items-center justify-between gap-4`},ee={class:`text-[26px] font-bold tracking-tight text-ink`},te={class:`mb-4 flex h-9.5 items-center gap-2 rounded-[10px] border border-card-border bg-[#FBFBFD] px-2.75 text-[13px] transition-colors focus-within:border-indigo-400`},E={key:0,class:`space-y-2`},D={key:1,class:`rounded-2xl border border-dashed border-gray-300 p-12 text-center`},O={class:`text-sm text-muted`},k={key:2,class:`overflow-hidden rounded-2xl border border-card-border bg-white shadow-[0_1px_2px_rgba(24,24,48,0.04),0_10px_28px_rgba(24,24,48,0.04)]`},A={class:`w-full text-sm`},j={class:`divide-y divide-[#F4F3F9]`},M=[`onClick`],N={class:`px-5.5 py-4 text-[14.5px] font-semibold text-ink`},P={class:`px-5.5 py-4 text-[13px] text-faint`},F={key:3,class:`mt-4 flex justify-center`},I=s({__name:`TaxonomyListView`,setup(s){let I=b(),L=v(),R=x(),{can:z}=y(),B=p(),V=w(),H=f(()=>I.params.type),U=f(()=>B.taxonomyTypes[H.value]),W=f(()=>U.value?.fields.find(e=>e.field_type===`text/plain`)?.name??`id`),G=e([]),K=e(0),q=e(1),J=e(!1),Y=e(``);function X(e){return typeof e!=`string`||!e?`—`:new Date(e).toLocaleDateString(void 0,{year:`numeric`,month:`short`,day:`numeric`})}async function Z(e){J.value=!0;let t=Y.value.trim();if(t===``){let t=V.getPage(H.value,e,50);if(t){G.value=t,K.value=V.total,J.value=!1;return}}let n=t===``?``:`&search=${encodeURIComponent(t)}`,r=await R.get(`/taxonomy/${H.value}?page=${e}&per_page=50${n}`);J.value=!1,r.ok&&(G.value=r.data,K.value=r.meta?.total??r.data.length,t===``&&(V.total=K.value,V.setPage(H.value,e,50,r.data)))}let Q=_(()=>{q.value=1,Z(1)},300);g(()=>{Z(q.value)}),u(H,()=>{q.value=1,G.value=[],Z(1)});function ne(e){q.value=e,Z(e)}function re(e){L.push({name:`taxonomy-edit`,params:{type:H.value,id:String(e.id)}})}function $(){L.push({name:`taxonomy-new`,params:{type:H.value}})}return(e,s)=>(t(),o(`div`,null,[a(`div`,T,[a(`h1`,ee,h(U.value?.label??H.value),1),i(z)(`taxonomy:create`)?(t(),o(`button`,{key:0,type:`button`,class:`inline-flex items-center gap-1.75 rounded-[11px] bg-indigo-600 px-4 py-2.5 text-[13.5px] font-semibold text-white shadow-[0_3px_10px_rgba(91,87,232,0.3)] transition-all hover:bg-indigo-700 hover:shadow-[0_6px_18px_rgba(91,87,232,0.4)]`,onClick:$},[s[2]||=a(`svg`,{width:`17`,height:`17`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`},[a(`path`,{d:`M12 5v14`}),a(`path`,{d:`M5 12h14`})],-1),d(` New `+h(U.value?.label??`Term`),1)])):m(``,!0)]),a(`div`,te,[s[3]||=a(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.8`,"stroke-linecap":`round`,"stroke-linejoin":`round`,class:`shrink-0 text-faint`},[a(`path`,{d:`M21 21l-4.3-4.3`}),a(`path`,{d:`M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z`})],-1),r(a(`input`,{"onUpdate:modelValue":s[0]||=e=>Y.value=e,type:`text`,placeholder:`Search terms…`,class:`w-full bg-transparent text-ink outline-none placeholder:text-faint`,onInput:s[1]||=(...e)=>i(Q)&&i(Q)(...e)},null,544),[[S,Y.value]])]),J.value?(t(),o(`div`,E,[(t(),o(l,null,n(6,e=>a(`div`,{key:e,class:`h-12 animate-pulse rounded-[10px] bg-gray-100`})),64))])):G.value.length===0?(t(),o(`div`,D,[a(`p`,O,h(Y.value.trim()===``?`No terms yet.`:`No results for “${Y.value.trim()}”.`),1),i(z)(`taxonomy:create`)&&Y.value.trim()===``?(t(),o(`button`,{key:0,type:`button`,class:`mt-3 text-sm font-medium text-indigo-600 hover:text-indigo-800`,onClick:$},` Create the first one → `)):m(``,!0)])):(t(),o(`div`,k,[a(`table`,A,[s[4]||=a(`thead`,{class:`text-[11.5px] font-bold uppercase tracking-[.06em] text-faint`},[a(`tr`,{class:`border-b border-divider`},[a(`th`,{class:`px-5.5 py-3.5 text-left`},`Name`),a(`th`,{class:`px-5.5 py-3.5 text-left`},`Updated`)])],-1),a(`tbody`,j,[(t(!0),o(l,null,n(G.value,e=>(t(),o(`tr`,{key:String(e.id),class:`cursor-pointer transition-colors hover:bg-[#FAFAFE]`,onClick:t=>re(e)},[a(`td`,N,h(e[W.value]??`—`),1),a(`td`,P,h(X(e.updated_at)),1)],8,M))),128))])])])),!J.value&&K.value>i(50)?(t(),o(`div`,F,[c(C,{total:K.value,page:q.value,"per-page":i(50),"onUpdate:page":ne},null,8,[`total`,`page`,`per-page`])])):m(``,!0)]))}});export{I as default};
@@ -1 +0,0 @@
1
- import{B as e,E as t,O as ee,P as n,W as r,c as i,d as a,g as o,i as s,l as c,s as l,u,ut as d,w as te}from"./schema-B-RKX_ep.js";import{c as f,d as p,l as m,n as h,o as g,s as _,t as v,u as y}from"./index-BaJYEgrK.js";import{t as ne}from"./useNotification-Cmvg0Rzg.js";import{t as re}from"./ConfirmDialog-B7nxdDge.js";import{t as ie}from"./users-DVibZ_HD.js";var ae={key:0,class:`flex items-center justify-center py-20`},oe={key:1,class:`mx-auto max-w-lg`},se={class:`mb-6 flex items-start justify-between gap-4`},ce={class:`text-[26px] font-bold tracking-tight text-ink`},le={class:`flex shrink-0 items-center gap-2`},ue=[`disabled`],de=[`disabled`],b={key:0,class:`mb-5 rounded-md border border-amber-200 bg-amber-50 p-4`,role:`alert`},x={class:`flex items-center gap-2`},S=[`value`],C={key:1,class:`mb-5 rounded-md border border-amber-200 bg-amber-50 p-4`,role:`alert`},w={class:`flex items-center gap-2`},T=[`value`],E=[`disabled`],D={key:0},O=[`disabled`],k=[`value`],A={key:0,class:`mt-1 text-xs text-gray-400`},j={key:1,class:`text-sm text-red-600`,role:`alert`},M=[`disabled`],N=o({__name:`UserFormView`,setup(o){let N=_(),P=f(),F=v(),{can:I,rolesBelow:L}=h(),R=ne(),fe=g(),z=ie(),B=l(()=>N.params.id),V=l(()=>!!B.value),H=l(()=>fe.id===B.value),U=e(``),W=e(``),G=e(!1),K=e(!1),q=e(``),J=e(null),Y=e(!1),X=e(null),Z=e(!1),Q=e(!1);te(async()=>{if(!V.value||!B.value){W.value=L()[0]?.name??``;return}G.value=!0;let e=z.users.find(e=>e.id===B.value);if(e){U.value=e.email,W.value=e.role,G.value=!1;return}let t=await F.get(`/users/${B.value}`);G.value=!1,t.ok&&(U.value=t.data.email,W.value=t.data.role,z.setUser(t.data))});async function pe(){if(q.value=``,K.value=!0,V.value){let e=await F.patch(`/users/${B.value}`,{email:U.value.trim(),role:W.value});if(K.value=!1,!e.ok){q.value=e.error.message;return}z.setUser(e.data),R.success(`User updated.`)}else{let e=await F.post(`/users`,{email:U.value.trim(),role:W.value});if(K.value=!1,!e.ok){q.value=e.error.message;return}z.setUser(e.data),J.value=e.data.temporary_password??null,R.success(`User created.`)}}async function $(e){try{await navigator.clipboard.writeText(e),Y.value=!0,setTimeout(()=>{Y.value=!1},2e3)}catch{}}async function me(){if(!B.value)return;Z.value=!0;let e=await F.post(`/users/${B.value}/reset-password`,{});Z.value=!1,e.ok?(X.value=e.data.temporary_password,Y.value=!1):R.error(e.error.message)}async function he(){if(Q.value=!1,!B.value)return;K.value=!0;let e=await F.del(`/users/${B.value}`);if(K.value=!1,!e.ok){q.value=e.error.message;return}z.removeUser(B.value),P.push({name:`user-list`})}let ge=l(()=>V.value?U.value||`Edit user`:`New user`);return(e,o)=>G.value?(t(),a(`div`,ae,[...o[5]||=[i(`span`,{class:`inline-block h-6 w-6 animate-spin rounded-full border-2 border-indigo-600 border-t-transparent`,"aria-hidden":`true`},null,-1)]])):(t(),a(`div`,oe,[i(`div`,se,[i(`h1`,ce,d(ge.value),1),i(`div`,le,[r(I)(`users:edit`)&&V.value&&!H.value?(t(),a(`button`,{key:0,type:`button`,disabled:Z.value,class:`rounded-md px-3 py-2 text-[13px] font-semibold text-[#3D3D52] ring-1 ring-inset ring-gray-300 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50`,onClick:me},d(Z.value?`Resetting…`:`Reset password`),9,ue)):u(``,!0),r(I)(`users:delete`)&&V.value&&!H.value?(t(),a(`button`,{key:1,type:`button`,disabled:K.value,class:`rounded-md px-3 py-2 text-sm font-medium text-red-600 ring-1 ring-inset ring-red-300 hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-50`,onClick:o[0]||=e=>Q.value=!0},` Delete `,8,de)):u(``,!0)])]),J.value?(t(),a(`div`,b,[o[6]||=i(`p`,{class:`mb-2 text-sm font-medium text-amber-800`},` User created. Share this temporary password — it will not be shown again. `,-1),i(`div`,x,[i(`input`,{value:J.value,type:`text`,readonly:``,class:`flex-1 rounded-md border border-amber-200 bg-white px-3 py-1.5 font-mono text-sm`},null,8,S),i(`button`,{type:`button`,class:`shrink-0 rounded-md bg-amber-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-amber-700`,onClick:o[1]||=e=>$(J.value)},d(Y.value?`Copied!`:`Copy`),1)])])):u(``,!0),X.value?(t(),a(`div`,C,[o[7]||=i(`p`,{class:`mb-2 text-sm font-medium text-amber-800`},` Password reset. Share this temporary password — it will not be shown again. `,-1),i(`div`,w,[i(`input`,{value:X.value,type:`text`,readonly:``,class:`flex-1 rounded-md border border-amber-200 bg-white px-3 py-1.5 font-mono text-sm`},null,8,T),i(`button`,{type:`button`,class:`shrink-0 rounded-md bg-amber-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-amber-700`,onClick:o[2]||=e=>$(X.value)},d(Y.value?`Copied!`:`Copy`),1)])])):u(``,!0),i(`form`,{class:`space-y-5`,novalidate:``,onSubmit:p(pe,[`prevent`])},[i(`div`,null,[o[8]||=i(`label`,{for:`user-email`,class:`block text-[13px] font-semibold text-[#3D3D52]`},`Email`,-1),n(i(`input`,{id:`user-email`,"onUpdate:modelValue":o[3]||=e=>U.value=e,type:`email`,required:``,autocomplete:`email`,disabled:K.value,class:`mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-400 focus:outline-none focus:ring-2 focus:ring-indigo-200 disabled:cursor-not-allowed disabled:opacity-60`},null,8,E),[[y,U.value]])]),H.value?u(``,!0):(t(),a(`div`,D,[o[10]||=i(`label`,{for:`user-role`,class:`block text-[13px] font-semibold text-[#3D3D52]`},`Role`,-1),n(i(`select`,{id:`user-role`,"onUpdate:modelValue":o[4]||=e=>W.value=e,disabled:K.value||r(L)().length===0,class:`mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-400 focus:outline-none focus:ring-2 focus:ring-indigo-200 disabled:cursor-not-allowed disabled:opacity-60`},[o[9]||=i(`option`,{value:``,disabled:``},`Select a role`,-1),(t(!0),a(s,null,ee(r(L)(),e=>(t(),a(`option`,{key:e.name,value:e.name},d(e.label),9,k))),128))],8,O),[[m,W.value]]),r(L)().length===0?(t(),a(`p`,A,` No assignable roles available. `)):u(``,!0)])),q.value?(t(),a(`p`,j,d(q.value),1)):u(``,!0),(V.value?r(I)(`users:edit`):r(I)(`users:create`))?(t(),a(`button`,{key:2,type:`submit`,disabled:K.value||!U.value.trim()||!H.value&&!W.value,class:`w-full rounded-md bg-indigo-600 px-4 py-2 text-sm font-semibold text-white hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50`},d(K.value?`Saving…`:V.value?`Save changes`:`Create user`),9,M)):u(``,!0)],32),Q.value?(t(),c(re,{key:2,message:`Are you sure you want to delete this user? This action cannot be undone.`,"on-confirm":he,"on-cancel":()=>Q.value=!1},null,8,[`on-cancel`])):u(``,!0)]))}});export{N as default};