@mulmoclaude/collection-plugin 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/index.cjs +4 -47
  2. package/dist/index.js +1 -44
  3. package/dist/{promptSafety-BSO2gdsg.cjs → promptSafety-B0pPJkfQ.cjs} +60 -1
  4. package/dist/promptSafety-B0pPJkfQ.cjs.map +1 -0
  5. package/dist/{promptSafety-DShN_VCG.js → promptSafety-DIQ2yDca.js} +43 -2
  6. package/dist/promptSafety-DIQ2yDca.js.map +1 -0
  7. package/dist/style.css +102 -0
  8. package/dist/vue/chat/Preview.vue.d.ts +8 -0
  9. package/dist/vue/chat/Preview.vue.d.ts.map +1 -0
  10. package/dist/vue/chat/View.vue.d.ts +16 -0
  11. package/dist/vue/chat/View.vue.d.ts.map +1 -0
  12. package/dist/vue/components/CollectionEmbedView.vue.d.ts.map +1 -1
  13. package/dist/vue/components/CollectionRecordModal.vue.d.ts.map +1 -1
  14. package/dist/vue/components/CollectionRecordPanel.vue.d.ts.map +1 -1
  15. package/dist/vue/components/CollectionView.vue.d.ts.map +1 -1
  16. package/dist/vue/index.d.ts +6 -0
  17. package/dist/vue/index.d.ts.map +1 -1
  18. package/dist/vue/lang/de.d.ts.map +1 -1
  19. package/dist/vue/lang/en.d.ts +6 -0
  20. package/dist/vue/lang/en.d.ts.map +1 -1
  21. package/dist/vue/lang/es.d.ts.map +1 -1
  22. package/dist/vue/lang/fr.d.ts.map +1 -1
  23. package/dist/vue/lang/index.d.ts +6 -0
  24. package/dist/vue/lang/index.d.ts.map +1 -1
  25. package/dist/vue/lang/ja.d.ts.map +1 -1
  26. package/dist/vue/lang/ko.d.ts.map +1 -1
  27. package/dist/vue/lang/ptBR.d.ts.map +1 -1
  28. package/dist/vue/lang/zh.d.ts.map +1 -1
  29. package/dist/vue/uiContext.d.ts +18 -0
  30. package/dist/vue/uiContext.d.ts.map +1 -1
  31. package/dist/vue.cjs +891 -711
  32. package/dist/vue.cjs.map +1 -1
  33. package/dist/vue.js +890 -713
  34. package/dist/vue.js.map +1 -1
  35. package/package.json +1 -1
  36. package/dist/index.cjs.map +0 -1
  37. package/dist/index.js.map +0 -1
  38. package/dist/promptSafety-BSO2gdsg.cjs.map +0 -1
  39. package/dist/promptSafety-DShN_VCG.js.map +0 -1
package/dist/vue.js CHANGED
@@ -1,6 +1,6 @@
1
- import { A as buildUpdatedRecord, C as dateSortValue, D as numericSortValue, E as nextSortDirection, F as rowFromItem, I as actionVisible, L as fieldVisible, M as draftToRecord, N as emptyRow, O as sortItems, P as firstMissingRequiredField, T as isSortableField, W as resolveEnumColor, _ as ymdKey, a as assignLanes, b as labelFieldFor, i as MINUTES_PER_DAY, j as coerceInlineValue, k as stringSortValue, l as dateOf, n as shortHexId, o as bucketRecords, r as errorMessage, s as buildMonthGrid, t as defangForPrompt, u as daySlice, v as itemIdOf, w as enumSortValue, x as boolSortValue, y as itemLabelOf } from "./promptSafety-DShN_VCG.js";
1
+ import { A as buildUpdatedRecord, C as dateSortValue, D as numericSortValue, E as nextSortDirection, F as rowFromItem, G as TOOL_DEFINITION, I as actionVisible, L as fieldVisible, M as draftToRecord, N as emptyRow, O as sortItems, P as firstMissingRequiredField, T as isSortableField, W as resolveEnumColor, _ as ymdKey, a as assignLanes, b as labelFieldFor, i as MINUTES_PER_DAY, j as coerceInlineValue, k as stringSortValue, l as dateOf, n as shortHexId, o as bucketRecords, q as executePresentCollection, r as errorMessage, s as buildMonthGrid, t as defangForPrompt, u as daySlice, v as itemIdOf, w as enumSortValue, x as boolSortValue, y as itemLabelOf } from "./promptSafety-DIQ2yDca.js";
2
2
  import { t as deriveAll } from "./deriveAll-BHcs1erT.js";
3
- import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, effectScope, mergeModels, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, renderSlot, resolveComponent, resolveDynamicComponent, toDisplayString, unref, useModel, vModelCheckbox, vModelDynamic, vModelSelect, vModelText, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers } from "vue";
3
+ import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, effectScope, mergeModels, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useModel, vModelCheckbox, vModelDynamic, vModelSelect, vModelText, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers } from "vue";
4
4
  import { createI18n } from "vue-i18n";
5
5
  import draggable from "vuedraggable";
6
6
  //#region src/vue/uiContext.ts
@@ -14,395 +14,6 @@ function collectionUi() {
14
14
  return current;
15
15
  }
16
16
  //#endregion
17
- //#region src/vue/useCollectionRendering.ts
18
- function useCollectionRendering(collection, locale) {
19
- const refCache = ref({});
20
- const refRecordCache = ref({});
21
- const embedCache = ref({});
22
- function resetLinkedCaches() {
23
- refCache.value = {};
24
- refRecordCache.value = {};
25
- embedCache.value = {};
26
- }
27
- function uniqueRefTargets(schema) {
28
- const targets = /* @__PURE__ */ new Set();
29
- const walk = (fields) => {
30
- for (const field of Object.values(fields)) {
31
- if (field.type === "ref" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
32
- if (field.type === "table" && field.of) walk(field.of);
33
- }
34
- };
35
- walk(schema.fields);
36
- return [...targets];
37
- }
38
- function uniqueEmbedTargets(schema) {
39
- const targets = /* @__PURE__ */ new Set();
40
- for (const field of Object.values(schema.fields)) if (field.type === "embed" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
41
- return [...targets];
42
- }
43
- function buildRefDisplayMap(detail) {
44
- const { fields, primaryKey } = detail.collection.schema;
45
- const displayField = "name" in fields ? "name" : "title" in fields ? "title" : primaryKey;
46
- const map = {};
47
- for (const item of detail.items) {
48
- const slugRaw = item[primaryKey];
49
- if (typeof slugRaw !== "string" || slugRaw.length === 0) continue;
50
- const displayRaw = item[displayField];
51
- map[slugRaw] = typeof displayRaw === "string" && displayRaw.length > 0 ? displayRaw : slugRaw;
52
- }
53
- return map;
54
- }
55
- function buildRefRecordMap(detail) {
56
- const { schema } = detail.collection;
57
- const map = {};
58
- for (const item of detail.items) {
59
- const slugRaw = item[schema.primaryKey];
60
- if (typeof slugRaw === "string" && slugRaw.length > 0) map[slugRaw] = deriveAll(schema, item, {});
61
- }
62
- return map;
63
- }
64
- async function loadLinkedCollections(schema, expectedSlug) {
65
- const refTargets = new Set(uniqueRefTargets(schema));
66
- const embedTargets = new Set(uniqueEmbedTargets(schema));
67
- const allTargets = [...new Set([...refTargets, ...embedTargets])];
68
- if (allTargets.length === 0) return;
69
- const binding = collectionUi();
70
- const results = await Promise.all(allTargets.map(async (target) => {
71
- try {
72
- return {
73
- target,
74
- result: await binding.fetchCollectionDetail(target)
75
- };
76
- } catch {
77
- return {
78
- target,
79
- result: { ok: false }
80
- };
81
- }
82
- }));
83
- if (collection.value?.slug !== expectedSlug) return;
84
- const nextRef = {};
85
- const nextRefRecords = {};
86
- const nextEmbed = {};
87
- for (const { target, result } of results) {
88
- if (!result.ok) continue;
89
- if (refTargets.has(target)) {
90
- nextRef[target] = buildRefDisplayMap(result.data);
91
- nextRefRecords[target] = buildRefRecordMap(result.data);
92
- }
93
- if (embedTargets.has(target)) nextEmbed[target] = {
94
- schema: result.data.collection.schema,
95
- items: result.data.items
96
- };
97
- }
98
- refCache.value = nextRef;
99
- refRecordCache.value = nextRefRecords;
100
- embedCache.value = nextEmbed;
101
- }
102
- function refDisplay(targetSlug, itemSlug) {
103
- const map = refCache.value[targetSlug];
104
- return map && map[itemSlug] || itemSlug;
105
- }
106
- function refOptions(targetSlug) {
107
- const map = refCache.value[targetSlug];
108
- if (!map) return [];
109
- return Object.entries(map).map(([slug, display]) => ({
110
- slug,
111
- display
112
- })).sort((left, right) => left.display.localeCompare(right.display));
113
- }
114
- function resolveEmbed(field) {
115
- if (field.type !== "embed" || !field.to || !field.id) return {
116
- schema: null,
117
- item: null
118
- };
119
- const data = embedCache.value[field.to];
120
- if (!data) return {
121
- schema: null,
122
- item: null
123
- };
124
- const item = data.items.find((entry) => String(entry[data.schema.primaryKey] ?? "") === field.id) ?? null;
125
- return {
126
- schema: data.schema,
127
- item
128
- };
129
- }
130
- function embedValue(field, value, record) {
131
- if (field.type === "money") return formatMoney(value, resolveCurrency(field, record), locale.value);
132
- return detailText(value);
133
- }
134
- const embedViews = computed(() => {
135
- const out = {};
136
- if (!collection.value) return out;
137
- for (const [key, field] of Object.entries(collection.value.schema.fields)) {
138
- if (field.type !== "embed") continue;
139
- const { schema, item } = resolveEmbed(field);
140
- const rows = [];
141
- if (schema && item) for (const [subKey, subField] of Object.entries(schema.fields)) {
142
- const value = item[subKey];
143
- if (value === void 0 || value === null || value === "") continue;
144
- rows.push({
145
- key: subKey,
146
- label: subField.label,
147
- type: subField.type,
148
- value,
149
- display: embedValue(subField, value, item)
150
- });
151
- }
152
- out[key] = {
153
- found: Boolean(item),
154
- rows,
155
- targetSlug: field.to ?? "",
156
- recordId: field.id ?? ""
157
- };
158
- }
159
- return out;
160
- });
161
- function resolveCurrency(field, record) {
162
- if (field.currencyField && record) {
163
- const code = record[field.currencyField];
164
- if (typeof code === "string" && code.trim().length > 0) return code;
165
- }
166
- return field.currency;
167
- }
168
- function currencySymbol(currency) {
169
- const code = currency && currency.length > 0 ? currency : "USD";
170
- try {
171
- return new Intl.NumberFormat(locale.value, {
172
- style: "currency",
173
- currency: code
174
- }).formatToParts(0).find((entry) => entry.type === "currency")?.value ?? code;
175
- } catch {
176
- return code;
177
- }
178
- }
179
- function formatMoney(value, currency, displayLocale) {
180
- if (value === void 0 || value === "") return "—";
181
- const amount = typeof value === "number" ? value : Number(value);
182
- if (!Number.isFinite(amount)) return String(value);
183
- const currencyCode = currency && currency.length > 0 ? currency : "USD";
184
- try {
185
- return new Intl.NumberFormat(displayLocale, {
186
- style: "currency",
187
- currency: currencyCode
188
- }).format(amount);
189
- } catch {
190
- return String(amount);
191
- }
192
- }
193
- function formatCell(value, type) {
194
- if (value === void 0 || value === null || value === "") return "—";
195
- if (type === "markdown" && typeof value === "string") return value.length > 80 ? `${value.slice(0, 80)}…` : value;
196
- if (typeof value === "string" || typeof value === "number") return String(value);
197
- return JSON.stringify(value);
198
- }
199
- function isExternalUrl(value) {
200
- return typeof value === "string" && /^https?:\/\//i.test(value);
201
- }
202
- function artifactUrl(value) {
203
- return collectionUi().fileAssetUrl(value);
204
- }
205
- function fileRoutePath(value) {
206
- return collectionUi().fileRoutePath(value);
207
- }
208
- function detailText(value) {
209
- if (value === void 0 || value === null || value === "") return "—";
210
- return String(value);
211
- }
212
- function tableRows(value) {
213
- if (!Array.isArray(value)) return [];
214
- return value.filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row));
215
- }
216
- function hasTableRows(value) {
217
- return tableRows(value).length > 0;
218
- }
219
- function formatSubCell(subField, value, record) {
220
- if (subField.type === "money") return formatMoney(value, resolveCurrency(subField, record), locale.value);
221
- if (subField.type === "ref" && subField.to && typeof value === "string" && value.length > 0) return refDisplay(subField.to, value);
222
- return formatCell(value, subField.type);
223
- }
224
- function inputTypeFor(type) {
225
- if (type === "email") return "email";
226
- if (type === "number") return "number";
227
- if (type === "money") return "number";
228
- if (type === "date") return "date";
229
- if (type === "datetime") return "datetime-local";
230
- return "text";
231
- }
232
- function evaluateDerivedAgainstItem(field, fieldKey, item) {
233
- if (!field.formula || !collection.value) return null;
234
- const result = deriveAll(collection.value.schema, item, refRecordCache.value)[fieldKey];
235
- return typeof result === "number" && Number.isFinite(result) ? result : null;
236
- }
237
- function derivedDisplay(field, computedValue, record) {
238
- if (computedValue === null || computedValue === void 0) return "—";
239
- if (field.display === "money") return formatMoney(computedValue, resolveCurrency(field, record), locale.value);
240
- return formatCell(computedValue, field.display ?? "number");
241
- }
242
- return {
243
- refCache,
244
- refRecordCache,
245
- embedCache,
246
- resetLinkedCaches,
247
- loadLinkedCollections,
248
- refDisplay,
249
- refOptions,
250
- embedViews,
251
- resolveCurrency,
252
- currencySymbol,
253
- formatMoney,
254
- formatCell,
255
- detailText,
256
- isExternalUrl,
257
- artifactUrl,
258
- fileRoutePath,
259
- tableRows,
260
- hasTableRows,
261
- formatSubCell,
262
- inputTypeFor,
263
- deriveAll,
264
- evaluateDerivedAgainstItem,
265
- derivedDisplay
266
- };
267
- }
268
- //#endregion
269
- //#region src/vue/collectionViewMode.ts
270
- var STORAGE_KEY = "collection_view_modes";
271
- var SORT_STORAGE_KEY = "collection_sorts";
272
- var BUILT_IN_MODES = [
273
- "table",
274
- "calendar",
275
- "kanban"
276
- ];
277
- /** A persisted mode is valid if it's a known built-in OR any `custom:<id>`
278
- * key (the id is validated against the live schema at render time, so an
279
- * unknown custom id simply collapses to the table there). Takes `unknown`
280
- * and type-guards `string` first: a corrupted localStorage entry could hold a
281
- * number/object, and calling `.startsWith` on that would throw. */
282
- function isValidViewMode(value) {
283
- return typeof value === "string" && (BUILT_IN_MODES.includes(value) || value.startsWith("custom:"));
284
- }
285
- function readAll() {
286
- try {
287
- const raw = localStorage.getItem(STORAGE_KEY);
288
- if (!raw) return {};
289
- const parsed = JSON.parse(raw);
290
- return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
291
- } catch {
292
- return {};
293
- }
294
- }
295
- function readCollectionViewMode(slug) {
296
- const stored = readAll()[slug];
297
- return isValidViewMode(stored) ? stored : null;
298
- }
299
- function writeCollectionViewMode(slug, view) {
300
- try {
301
- const all = readAll();
302
- all[slug] = view;
303
- localStorage.setItem(STORAGE_KEY, JSON.stringify(all));
304
- } catch {}
305
- }
306
- function isSortState(value) {
307
- if (!value || typeof value !== "object") return false;
308
- const rec = value;
309
- return typeof rec.field === "string" && (rec.direction === "asc" || rec.direction === "desc");
310
- }
311
- function readAllSorts() {
312
- try {
313
- const raw = localStorage.getItem(SORT_STORAGE_KEY);
314
- if (!raw) return {};
315
- const parsed = JSON.parse(raw);
316
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
317
- const out = {};
318
- for (const [slug, value] of Object.entries(parsed)) if (isSortState(value)) out[slug] = value;
319
- return out;
320
- } catch {
321
- return {};
322
- }
323
- }
324
- function readCollectionSort(slug) {
325
- return readAllSorts()[slug] ?? null;
326
- }
327
- /** Persist (or, when `sort` is null, clear) the slug's active column sort. */
328
- function writeCollectionSort(slug, sort) {
329
- try {
330
- const all = Object.fromEntries(Object.entries(readAllSorts()).filter(([key]) => key !== slug));
331
- if (sort) all[slug] = sort;
332
- localStorage.setItem(SORT_STORAGE_KEY, JSON.stringify(all));
333
- } catch {}
334
- }
335
- //#endregion
336
- //#region src/vue/components/CollectionRecordModal.vue
337
- var CollectionRecordModal_default = /* @__PURE__ */ defineComponent({
338
- __name: "CollectionRecordModal",
339
- emits: ["close"],
340
- setup(__props, { emit: __emit }) {
341
- const emit = __emit;
342
- const dialogEl = ref(null);
343
- let previouslyFocused = null;
344
- const FOCUSABLE_SELECTOR = [
345
- "a[href]",
346
- "button:not([disabled])",
347
- "input:not([disabled])",
348
- "select:not([disabled])",
349
- "textarea:not([disabled])",
350
- "[tabindex]:not([tabindex=\"-1\"])"
351
- ].join(",");
352
- /** Visible, focusable controls inside the dialog, in DOM order. */
353
- function focusableItems() {
354
- if (!dialogEl.value) return [];
355
- return Array.from(dialogEl.value.querySelectorAll(FOCUSABLE_SELECTOR)).filter((node) => node.offsetParent !== null);
356
- }
357
- /** Trap Tab / Shift+Tab inside the dialog so focus can't escape to the
358
- * page behind the overlay. Wraps at both ends; the dialog container
359
- * itself (tabindex -1) counts as "before the first item". */
360
- function onTab(event) {
361
- const items = focusableItems();
362
- if (items.length === 0) {
363
- event.preventDefault();
364
- dialogEl.value?.focus();
365
- return;
366
- }
367
- const [first] = items;
368
- const last = items[items.length - 1];
369
- const active = document.activeElement;
370
- if (event.shiftKey) {
371
- if (active === first || active === dialogEl.value) {
372
- event.preventDefault();
373
- last.focus();
374
- }
375
- } else if (active === last) {
376
- event.preventDefault();
377
- first.focus();
378
- }
379
- }
380
- onMounted(async () => {
381
- previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
382
- await nextTick();
383
- dialogEl.value?.focus();
384
- });
385
- onBeforeUnmount(() => {
386
- previouslyFocused?.focus?.();
387
- });
388
- return (_ctx, _cache) => {
389
- return openBlock(), createBlock(Teleport, { to: "body" }, [createElementVNode("div", {
390
- class: "fixed inset-0 z-40 flex items-center justify-center bg-slate-900/40 p-4",
391
- "data-testid": "collections-record-modal",
392
- onClick: _cache[1] || (_cache[1] = withModifiers(($event) => emit("close"), ["self"]))
393
- }, [createElementVNode("div", {
394
- ref_key: "dialogEl",
395
- ref: dialogEl,
396
- class: "flex max-h-[85vh] w-full max-w-2xl flex-col overflow-hidden rounded-2xl bg-white shadow-xl focus:outline-none",
397
- role: "dialog",
398
- "aria-modal": "true",
399
- tabindex: "-1",
400
- onKeydown: [_cache[0] || (_cache[0] = withKeys(($event) => emit("close"), ["esc"])), withKeys(onTab, ["tab"])]
401
- }, [renderSlot(_ctx.$slots, "default")], 544)])]);
402
- };
403
- }
404
- });
405
- //#endregion
406
17
  //#region src/vue/lang/index.ts
407
18
  var i18n = createI18n({
408
19
  legacy: false,
@@ -494,6 +105,7 @@ var i18n = createI18n({
494
105
  }
495
106
  },
496
107
  common: {
108
+ close: "Close",
497
109
  add: "Add",
498
110
  cancel: "Cancel",
499
111
  loading: "Loading...",
@@ -502,6 +114,11 @@ var i18n = createI18n({
502
114
  save: "Save",
503
115
  saving: "Saving...",
504
116
  yes: "Yes"
117
+ },
118
+ pluginPresentCollection: {
119
+ fallbackTitle: "Collection",
120
+ itemLabel: "Item: {id}",
121
+ listLabel: "All records"
505
122
  }
506
123
  },
507
124
  ja: {
@@ -589,6 +206,7 @@ var i18n = createI18n({
589
206
  }
590
207
  },
591
208
  common: {
209
+ close: "閉じる",
592
210
  add: "追加",
593
211
  cancel: "キャンセル",
594
212
  loading: "読み込み中...",
@@ -597,6 +215,11 @@ var i18n = createI18n({
597
215
  save: "保存",
598
216
  saving: "保存中...",
599
217
  yes: "はい"
218
+ },
219
+ pluginPresentCollection: {
220
+ fallbackTitle: "コレクション",
221
+ itemLabel: "項目: {id}",
222
+ listLabel: "すべてのレコード"
600
223
  }
601
224
  },
602
225
  zh: {
@@ -684,6 +307,7 @@ var i18n = createI18n({
684
307
  }
685
308
  },
686
309
  common: {
310
+ close: "关闭",
687
311
  add: "添加",
688
312
  cancel: "取消",
689
313
  loading: "加载中...",
@@ -692,6 +316,11 @@ var i18n = createI18n({
692
316
  save: "保存",
693
317
  saving: "保存中...",
694
318
  yes: "是"
319
+ },
320
+ pluginPresentCollection: {
321
+ fallbackTitle: "集合",
322
+ itemLabel: "项目:{id}",
323
+ listLabel: "全部记录"
695
324
  }
696
325
  },
697
326
  ko: {
@@ -779,6 +408,7 @@ var i18n = createI18n({
779
408
  }
780
409
  },
781
410
  common: {
411
+ close: "닫기",
782
412
  add: "추가",
783
413
  cancel: "취소",
784
414
  loading: "불러오는 중...",
@@ -787,6 +417,11 @@ var i18n = createI18n({
787
417
  save: "저장",
788
418
  saving: "저장 중...",
789
419
  yes: "예"
420
+ },
421
+ pluginPresentCollection: {
422
+ fallbackTitle: "컬렉션",
423
+ itemLabel: "항목: {id}",
424
+ listLabel: "모든 레코드"
790
425
  }
791
426
  },
792
427
  es: {
@@ -874,6 +509,7 @@ var i18n = createI18n({
874
509
  }
875
510
  },
876
511
  common: {
512
+ close: "Cerrar",
877
513
  add: "Añadir",
878
514
  cancel: "Cancelar",
879
515
  loading: "Cargando...",
@@ -882,6 +518,11 @@ var i18n = createI18n({
882
518
  save: "Guardar",
883
519
  saving: "Guardando...",
884
520
  yes: "Sí"
521
+ },
522
+ pluginPresentCollection: {
523
+ fallbackTitle: "Colección",
524
+ itemLabel: "Elemento: {id}",
525
+ listLabel: "Todos los registros"
885
526
  }
886
527
  },
887
528
  "pt-BR": {
@@ -969,6 +610,7 @@ var i18n = createI18n({
969
610
  }
970
611
  },
971
612
  common: {
613
+ close: "Fechar",
972
614
  add: "Adicionar",
973
615
  cancel: "Cancelar",
974
616
  loading: "Carregando...",
@@ -977,6 +619,11 @@ var i18n = createI18n({
977
619
  save: "Salvar",
978
620
  saving: "Salvando...",
979
621
  yes: "Sim"
622
+ },
623
+ pluginPresentCollection: {
624
+ fallbackTitle: "Coleção",
625
+ itemLabel: "Item: {id}",
626
+ listLabel: "Todos os registros"
980
627
  }
981
628
  },
982
629
  fr: {
@@ -1064,6 +711,7 @@ var i18n = createI18n({
1064
711
  }
1065
712
  },
1066
713
  common: {
714
+ close: "Fermer",
1067
715
  add: "Ajouter",
1068
716
  cancel: "Annuler",
1069
717
  loading: "Chargement...",
@@ -1072,6 +720,11 @@ var i18n = createI18n({
1072
720
  save: "Enregistrer",
1073
721
  saving: "Enregistrement...",
1074
722
  yes: "Oui"
723
+ },
724
+ pluginPresentCollection: {
725
+ fallbackTitle: "Collection",
726
+ itemLabel: "Élément : {id}",
727
+ listLabel: "Tous les enregistrements"
1075
728
  }
1076
729
  },
1077
730
  de: {
@@ -1159,6 +812,7 @@ var i18n = createI18n({
1159
812
  }
1160
813
  },
1161
814
  common: {
815
+ close: "Schließen",
1162
816
  add: "Hinzufügen",
1163
817
  cancel: "Abbrechen",
1164
818
  loading: "Wird geladen...",
@@ -1167,6 +821,11 @@ var i18n = createI18n({
1167
821
  save: "Speichern",
1168
822
  saving: "Wird gespeichert...",
1169
823
  yes: "Ja"
824
+ },
825
+ pluginPresentCollection: {
826
+ fallbackTitle: "Sammlung",
827
+ itemLabel: "Eintrag: {id}",
828
+ listLabel: "Alle Datensätze"
1170
829
  }
1171
830
  }
1172
831
  }
@@ -1179,12 +838,12 @@ var syncing = false;
1179
838
  * configured the binding, so `collectionUi()` resolves. */
1180
839
  function ensureLocaleSync() {
1181
840
  if (syncing) return;
1182
- syncing = true;
1183
841
  syncScope.run(() => {
1184
842
  watchEffect(() => {
1185
843
  i18n.global.locale.value = collectionUi().localeTag();
1186
844
  });
1187
845
  });
846
+ syncing = true;
1188
847
  }
1189
848
  /** The plugin's i18n composable — a drop-in for vue-i18n's `useI18n()` over the
1190
849
  * plugin's own self-contained instance. Returns `{ t, locale }` (destructured at
@@ -1198,121 +857,106 @@ function useCollectionI18n() {
1198
857
  };
1199
858
  }
1200
859
  //#endregion
1201
- //#region src/vue/components/CollectionEmbedView.vue?vue&type=script&setup=true&lang.ts
1202
- var _hoisted_1$9 = { class: "flex items-center justify-between text-[10px] font-bold text-indigo-600/90 tracking-wider uppercase" };
1203
- var _hoisted_2$9 = { class: "flex items-center gap-1.5" };
1204
- var _hoisted_3$9 = { class: "bg-indigo-100/60 text-indigo-700 px-1.5 py-0.5 rounded font-mono font-medium lowercase" };
1205
- var _hoisted_4$9 = { class: "grid gap-x-4 gap-y-3 grid-cols-2" };
1206
- var _hoisted_5$8 = { class: "text-[10px] font-semibold text-slate-400 uppercase tracking-wide" };
1207
- var _hoisted_6$8 = ["data-testid"];
1208
- var _hoisted_7$8 = {
1209
- key: 0,
1210
- class: "material-icons text-emerald-600 text-sm align-middle"
1211
- };
1212
- var _hoisted_8$8 = {
1213
- key: 1,
1214
- class: "text-slate-300"
1215
- };
1216
- var _hoisted_9$8 = {
1217
- key: 1,
1218
- class: "whitespace-pre-wrap font-normal text-slate-600"
1219
- };
1220
- var _hoisted_10$8 = { key: 2 };
1221
- var _hoisted_11$8 = ["data-testid"];
1222
- var _hoisted_12$7 = { class: "flex items-start gap-3" };
1223
- var _hoisted_13$6 = { class: "flex-1 min-w-0" };
1224
- var _hoisted_14$5 = { class: "text-xs font-semibold text-red-800 uppercase tracking-wider mb-1" };
1225
- var _hoisted_15$5 = ["data-testid"];
1226
- //#endregion
1227
- //#region src/vue/components/CollectionEmbedView.vue
1228
- var CollectionEmbedView_default = /* @__PURE__ */ defineComponent({
1229
- __name: "CollectionEmbedView",
1230
- props: {
1231
- view: {},
1232
- fieldKey: {}
1233
- },
1234
- setup(__props) {
1235
- const { t } = useCollectionI18n();
860
+ //#region src/vue/components/CollectionRecordModal.vue
861
+ var CollectionRecordModal_default = /* @__PURE__ */ defineComponent({
862
+ __name: "CollectionRecordModal",
863
+ emits: ["close"],
864
+ setup(__props, { emit: __emit }) {
865
+ const emit = __emit;
866
+ const teleportTarget = collectionUi().modalTeleportTarget?.() ?? "body";
867
+ const dialogEl = ref(null);
868
+ let previouslyFocused = null;
869
+ const FOCUSABLE_SELECTOR = [
870
+ "a[href]",
871
+ "button:not([disabled])",
872
+ "input:not([disabled])",
873
+ "select:not([disabled])",
874
+ "textarea:not([disabled])",
875
+ "[tabindex]:not([tabindex=\"-1\"])"
876
+ ].join(",");
877
+ /** Visible, focusable controls inside the dialog, in DOM order. */
878
+ function focusableItems() {
879
+ if (!dialogEl.value) return [];
880
+ return Array.from(dialogEl.value.querySelectorAll(FOCUSABLE_SELECTOR)).filter((node) => node.offsetParent !== null);
881
+ }
882
+ /** Trap Tab / Shift+Tab inside the dialog so focus can't escape to the
883
+ * page behind the overlay. Wraps at both ends; the dialog container
884
+ * itself (tabindex -1) counts as "before the first item". */
885
+ function onTab(event) {
886
+ const items = focusableItems();
887
+ if (items.length === 0) {
888
+ event.preventDefault();
889
+ dialogEl.value?.focus();
890
+ return;
891
+ }
892
+ const [first] = items;
893
+ const last = items[items.length - 1];
894
+ const active = document.activeElement;
895
+ if (event.shiftKey) {
896
+ if (active === first || active === dialogEl.value) {
897
+ event.preventDefault();
898
+ last.focus();
899
+ }
900
+ } else if (active === last) {
901
+ event.preventDefault();
902
+ first.focus();
903
+ }
904
+ }
905
+ onMounted(async () => {
906
+ previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
907
+ await nextTick();
908
+ dialogEl.value?.focus();
909
+ });
910
+ onBeforeUnmount(() => {
911
+ previouslyFocused?.focus?.();
912
+ });
1236
913
  return (_ctx, _cache) => {
1237
- const _component_router_link = resolveComponent("router-link");
1238
- return __props.view.found ? (openBlock(), createBlock(_component_router_link, {
1239
- key: 0,
1240
- to: {
1241
- path: `/collections/${__props.view.targetSlug}`,
1242
- query: { selected: __props.view.recordId }
1243
- },
1244
- class: "group block relative rounded-xl border border-slate-200 bg-slate-50/50 p-4 pl-5 space-y-3 hover:bg-indigo-50/20 hover:border-indigo-200 transition-all duration-300 shadow-sm",
1245
- "data-testid": `collections-embed-${__props.fieldKey}`
1246
- }, {
1247
- default: withCtx(() => [
1248
- _cache[1] || (_cache[1] = createElementVNode("div", { class: "absolute left-0 top-0 bottom-0 w-1 bg-indigo-500 rounded-l-xl transition-all duration-300 group-hover:w-1.5 group-hover:bg-indigo-600" }, null, -1)),
1249
- createElementVNode("div", _hoisted_1$9, [createElementVNode("div", _hoisted_2$9, [_cache[0] || (_cache[0] = createElementVNode("span", { class: "material-icons text-sm" }, "link", -1)), createElementVNode("span", null, toDisplayString(__props.view.targetSlug), 1)]), createElementVNode("span", _hoisted_3$9, toDisplayString(__props.view.recordId), 1)]),
1250
- createElementVNode("div", _hoisted_4$9, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.view.rows, (row) => {
1251
- return openBlock(), createElementBlock("div", {
1252
- key: row.key,
1253
- class: "space-y-0.5"
1254
- }, [createElementVNode("div", _hoisted_5$8, toDisplayString(row.label), 1), createElementVNode("div", {
1255
- class: "text-xs text-slate-700 font-medium break-words",
1256
- "data-testid": `collections-embed-${__props.fieldKey}-${row.key}`
1257
- }, [row.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [row.value === true ? (openBlock(), createElementBlock("span", _hoisted_7$8, "check_circle")) : (openBlock(), createElementBlock("span", _hoisted_8$8, "—"))], 64)) : row.type === "markdown" ? (openBlock(), createElementBlock("p", _hoisted_9$8, toDisplayString(row.display), 1)) : (openBlock(), createElementBlock("span", _hoisted_10$8, toDisplayString(row.display), 1))], 8, _hoisted_6$8)]);
1258
- }), 128))])
1259
- ]),
1260
- _: 1
1261
- }, 8, ["to", "data-testid"])) : (openBlock(), createElementBlock("div", {
1262
- key: 1,
1263
- class: "relative rounded-xl border border-red-100 bg-red-50/30 p-4 pl-5 shadow-sm",
1264
- "data-testid": `collections-embed-${__props.fieldKey}`
1265
- }, [_cache[4] || (_cache[4] = createElementVNode("div", { class: "absolute left-0 top-0 bottom-0 w-1 bg-red-400 rounded-l-xl" }, null, -1)), createElementVNode("div", _hoisted_12$7, [_cache[3] || (_cache[3] = createElementVNode("span", { class: "material-icons text-red-500 text-lg mt-0.5" }, "error_outline", -1)), createElementVNode("div", _hoisted_13$6, [
1266
- createElementVNode("p", _hoisted_14$5, toDisplayString(unref(t)("collectionsView.embedMissingTitle")), 1),
1267
- createElementVNode("p", {
1268
- class: "text-xs text-red-600",
1269
- "data-testid": `collections-embed-missing-${__props.fieldKey}`
1270
- }, toDisplayString(unref(t)("collectionsView.embedMissing", {
1271
- collection: __props.view.targetSlug,
1272
- id: __props.view.recordId
1273
- })), 9, _hoisted_15$5),
1274
- __props.view.targetSlug ? (openBlock(), createBlock(_component_router_link, {
1275
- key: 0,
1276
- to: { path: `/collections/${__props.view.targetSlug}` },
1277
- class: "inline-flex items-center gap-0.5 text-xs text-indigo-600 hover:text-indigo-800 font-semibold mt-2 hover:underline"
1278
- }, {
1279
- default: withCtx(() => [createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.embedCreate")), 1), _cache[2] || (_cache[2] = createElementVNode("span", { class: "material-icons text-xs" }, "arrow_forward", -1))]),
1280
- _: 1
1281
- }, 8, ["to"])) : createCommentVNode("", true)
1282
- ])])], 8, _hoisted_11$8));
914
+ return openBlock(), createBlock(Teleport, { to: unref(teleportTarget) }, [createElementVNode("div", {
915
+ class: "fixed inset-0 z-40 flex items-center justify-center bg-slate-900/40 p-4",
916
+ "data-testid": "collections-record-modal",
917
+ onClick: _cache[1] || (_cache[1] = withModifiers(($event) => emit("close"), ["self"]))
918
+ }, [createElementVNode("div", {
919
+ ref_key: "dialogEl",
920
+ ref: dialogEl,
921
+ class: "flex max-h-[85vh] w-full max-w-2xl flex-col overflow-hidden rounded-2xl bg-white shadow-xl focus:outline-none",
922
+ role: "dialog",
923
+ "aria-modal": "true",
924
+ tabindex: "-1",
925
+ onKeydown: [_cache[0] || (_cache[0] = withKeys(($event) => emit("close"), ["esc"])), withKeys(onTab, ["tab"])]
926
+ }, [renderSlot(_ctx.$slots, "default")], 544)])], 8, ["to"]);
1283
927
  };
1284
928
  }
1285
929
  });
1286
930
  //#endregion
1287
931
  //#region src/vue/components/CollectionCalendarView.vue?vue&type=script&setup=true&lang.ts
1288
- var _hoisted_1$8 = {
932
+ var _hoisted_1$11 = {
1289
933
  class: "flex flex-col gap-3",
1290
934
  "data-testid": "collection-calendar"
1291
935
  };
1292
- var _hoisted_2$8 = { class: "flex items-center gap-2" };
1293
- var _hoisted_3$8 = ["aria-label"];
1294
- var _hoisted_4$8 = ["aria-label"];
1295
- var _hoisted_5$7 = {
936
+ var _hoisted_2$10 = { class: "flex items-center gap-2" };
937
+ var _hoisted_3$10 = ["aria-label"];
938
+ var _hoisted_4$10 = ["aria-label"];
939
+ var _hoisted_5$9 = {
1296
940
  class: "text-sm font-bold text-slate-800 flex-1",
1297
941
  "data-testid": "collection-calendar-month"
1298
942
  };
1299
- var _hoisted_6$7 = { class: "grid grid-cols-7 gap-1 text-[10px] font-bold text-slate-400 uppercase tracking-wider select-none" };
1300
- var _hoisted_7$7 = { class: "grid grid-cols-7 gap-1" };
1301
- var _hoisted_8$7 = [
943
+ var _hoisted_6$8 = { class: "grid grid-cols-7 gap-1 text-[10px] font-bold text-slate-400 uppercase tracking-wider select-none" };
944
+ var _hoisted_7$8 = { class: "grid grid-cols-7 gap-1" };
945
+ var _hoisted_8$8 = [
1302
946
  "aria-label",
1303
947
  "data-testid",
1304
948
  "onClick",
1305
949
  "onKeydown"
1306
950
  ];
1307
- var _hoisted_9$7 = { class: "flex items-center justify-end" };
1308
- var _hoisted_10$7 = ["data-testid", "onClick"];
1309
- var _hoisted_11$7 = {
951
+ var _hoisted_9$8 = { class: "flex items-center justify-end" };
952
+ var _hoisted_10$8 = ["data-testid", "onClick"];
953
+ var _hoisted_11$8 = {
1310
954
  key: 0,
1311
955
  class: "flex flex-wrap items-center gap-1.5 pt-1",
1312
956
  "data-testid": "collection-calendar-no-date"
1313
957
  };
1314
- var _hoisted_12$6 = { class: "text-[10px] font-bold text-slate-400 uppercase tracking-wider mr-1" };
1315
- var _hoisted_13$5 = ["data-testid", "onClick"];
958
+ var _hoisted_12$7 = { class: "text-[10px] font-bold text-slate-400 uppercase tracking-wider mr-1" };
959
+ var _hoisted_13$6 = ["data-testid", "onClick"];
1316
960
  /** Sort key for ordering a day's chips by start time: earliest first, with
1317
961
  * clock-less all-day records sinking to the bottom (matching the day view). */
1318
962
  var DAY_CHIP_DEFAULT = "bg-indigo-50 text-indigo-700 border-indigo-100 hover:bg-indigo-100";
@@ -1426,23 +1070,23 @@ var CollectionCalendarView_default = /* @__PURE__ */ defineComponent({
1426
1070
  viewMonth.value = now.getMonth() + 1;
1427
1071
  }
1428
1072
  return (_ctx, _cache) => {
1429
- return openBlock(), createElementBlock("div", _hoisted_1$8, [
1430
- createElementVNode("div", _hoisted_2$8, [
1073
+ return openBlock(), createElementBlock("div", _hoisted_1$11, [
1074
+ createElementVNode("div", _hoisted_2$10, [
1431
1075
  createElementVNode("button", {
1432
1076
  type: "button",
1433
1077
  class: "h-8 w-8 flex items-center justify-center rounded text-slate-500 hover:bg-slate-100 transition-colors",
1434
1078
  "aria-label": unref(t)("collectionsView.calendarPrevMonth"),
1435
1079
  "data-testid": "collection-calendar-prev",
1436
1080
  onClick: _cache[0] || (_cache[0] = ($event) => stepMonth(-1))
1437
- }, [..._cache[2] || (_cache[2] = [createElementVNode("span", { class: "material-icons text-lg" }, "chevron_left", -1)])], 8, _hoisted_3$8),
1081
+ }, [..._cache[2] || (_cache[2] = [createElementVNode("span", { class: "material-icons text-lg" }, "chevron_left", -1)])], 8, _hoisted_3$10),
1438
1082
  createElementVNode("button", {
1439
1083
  type: "button",
1440
1084
  class: "h-8 w-8 flex items-center justify-center rounded text-slate-500 hover:bg-slate-100 transition-colors",
1441
1085
  "aria-label": unref(t)("collectionsView.calendarNextMonth"),
1442
1086
  "data-testid": "collection-calendar-next",
1443
1087
  onClick: _cache[1] || (_cache[1] = ($event) => stepMonth(1))
1444
- }, [..._cache[3] || (_cache[3] = [createElementVNode("span", { class: "material-icons text-lg" }, "chevron_right", -1)])], 8, _hoisted_4$8),
1445
- createElementVNode("h3", _hoisted_5$7, toDisplayString(monthLabel.value), 1),
1088
+ }, [..._cache[3] || (_cache[3] = [createElementVNode("span", { class: "material-icons text-lg" }, "chevron_right", -1)])], 8, _hoisted_4$10),
1089
+ createElementVNode("h3", _hoisted_5$9, toDisplayString(monthLabel.value), 1),
1446
1090
  createElementVNode("button", {
1447
1091
  type: "button",
1448
1092
  class: "h-8 px-2.5 flex items-center gap-1 rounded border border-slate-200 bg-white text-slate-600 hover:bg-slate-50 text-xs font-bold transition-colors",
@@ -1450,13 +1094,13 @@ var CollectionCalendarView_default = /* @__PURE__ */ defineComponent({
1450
1094
  onClick: goToday
1451
1095
  }, toDisplayString(unref(t)("collectionsView.calendarToday")), 1)
1452
1096
  ]),
1453
- createElementVNode("div", _hoisted_6$7, [(openBlock(true), createElementBlock(Fragment, null, renderList(weekdayLabels.value, (label, idx) => {
1097
+ createElementVNode("div", _hoisted_6$8, [(openBlock(true), createElementBlock(Fragment, null, renderList(weekdayLabels.value, (label, idx) => {
1454
1098
  return openBlock(), createElementBlock("div", {
1455
1099
  key: idx,
1456
1100
  class: "px-1 py-1 text-center"
1457
1101
  }, toDisplayString(label), 1);
1458
1102
  }), 128))]),
1459
- createElementVNode("div", _hoisted_7$7, [(openBlock(true), createElementBlock(Fragment, null, renderList(cells.value, ({ cell, entries }) => {
1103
+ createElementVNode("div", _hoisted_7$8, [(openBlock(true), createElementBlock(Fragment, null, renderList(cells.value, ({ cell, entries }) => {
1460
1104
  return openBlock(), createElementBlock("div", {
1461
1105
  key: cell.key,
1462
1106
  class: normalizeClass(["min-h-[5.5rem] rounded-lg border p-1 flex flex-col gap-1 overflow-hidden transition-colors cursor-pointer hover:border-indigo-300 focus:outline-none focus:ring-2 focus:ring-indigo-500/30", cell.inMonth ? "bg-white border-slate-200" : "bg-slate-50/50 border-slate-100"]),
@@ -1466,24 +1110,24 @@ var CollectionCalendarView_default = /* @__PURE__ */ defineComponent({
1466
1110
  "data-testid": `collection-calendar-day-${cell.key}`,
1467
1111
  onClick: ($event) => emit("openDay", cell.ymd),
1468
1112
  onKeydown: [withKeys(withModifiers(($event) => emit("openDay", cell.ymd), ["self", "prevent"]), ["enter"]), withKeys(withModifiers(($event) => emit("openDay", cell.ymd), ["self", "prevent"]), ["space"])]
1469
- }, [createElementVNode("div", _hoisted_9$7, [createElementVNode("span", { class: normalizeClass(["text-[11px] font-bold h-5 min-w-5 px-1 inline-flex items-center justify-center rounded-full", cell.key === unref(todayKey) ? "bg-indigo-600 text-white" : cell.inMonth ? "text-slate-500" : "text-slate-300"]) }, toDisplayString(cell.ymd.day), 3)]), (openBlock(true), createElementBlock(Fragment, null, renderList(entries, (entry) => {
1113
+ }, [createElementVNode("div", _hoisted_9$8, [createElementVNode("span", { class: normalizeClass(["text-[11px] font-bold h-5 min-w-5 px-1 inline-flex items-center justify-center rounded-full", cell.key === unref(todayKey) ? "bg-indigo-600 text-white" : cell.inMonth ? "text-slate-500" : "text-slate-300"]) }, toDisplayString(cell.ymd.day), 3)]), (openBlock(true), createElementBlock(Fragment, null, renderList(entries, (entry) => {
1470
1114
  return openBlock(), createElementBlock("button", {
1471
1115
  key: entry.id,
1472
1116
  type: "button",
1473
1117
  class: normalizeClass(["text-left text-[11px] leading-tight font-semibold truncate rounded px-1.5 py-0.5 border transition-colors", chipClass(entry, DAY_CHIP_DEFAULT)]),
1474
1118
  "data-testid": `collection-calendar-chip-${entry.id}`,
1475
1119
  onClick: withModifiers(($event) => emit("select", entry.id), ["stop"])
1476
- }, toDisplayString(entry.label), 11, _hoisted_10$7);
1477
- }), 128))], 42, _hoisted_8$7);
1120
+ }, toDisplayString(entry.label), 11, _hoisted_10$8);
1121
+ }), 128))], 42, _hoisted_8$8);
1478
1122
  }), 128))]),
1479
- bucketed.value.noDate.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_11$7, [createElementVNode("span", _hoisted_12$6, toDisplayString(unref(t)("collectionsView.calendarNoDate")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(undatedEntries.value, (entry) => {
1123
+ bucketed.value.noDate.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_11$8, [createElementVNode("span", _hoisted_12$7, toDisplayString(unref(t)("collectionsView.calendarNoDate")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(undatedEntries.value, (entry) => {
1480
1124
  return openBlock(), createElementBlock("button", {
1481
1125
  key: entry.id,
1482
1126
  type: "button",
1483
1127
  class: normalizeClass(["text-[11px] font-semibold truncate rounded px-1.5 py-0.5 border transition-colors", chipClass(entry, UNDATED_CHIP_DEFAULT)]),
1484
1128
  "data-testid": `collection-calendar-undated-${entry.id}`,
1485
1129
  onClick: ($event) => emit("select", entry.id)
1486
- }, toDisplayString(entry.label), 11, _hoisted_13$5);
1130
+ }, toDisplayString(entry.label), 11, _hoisted_13$6);
1487
1131
  }), 128))])) : createCommentVNode("", true)
1488
1132
  ]);
1489
1133
  };
@@ -1491,40 +1135,40 @@ var CollectionCalendarView_default = /* @__PURE__ */ defineComponent({
1491
1135
  });
1492
1136
  //#endregion
1493
1137
  //#region src/vue/components/CollectionDayView.vue?vue&type=script&setup=true&lang.ts
1494
- var _hoisted_1$7 = { class: "flex items-center gap-2 border-b border-slate-200 px-4 py-3" };
1495
- var _hoisted_2$7 = {
1138
+ var _hoisted_1$10 = { class: "flex items-center gap-2 border-b border-slate-200 px-4 py-3" };
1139
+ var _hoisted_2$9 = {
1496
1140
  class: "flex-1 text-sm font-bold text-slate-800",
1497
1141
  "data-testid": "collection-day-view-title"
1498
1142
  };
1499
- var _hoisted_3$7 = ["aria-label"];
1500
- var _hoisted_4$7 = ["aria-label"];
1501
- var _hoisted_5$6 = {
1143
+ var _hoisted_3$9 = ["aria-label"];
1144
+ var _hoisted_4$9 = ["aria-label"];
1145
+ var _hoisted_5$8 = {
1502
1146
  key: 0,
1503
1147
  class: "px-4 py-10 text-center text-sm text-slate-400"
1504
1148
  };
1505
- var _hoisted_6$6 = { class: "absolute -top-2 left-0 w-10 pr-1 text-right text-[10px] tabular-nums text-slate-400" };
1506
- var _hoisted_7$6 = {
1149
+ var _hoisted_6$7 = { class: "absolute -top-2 left-0 w-10 pr-1 text-right text-[10px] tabular-nums text-slate-400" };
1150
+ var _hoisted_7$7 = {
1507
1151
  class: "absolute inset-y-0 right-0",
1508
1152
  style: { "left": "2.75rem" }
1509
1153
  };
1510
- var _hoisted_8$6 = ["data-testid", "onClick"];
1511
- var _hoisted_9$6 = { class: "block truncate text-[11px] font-semibold leading-tight" };
1512
- var _hoisted_10$6 = {
1154
+ var _hoisted_8$7 = ["data-testid", "onClick"];
1155
+ var _hoisted_9$7 = { class: "block truncate text-[11px] font-semibold leading-tight" };
1156
+ var _hoisted_10$7 = {
1513
1157
  key: 0,
1514
1158
  "aria-hidden": "true"
1515
1159
  };
1516
- var _hoisted_11$6 = {
1160
+ var _hoisted_11$7 = {
1517
1161
  key: 1,
1518
1162
  "aria-hidden": "true"
1519
1163
  };
1520
- var _hoisted_12$5 = {
1164
+ var _hoisted_12$6 = {
1521
1165
  key: 2,
1522
1166
  class: "flex flex-wrap items-center gap-1.5 border-t border-slate-200 px-4 py-2",
1523
1167
  "data-testid": "collection-day-view-all-day"
1524
1168
  };
1525
- var _hoisted_13$4 = { class: "mr-1 text-[10px] font-bold uppercase tracking-wider text-slate-400" };
1526
- var _hoisted_14$4 = ["data-testid", "onClick"];
1527
- var _hoisted_15$4 = {
1169
+ var _hoisted_13$5 = { class: "mr-1 text-[10px] font-bold uppercase tracking-wider text-slate-400" };
1170
+ var _hoisted_14$5 = ["data-testid", "onClick"];
1171
+ var _hoisted_15$5 = {
1528
1172
  key: 0,
1529
1173
  class: "min-w-0 flex-1 overflow-y-auto",
1530
1174
  "data-testid": "collection-day-view-detail"
@@ -1683,8 +1327,8 @@ var CollectionDayView_default = /* @__PURE__ */ defineComponent({
1683
1327
  role: "dialog",
1684
1328
  "aria-modal": "true"
1685
1329
  }, [createElementVNode("div", { class: normalizeClass(["flex min-h-0 flex-col", __props.showDetail ? "w-80 shrink-0 border-r border-slate-200" : "w-full"]) }, [
1686
- createElementVNode("div", _hoisted_1$7, [
1687
- createElementVNode("h3", _hoisted_2$7, toDisplayString(dayLabel.value), 1),
1330
+ createElementVNode("div", _hoisted_1$10, [
1331
+ createElementVNode("h3", _hoisted_2$9, toDisplayString(dayLabel.value), 1),
1688
1332
  __props.canCreate ? (openBlock(), createElementBlock("button", {
1689
1333
  key: 0,
1690
1334
  type: "button",
@@ -1692,16 +1336,16 @@ var CollectionDayView_default = /* @__PURE__ */ defineComponent({
1692
1336
  "aria-label": unref(t)("collectionsView.calendarCreateOn", { date: dayKey.value }),
1693
1337
  "data-testid": "collection-day-view-create",
1694
1338
  onClick: onCreate
1695
- }, [..._cache[3] || (_cache[3] = [createElementVNode("span", { class: "material-icons text-lg" }, "add", -1)])], 8, _hoisted_3$7)) : createCommentVNode("", true),
1339
+ }, [..._cache[3] || (_cache[3] = [createElementVNode("span", { class: "material-icons text-lg" }, "add", -1)])], 8, _hoisted_3$9)) : createCommentVNode("", true),
1696
1340
  createElementVNode("button", {
1697
1341
  type: "button",
1698
1342
  class: "h-8 w-8 flex items-center justify-center rounded text-slate-500 hover:bg-slate-100 transition-colors",
1699
1343
  "aria-label": unref(t)("collectionsView.dayViewClose"),
1700
1344
  "data-testid": "collection-day-view-close",
1701
1345
  onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
1702
- }, [..._cache[4] || (_cache[4] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_4$7)
1346
+ }, [..._cache[4] || (_cache[4] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_4$9)
1703
1347
  ]),
1704
- timedEntries.value.length === 0 && allDayEntries.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_5$6, toDisplayString(unref(t)("collectionsView.dayViewEmpty")), 1)) : (openBlock(), createElementBlock("div", {
1348
+ timedEntries.value.length === 0 && allDayEntries.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_5$8, toDisplayString(unref(t)("collectionsView.dayViewEmpty")), 1)) : (openBlock(), createElementBlock("div", {
1705
1349
  key: 1,
1706
1350
  ref_key: "scrollEl",
1707
1351
  ref: scrollEl,
@@ -1715,8 +1359,8 @@ var CollectionDayView_default = /* @__PURE__ */ defineComponent({
1715
1359
  key: hour,
1716
1360
  class: "absolute left-0 right-0 border-t border-slate-100",
1717
1361
  style: normalizeStyle({ top: `${(hour - 1) * HOUR_PX}px` })
1718
- }, [createElementVNode("span", _hoisted_6$6, toDisplayString(hourLabel(hour - 1)), 1)], 4);
1719
- }), 64)), createElementVNode("div", _hoisted_7$6, [(openBlock(true), createElementBlock(Fragment, null, renderList(timedEntries.value, (entry) => {
1362
+ }, [createElementVNode("span", _hoisted_6$7, toDisplayString(hourLabel(hour - 1)), 1)], 4);
1363
+ }), 64)), createElementVNode("div", _hoisted_7$7, [(openBlock(true), createElementBlock(Fragment, null, renderList(timedEntries.value, (entry) => {
1720
1364
  return openBlock(), createElementBlock("button", {
1721
1365
  key: entry.id,
1722
1366
  type: "button",
@@ -1724,56 +1368,56 @@ var CollectionDayView_default = /* @__PURE__ */ defineComponent({
1724
1368
  style: normalizeStyle(entry.style),
1725
1369
  "data-testid": `collection-day-view-chip-${entry.id}`,
1726
1370
  onClick: ($event) => onSelect(entry.id)
1727
- }, [createElementVNode("span", _hoisted_9$6, [
1728
- entry.slice.bleedsBefore ? (openBlock(), createElementBlock("span", _hoisted_10$6, "▲ ")) : createCommentVNode("", true),
1371
+ }, [createElementVNode("span", _hoisted_9$7, [
1372
+ entry.slice.bleedsBefore ? (openBlock(), createElementBlock("span", _hoisted_10$7, "▲ ")) : createCommentVNode("", true),
1729
1373
  createTextVNode(toDisplayString(entry.label), 1),
1730
- entry.slice.bleedsAfter ? (openBlock(), createElementBlock("span", _hoisted_11$6, " ▼")) : createCommentVNode("", true)
1374
+ entry.slice.bleedsAfter ? (openBlock(), createElementBlock("span", _hoisted_11$7, " ▼")) : createCommentVNode("", true)
1731
1375
  ]), (openBlock(true), createElementBlock(Fragment, null, renderList(entry.secondary, (text, i) => {
1732
1376
  return openBlock(), createElementBlock("span", {
1733
1377
  key: i,
1734
1378
  class: "block truncate text-[10px] leading-tight opacity-70"
1735
1379
  }, toDisplayString(text), 1);
1736
- }), 128))], 14, _hoisted_8$6);
1380
+ }), 128))], 14, _hoisted_8$7);
1737
1381
  }), 128))])], 4)], 512)),
1738
- allDayEntries.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_12$5, [createElementVNode("span", _hoisted_13$4, toDisplayString(unref(t)("collectionsView.dayViewAllDay")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(allDayEntries.value, (entry) => {
1382
+ allDayEntries.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_12$6, [createElementVNode("span", _hoisted_13$5, toDisplayString(unref(t)("collectionsView.dayViewAllDay")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(allDayEntries.value, (entry) => {
1739
1383
  return openBlock(), createElementBlock("button", {
1740
1384
  key: entry.id,
1741
1385
  type: "button",
1742
1386
  class: normalizeClass(["truncate rounded border px-1.5 py-0.5 text-[11px] font-semibold transition-colors", allDayChipClass(entry)]),
1743
1387
  "data-testid": `collection-day-view-allday-${entry.id}`,
1744
1388
  onClick: ($event) => onSelect(entry.id)
1745
- }, toDisplayString(entry.label), 11, _hoisted_14$4);
1389
+ }, toDisplayString(entry.label), 11, _hoisted_14$5);
1746
1390
  }), 128))])) : createCommentVNode("", true)
1747
- ], 2), __props.showDetail ? (openBlock(), createElementBlock("div", _hoisted_15$4, [renderSlot(_ctx.$slots, "detail")])) : createCommentVNode("", true)], 2)], 32);
1391
+ ], 2), __props.showDetail ? (openBlock(), createElementBlock("div", _hoisted_15$5, [renderSlot(_ctx.$slots, "detail")])) : createCommentVNode("", true)], 2)], 32);
1748
1392
  };
1749
1393
  }
1750
1394
  });
1751
1395
  //#endregion
1752
1396
  //#region src/vue/components/CollectionKanbanView.vue?vue&type=script&setup=true&lang.ts
1753
- var _hoisted_1$6 = {
1397
+ var _hoisted_1$9 = {
1754
1398
  class: "h-full overflow-x-auto overflow-y-hidden",
1755
1399
  "data-testid": "collection-kanban"
1756
1400
  };
1757
- var _hoisted_2$6 = { class: "flex gap-3 h-full p-1 min-w-max" };
1758
- var _hoisted_3$6 = ["data-testid"];
1759
- var _hoisted_4$6 = { class: "flex items-center justify-between px-3 py-2 border-b border-slate-200" };
1760
- var _hoisted_5$5 = { class: "flex items-center gap-2 min-w-0" };
1761
- var _hoisted_6$5 = ["title"];
1762
- var _hoisted_7$5 = { class: "text-[11px] text-slate-400 shrink-0" };
1763
- var _hoisted_8$5 = [
1401
+ var _hoisted_2$8 = { class: "flex gap-3 h-full p-1 min-w-max" };
1402
+ var _hoisted_3$8 = ["data-testid"];
1403
+ var _hoisted_4$8 = { class: "flex items-center justify-between px-3 py-2 border-b border-slate-200" };
1404
+ var _hoisted_5$7 = { class: "flex items-center gap-2 min-w-0" };
1405
+ var _hoisted_6$6 = ["title"];
1406
+ var _hoisted_7$6 = { class: "text-[11px] text-slate-400 shrink-0" };
1407
+ var _hoisted_8$6 = [
1764
1408
  "data-testid",
1765
1409
  "aria-label",
1766
1410
  "onClick",
1767
1411
  "onKeydown"
1768
1412
  ];
1769
- var _hoisted_9$5 = { class: "flex items-start gap-2" };
1770
- var _hoisted_10$5 = [
1413
+ var _hoisted_9$6 = { class: "flex items-start gap-2" };
1414
+ var _hoisted_10$6 = [
1771
1415
  "checked",
1772
1416
  "aria-label",
1773
1417
  "data-testid",
1774
1418
  "onChange"
1775
1419
  ];
1776
- var _hoisted_11$5 = { class: "text-sm font-medium text-slate-800 truncate" };
1420
+ var _hoisted_11$6 = { class: "text-sm font-medium text-slate-800 truncate" };
1777
1421
  var UNCATEGORIZED = "";
1778
1422
  //#endregion
1779
1423
  //#region src/vue/components/CollectionKanbanView.vue
@@ -1871,15 +1515,15 @@ var CollectionKanbanView_default = /* @__PURE__ */ defineComponent({
1871
1515
  emit("move", itemId(item), next);
1872
1516
  }
1873
1517
  return (_ctx, _cache) => {
1874
- return openBlock(), createElementBlock("div", _hoisted_1$6, [createElementVNode("div", _hoisted_2$6, [(openBlock(true), createElementBlock(Fragment, null, renderList(columns.value, (column) => {
1518
+ return openBlock(), createElementBlock("div", _hoisted_1$9, [createElementVNode("div", _hoisted_2$8, [(openBlock(true), createElementBlock(Fragment, null, renderList(columns.value, (column) => {
1875
1519
  return openBlock(), createElementBlock("div", {
1876
1520
  key: column.value,
1877
1521
  "data-testid": `collection-kanban-column-${column.value || "uncategorized"}`,
1878
1522
  class: "w-72 shrink-0 flex flex-col bg-slate-100 rounded-lg"
1879
- }, [createElementVNode("div", _hoisted_4$6, [createElementVNode("div", _hoisted_5$5, [createElementVNode("span", { class: normalizeClass(["w-2 h-2 rounded-full shrink-0", unref(resolveEnumColor)(__props.schema, __props.groupField, column.value).dot]) }, null, 2), createElementVNode("span", {
1523
+ }, [createElementVNode("div", _hoisted_4$8, [createElementVNode("div", _hoisted_5$7, [createElementVNode("span", { class: normalizeClass(["w-2 h-2 rounded-full shrink-0", unref(resolveEnumColor)(__props.schema, __props.groupField, column.value).dot]) }, null, 2), createElementVNode("span", {
1880
1524
  class: "font-semibold text-xs text-slate-600 truncate",
1881
1525
  title: column.label
1882
- }, toDisplayString(column.label), 9, _hoisted_6$5)]), createElementVNode("span", _hoisted_7$5, toDisplayString(itemsByColumn(column.value).length), 1)]), createVNode(unref(draggable), {
1526
+ }, toDisplayString(column.label), 9, _hoisted_6$6)]), createElementVNode("span", _hoisted_7$6, toDisplayString(itemsByColumn(column.value).length), 1)]), createVNode(unref(draggable), {
1883
1527
  "model-value": itemsByColumn(column.value),
1884
1528
  "item-key": __props.schema.primaryKey,
1885
1529
  group: "collection-kanban-cards",
@@ -1895,7 +1539,7 @@ var CollectionKanbanView_default = /* @__PURE__ */ defineComponent({
1895
1539
  class: normalizeClass(["bg-white border border-slate-200 rounded shadow-sm p-2 cursor-grab hover:shadow active:cursor-grabbing focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-400", [itemId(element) === __props.selected ? "ring-2 ring-indigo-500 border-indigo-300" : "", notifyAccentClass(element)]]),
1896
1540
  onClick: ($event) => emit("select", itemId(element)),
1897
1541
  onKeydown: [withKeys(withModifiers((e) => !e.repeat && emit("select", itemId(element)), ["prevent", "self"]), ["enter"]), withKeys(withModifiers((e) => !e.repeat && emit("select", itemId(element)), ["prevent", "self"]), ["space"])]
1898
- }, [createElementVNode("div", _hoisted_9$5, [cardToggle.value ? (openBlock(), createElementBlock("input", {
1542
+ }, [createElementVNode("div", _hoisted_9$6, [cardToggle.value ? (openBlock(), createElementBlock("input", {
1899
1543
  key: 0,
1900
1544
  type: "checkbox",
1901
1545
  checked: cardChecked(element),
@@ -1904,24 +1548,105 @@ var CollectionKanbanView_default = /* @__PURE__ */ defineComponent({
1904
1548
  "data-testid": `collection-kanban-toggle-${itemId(element)}`,
1905
1549
  onClick: _cache[0] || (_cache[0] = withModifiers(() => {}, ["stop"])),
1906
1550
  onChange: ($event) => onCardToggle(element)
1907
- }, null, 40, _hoisted_10$5)) : createCommentVNode("", true), createElementVNode("div", _hoisted_11$5, toDisplayString(itemLabel(element)), 1)])], 42, _hoisted_8$5)]),
1551
+ }, null, 40, _hoisted_10$6)) : createCommentVNode("", true), createElementVNode("div", _hoisted_11$6, toDisplayString(itemLabel(element)), 1)])], 42, _hoisted_8$6)]),
1908
1552
  _: 1
1909
1553
  }, 8, [
1910
1554
  "model-value",
1911
1555
  "item-key",
1912
1556
  "onChange"
1913
- ])], 8, _hoisted_3$6);
1557
+ ])], 8, _hoisted_3$8);
1914
1558
  }), 128))])]);
1915
1559
  };
1916
1560
  }
1917
1561
  });
1918
1562
  //#endregion
1563
+ //#region src/vue/components/CollectionEmbedView.vue?vue&type=script&setup=true&lang.ts
1564
+ var _hoisted_1$8 = ["href", "data-testid"];
1565
+ var _hoisted_2$7 = { class: "flex items-center justify-between text-[10px] font-bold text-indigo-600/90 tracking-wider uppercase" };
1566
+ var _hoisted_3$7 = { class: "flex items-center gap-1.5" };
1567
+ var _hoisted_4$7 = { class: "bg-indigo-100/60 text-indigo-700 px-1.5 py-0.5 rounded font-mono font-medium lowercase" };
1568
+ var _hoisted_5$6 = { class: "grid gap-x-4 gap-y-3 grid-cols-2" };
1569
+ var _hoisted_6$5 = { class: "text-[10px] font-semibold text-slate-400 uppercase tracking-wide" };
1570
+ var _hoisted_7$5 = ["data-testid"];
1571
+ var _hoisted_8$5 = {
1572
+ key: 0,
1573
+ class: "material-icons text-emerald-600 text-sm align-middle"
1574
+ };
1575
+ var _hoisted_9$5 = {
1576
+ key: 1,
1577
+ class: "text-slate-300"
1578
+ };
1579
+ var _hoisted_10$5 = {
1580
+ key: 1,
1581
+ class: "whitespace-pre-wrap font-normal text-slate-600"
1582
+ };
1583
+ var _hoisted_11$5 = { key: 2 };
1584
+ var _hoisted_12$5 = ["data-testid"];
1585
+ var _hoisted_13$4 = { class: "flex items-start gap-3" };
1586
+ var _hoisted_14$4 = { class: "flex-1 min-w-0" };
1587
+ var _hoisted_15$4 = { class: "text-xs font-semibold text-red-800 uppercase tracking-wider mb-1" };
1588
+ var _hoisted_16$3 = ["data-testid"];
1589
+ var _hoisted_17$3 = ["href"];
1590
+ //#endregion
1591
+ //#region src/vue/components/CollectionEmbedView.vue
1592
+ var CollectionEmbedView_default = /* @__PURE__ */ defineComponent({
1593
+ __name: "CollectionEmbedView",
1594
+ props: {
1595
+ view: {},
1596
+ fieldKey: {}
1597
+ },
1598
+ setup(__props) {
1599
+ const { t } = useCollectionI18n();
1600
+ const cui = collectionUi();
1601
+ return (_ctx, _cache) => {
1602
+ return __props.view.found ? (openBlock(), createElementBlock("a", {
1603
+ key: 0,
1604
+ href: unref(cui).recordHref?.(__props.view.targetSlug, __props.view.recordId),
1605
+ class: "group block relative rounded-xl border border-slate-200 bg-slate-50/50 p-4 pl-5 space-y-3 hover:bg-indigo-50/20 hover:border-indigo-200 transition-all duration-300 shadow-sm",
1606
+ "data-testid": `collections-embed-${__props.fieldKey}`,
1607
+ onClick: _cache[0] || (_cache[0] = withModifiers(($event) => unref(cui).navigateToRecord(__props.view.targetSlug, __props.view.recordId), ["exact", "prevent"]))
1608
+ }, [
1609
+ _cache[3] || (_cache[3] = createElementVNode("div", { class: "absolute left-0 top-0 bottom-0 w-1 bg-indigo-500 rounded-l-xl transition-all duration-300 group-hover:w-1.5 group-hover:bg-indigo-600" }, null, -1)),
1610
+ createElementVNode("div", _hoisted_2$7, [createElementVNode("div", _hoisted_3$7, [_cache[2] || (_cache[2] = createElementVNode("span", { class: "material-icons text-sm" }, "link", -1)), createElementVNode("span", null, toDisplayString(__props.view.targetSlug), 1)]), createElementVNode("span", _hoisted_4$7, toDisplayString(__props.view.recordId), 1)]),
1611
+ createElementVNode("div", _hoisted_5$6, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.view.rows, (row) => {
1612
+ return openBlock(), createElementBlock("div", {
1613
+ key: row.key,
1614
+ class: "space-y-0.5"
1615
+ }, [createElementVNode("div", _hoisted_6$5, toDisplayString(row.label), 1), createElementVNode("div", {
1616
+ class: "text-xs text-slate-700 font-medium break-words",
1617
+ "data-testid": `collections-embed-${__props.fieldKey}-${row.key}`
1618
+ }, [row.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [row.value === true ? (openBlock(), createElementBlock("span", _hoisted_8$5, "check_circle")) : (openBlock(), createElementBlock("span", _hoisted_9$5, "—"))], 64)) : row.type === "markdown" ? (openBlock(), createElementBlock("p", _hoisted_10$5, toDisplayString(row.display), 1)) : (openBlock(), createElementBlock("span", _hoisted_11$5, toDisplayString(row.display), 1))], 8, _hoisted_7$5)]);
1619
+ }), 128))])
1620
+ ], 8, _hoisted_1$8)) : (openBlock(), createElementBlock("div", {
1621
+ key: 1,
1622
+ class: "relative rounded-xl border border-red-100 bg-red-50/30 p-4 pl-5 shadow-sm",
1623
+ "data-testid": `collections-embed-${__props.fieldKey}`
1624
+ }, [_cache[6] || (_cache[6] = createElementVNode("div", { class: "absolute left-0 top-0 bottom-0 w-1 bg-red-400 rounded-l-xl" }, null, -1)), createElementVNode("div", _hoisted_13$4, [_cache[5] || (_cache[5] = createElementVNode("span", { class: "material-icons text-red-500 text-lg mt-0.5" }, "error_outline", -1)), createElementVNode("div", _hoisted_14$4, [
1625
+ createElementVNode("p", _hoisted_15$4, toDisplayString(unref(t)("collectionsView.embedMissingTitle")), 1),
1626
+ createElementVNode("p", {
1627
+ class: "text-xs text-red-600",
1628
+ "data-testid": `collections-embed-missing-${__props.fieldKey}`
1629
+ }, toDisplayString(unref(t)("collectionsView.embedMissing", {
1630
+ collection: __props.view.targetSlug,
1631
+ id: __props.view.recordId
1632
+ })), 9, _hoisted_16$3),
1633
+ __props.view.targetSlug ? (openBlock(), createElementBlock("a", {
1634
+ key: 0,
1635
+ href: unref(cui).recordHref?.(__props.view.targetSlug),
1636
+ class: "inline-flex items-center gap-0.5 text-xs text-indigo-600 hover:text-indigo-800 font-semibold mt-2 hover:underline",
1637
+ onClick: _cache[1] || (_cache[1] = withModifiers(($event) => unref(cui).navigateToRecord(__props.view.targetSlug), ["exact", "prevent"]))
1638
+ }, [createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.embedCreate")), 1), _cache[4] || (_cache[4] = createElementVNode("span", { class: "material-icons text-xs" }, "arrow_forward", -1))], 8, _hoisted_17$3)) : createCommentVNode("", true)
1639
+ ])])], 8, _hoisted_12$5));
1640
+ };
1641
+ }
1642
+ });
1643
+ //#endregion
1919
1644
  //#region src/vue/components/CollectionRecordPanel.vue?vue&type=script&setup=true&lang.ts
1920
- var _hoisted_1$5 = { class: "flex items-center gap-2 mb-4" };
1921
- var _hoisted_2$5 = { class: "flex-1 min-w-0" };
1922
- var _hoisted_3$5 = { class: "block text-[9px] font-bold text-slate-400 uppercase tracking-wider" };
1923
- var _hoisted_4$5 = ["data-testid"];
1924
- var _hoisted_5$4 = ["disabled"];
1645
+ var _hoisted_1$7 = { class: "flex items-center gap-2 mb-4" };
1646
+ var _hoisted_2$6 = { class: "flex-1 min-w-0" };
1647
+ var _hoisted_3$6 = { class: "block text-[9px] font-bold text-slate-400 uppercase tracking-wider" };
1648
+ var _hoisted_4$6 = ["data-testid"];
1649
+ var _hoisted_5$5 = ["disabled"];
1925
1650
  var _hoisted_6$4 = {
1926
1651
  key: 1,
1927
1652
  class: "flex items-center gap-2"
@@ -2057,49 +1782,59 @@ var _hoisted_52$1 = {
2057
1782
  key: 2,
2058
1783
  class: "text-slate-300"
2059
1784
  };
2060
- var _hoisted_53$1 = {
1785
+ var _hoisted_53$1 = [
1786
+ "href",
1787
+ "data-testid",
1788
+ "onClick"
1789
+ ];
1790
+ var _hoisted_54$1 = {
2061
1791
  key: 3,
2062
1792
  class: "font-semibold text-slate-900 tabular-nums text-sm"
2063
1793
  };
2064
- var _hoisted_54$1 = {
1794
+ var _hoisted_55$1 = {
2065
1795
  key: 4,
2066
1796
  class: "inline-block truncate tabular-nums font-bold text-indigo-900 bg-indigo-50/50 px-2 py-0.5 rounded border border-indigo-100/50"
2067
1797
  };
2068
- var _hoisted_55$1 = {
1798
+ var _hoisted_56$1 = {
2069
1799
  key: 5,
2070
1800
  class: "border border-slate-200/80 rounded-xl overflow-hidden shadow-sm mt-1"
2071
1801
  };
2072
- var _hoisted_56$1 = { class: "w-full text-[11px] text-slate-600 bg-white" };
2073
- var _hoisted_57$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
2074
- var _hoisted_58$1 = { class: "divide-y divide-slate-100" };
2075
- var _hoisted_59$1 = {
1802
+ var _hoisted_57$1 = { class: "w-full text-[11px] text-slate-600 bg-white" };
1803
+ var _hoisted_58$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
1804
+ var _hoisted_59$1 = { class: "divide-y divide-slate-100" };
1805
+ var _hoisted_60$1 = {
2076
1806
  key: 0,
2077
1807
  class: "material-icons text-emerald-600 text-base"
2078
1808
  };
2079
- var _hoisted_60$1 = {
1809
+ var _hoisted_61$1 = {
2080
1810
  key: 1,
2081
1811
  class: "text-slate-300"
2082
1812
  };
2083
- var _hoisted_61$1 = {
1813
+ var _hoisted_62$1 = {
2084
1814
  key: 6,
2085
1815
  class: "text-slate-400 italic"
2086
1816
  };
2087
- var _hoisted_62$1 = {
1817
+ var _hoisted_63$1 = {
2088
1818
  key: 7,
2089
1819
  class: "bg-slate-50 rounded-xl p-4 border border-slate-200/60 text-slate-600 text-xs whitespace-pre-wrap leading-relaxed max-h-[30vh] overflow-y-auto"
2090
1820
  };
2091
- var _hoisted_63$1 = [
1821
+ var _hoisted_64$1 = [
2092
1822
  "src",
2093
1823
  "alt",
2094
1824
  "data-testid"
2095
1825
  ];
2096
- var _hoisted_64$1 = ["href", "data-testid"];
2097
1826
  var _hoisted_65$1 = ["href", "data-testid"];
2098
- var _hoisted_66$1 = {
1827
+ var _hoisted_66$1 = ["href", "data-testid"];
1828
+ var _hoisted_67$1 = [
1829
+ "href",
1830
+ "data-testid",
1831
+ "onClick"
1832
+ ];
1833
+ var _hoisted_68$1 = {
2099
1834
  key: 13,
2100
1835
  class: "text-slate-800 font-semibold"
2101
1836
  };
2102
- var _hoisted_67$1 = {
1837
+ var _hoisted_69$1 = {
2103
1838
  key: 0,
2104
1839
  class: "col-span-full text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl"
2105
1840
  };
@@ -2134,7 +1869,8 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2134
1869
  "runAction"
2135
1870
  ], ["update:editing"]),
2136
1871
  setup(__props, { emit: __emit }) {
2137
- const resolveImageSrc = collectionUi().imageSrc;
1872
+ const cui = collectionUi();
1873
+ const resolveImageSrc = cui.imageSrc;
2138
1874
  const props = __props;
2139
1875
  const editing = useModel(__props, "editing");
2140
1876
  const emit = __emit;
@@ -2214,17 +1950,16 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2214
1950
  if (rows) rows.splice(index, 1);
2215
1951
  }
2216
1952
  return (_ctx, _cache) => {
2217
- const _component_router_link = resolveComponent("router-link");
2218
1953
  return openBlock(), createBlock(resolveDynamicComponent(editing.value ? "form" : "div"), {
2219
1954
  class: "px-6 py-5 max-h-[60vh] overflow-y-auto",
2220
1955
  "data-testid": rootTestid.value,
2221
1956
  onSubmit: _cache[4] || (_cache[4] = withModifiers(($event) => emit("submit"), ["prevent"]))
2222
1957
  }, {
2223
1958
  default: withCtx(() => [
2224
- createElementVNode("div", _hoisted_1$5, [createElementVNode("div", _hoisted_2$5, [createElementVNode("span", _hoisted_3$5, toDisplayString(__props.collection.title), 1), createElementVNode("h2", {
1959
+ createElementVNode("div", _hoisted_1$7, [createElementVNode("div", _hoisted_2$6, [createElementVNode("span", _hoisted_3$6, toDisplayString(__props.collection.title), 1), createElementVNode("h2", {
2225
1960
  class: "text-base font-bold text-slate-800 truncate",
2226
1961
  "data-testid": editing.value ? "collections-edit-title" : "collections-detail-title"
2227
- }, toDisplayString(headerTitle.value), 9, _hoisted_4$5)]), editing.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("button", {
1962
+ }, toDisplayString(headerTitle.value), 9, _hoisted_4$6)]), editing.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("button", {
2228
1963
  type: "button",
2229
1964
  class: "h-8 px-2.5 rounded text-xs font-bold text-slate-500 hover:bg-slate-200/50 transition-colors",
2230
1965
  "data-testid": "collections-editor-cancel",
@@ -2234,7 +1969,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2234
1969
  class: "h-8 px-2.5 rounded bg-indigo-600 text-white font-bold text-xs hover:bg-indigo-700 disabled:opacity-50 transition-all shadow-sm shadow-indigo-600/10",
2235
1970
  disabled: __props.saving,
2236
1971
  "data-testid": "collections-editor-save"
2237
- }, toDisplayString(__props.saving ? unref(t)("common.saving") : unref(t)("common.save")), 9, _hoisted_5$4)], 64)) : (openBlock(), createElementBlock("div", _hoisted_6$4, [
1972
+ }, toDisplayString(__props.saving ? unref(t)("common.saving") : unref(t)("common.save")), 9, _hoisted_5$5)], 64)) : (openBlock(), createElementBlock("div", _hoisted_6$4, [
2238
1973
  (openBlock(true), createElementBlock(Fragment, null, renderList(__props.visibleActions, (action) => {
2239
1974
  return openBlock(), createElementBlock("button", {
2240
1975
  key: action.id,
@@ -2410,23 +2145,18 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2410
2145
  key: 1,
2411
2146
  class: "text-xs font-medium text-slate-700 break-words",
2412
2147
  "data-testid": `collections-detail-value-${key}`
2413
- }, [field.type === "toggle" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [field.field !== void 0 && String(detailRecord.value[field.field] ?? "") === field.onValue ? (openBlock(), createElementBlock("span", _hoisted_48$1, [_cache[11] || (_cache[11] = createElementVNode("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), createTextVNode(" " + toDisplayString(unref(t)("common.yes")), 1)])) : (openBlock(), createElementBlock("span", _hoisted_49$1, toDisplayString(unref(t)("common.no")), 1))], 64)) : field.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [detailRecord.value[key] === true ? (openBlock(), createElementBlock("span", _hoisted_50$1, [_cache[12] || (_cache[12] = createElementVNode("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), createTextVNode(" " + toDisplayString(unref(t)("common.yes")), 1)])) : detailRecord.value[key] === false ? (openBlock(), createElementBlock("span", _hoisted_51$1, toDisplayString(unref(t)("common.no")), 1)) : (openBlock(), createElementBlock("span", _hoisted_52$1, "—"))], 64)) : field.type === "ref" && field.to && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? (openBlock(), createBlock(_component_router_link, {
2148
+ }, [field.type === "toggle" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [field.field !== void 0 && String(detailRecord.value[field.field] ?? "") === field.onValue ? (openBlock(), createElementBlock("span", _hoisted_48$1, [_cache[11] || (_cache[11] = createElementVNode("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), createTextVNode(" " + toDisplayString(unref(t)("common.yes")), 1)])) : (openBlock(), createElementBlock("span", _hoisted_49$1, toDisplayString(unref(t)("common.no")), 1))], 64)) : field.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [detailRecord.value[key] === true ? (openBlock(), createElementBlock("span", _hoisted_50$1, [_cache[12] || (_cache[12] = createElementVNode("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), createTextVNode(" " + toDisplayString(unref(t)("common.yes")), 1)])) : detailRecord.value[key] === false ? (openBlock(), createElementBlock("span", _hoisted_51$1, toDisplayString(unref(t)("common.no")), 1)) : (openBlock(), createElementBlock("span", _hoisted_52$1, "—"))], 64)) : field.type === "ref" && field.to && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? (openBlock(), createElementBlock("a", {
2414
2149
  key: 2,
2415
- to: {
2416
- path: `/collections/${field.to}`,
2417
- query: { selected: String(detailRecord.value[key]) }
2418
- },
2150
+ href: unref(cui).recordHref?.(field.to, String(detailRecord.value[key])),
2419
2151
  class: "text-indigo-600 hover:text-indigo-800 font-bold hover:underline",
2420
- "data-testid": `collections-detail-ref-${key}`
2421
- }, {
2422
- default: withCtx(() => [createTextVNode(toDisplayString(__props.render.refDisplay(field.to, String(detailRecord.value[key]))), 1)]),
2423
- _: 2
2424
- }, 1032, ["to", "data-testid"])) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_53$1, toDisplayString(__props.render.formatMoney(detailRecord.value[key], __props.render.resolveCurrency(field, detailRecord.value), __props.locale)), 1)) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_54$1, toDisplayString(__props.render.derivedDisplay(field, __props.render.evaluateDerivedAgainstItem(field, String(key), detailRecord.value), detailRecord.value)), 1)) : field.type === "table" && field.of && __props.render.hasTableRows(detailRecord.value[key]) ? (openBlock(), createElementBlock("div", _hoisted_55$1, [createElementVNode("table", _hoisted_56$1, [createElementVNode("thead", _hoisted_57$1, [createElementVNode("tr", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(field.of, (subField, subKey) => {
2152
+ "data-testid": `collections-detail-ref-${key}`,
2153
+ onClick: withModifiers(($event) => unref(cui).navigateToRecord(field.to, String(detailRecord.value[key])), ["exact", "prevent"])
2154
+ }, toDisplayString(__props.render.refDisplay(field.to, String(detailRecord.value[key]))), 9, _hoisted_53$1)) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_54$1, toDisplayString(__props.render.formatMoney(detailRecord.value[key], __props.render.resolveCurrency(field, detailRecord.value), __props.locale)), 1)) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_55$1, toDisplayString(__props.render.derivedDisplay(field, __props.render.evaluateDerivedAgainstItem(field, String(key), detailRecord.value), detailRecord.value)), 1)) : field.type === "table" && field.of && __props.render.hasTableRows(detailRecord.value[key]) ? (openBlock(), createElementBlock("div", _hoisted_56$1, [createElementVNode("table", _hoisted_57$1, [createElementVNode("thead", _hoisted_58$1, [createElementVNode("tr", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(field.of, (subField, subKey) => {
2425
2155
  return openBlock(), createElementBlock("th", {
2426
2156
  key: subKey,
2427
2157
  class: "text-left px-4 py-2 font-bold"
2428
2158
  }, toDisplayString(subField.label), 1);
2429
- }), 128))])]), createElementVNode("tbody", _hoisted_58$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.tableRows(detailRecord.value[key]), (row, rowIdx) => {
2159
+ }), 128))])]), createElementVNode("tbody", _hoisted_59$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.tableRows(detailRecord.value[key]), (row, rowIdx) => {
2430
2160
  return openBlock(), createElementBlock("tr", {
2431
2161
  key: rowIdx,
2432
2162
  class: "hover:bg-slate-50/50"
@@ -2434,12 +2164,12 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2434
2164
  return openBlock(), createElementBlock("td", {
2435
2165
  key: subKey,
2436
2166
  class: "px-4 py-2 align-middle font-medium"
2437
- }, [subField.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [row[subKey] === true ? (openBlock(), createElementBlock("span", _hoisted_59$1, "check_circle")) : (openBlock(), createElementBlock("span", _hoisted_60$1, "—"))], 64)) : (openBlock(), createElementBlock("span", {
2167
+ }, [subField.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [row[subKey] === true ? (openBlock(), createElementBlock("span", _hoisted_60$1, "check_circle")) : (openBlock(), createElementBlock("span", _hoisted_61$1, "—"))], 64)) : (openBlock(), createElementBlock("span", {
2438
2168
  key: 1,
2439
2169
  class: normalizeClass([subField.type === "money" ? "font-bold text-slate-800 tabular-nums" : ""])
2440
2170
  }, toDisplayString(__props.render.formatSubCell(subField, row[subKey], detailRecord.value)), 3))]);
2441
2171
  }), 128))]);
2442
- }), 128))])])])) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_61$1, toDisplayString(unref(t)("collectionsView.noRows")), 1)) : field.type === "markdown" ? (openBlock(), createElementBlock("div", _hoisted_62$1, toDisplayString(__props.render.detailText(detailRecord.value[key])), 1)) : field.type === "embed" && embedViews.value[key] ? (openBlock(), createBlock(CollectionEmbedView_default, {
2172
+ }), 128))])])])) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_62$1, toDisplayString(unref(t)("collectionsView.noRows")), 1)) : field.type === "markdown" ? (openBlock(), createElementBlock("div", _hoisted_63$1, toDisplayString(__props.render.detailText(detailRecord.value[key])), 1)) : field.type === "embed" && embedViews.value[key] ? (openBlock(), createBlock(CollectionEmbedView_default, {
2443
2173
  key: 8,
2444
2174
  view: embedViews.value[key],
2445
2175
  "field-key": String(key)
@@ -2449,30 +2179,28 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2449
2179
  alt: field.label,
2450
2180
  class: "max-h-64 max-w-full object-contain rounded-lg border border-slate-200 bg-slate-50",
2451
2181
  "data-testid": `collections-detail-image-${key}`
2452
- }, null, 8, _hoisted_63$1)) : field.type !== "file" && __props.render.isExternalUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2182
+ }, null, 8, _hoisted_64$1)) : field.type !== "file" && __props.render.isExternalUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2453
2183
  key: 10,
2454
2184
  href: String(detailRecord.value[key]),
2455
2185
  target: "_blank",
2456
2186
  rel: "noopener noreferrer",
2457
2187
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
2458
2188
  "data-testid": `collections-detail-url-${key}`
2459
- }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_64$1)) : field.type === "file" && __props.render.artifactUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2189
+ }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_65$1)) : field.type === "file" && __props.render.artifactUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2460
2190
  key: 11,
2461
2191
  href: __props.render.artifactUrl(detailRecord.value[key]) ?? void 0,
2462
2192
  target: "_blank",
2463
2193
  rel: "noopener noreferrer",
2464
2194
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
2465
2195
  "data-testid": `collections-detail-file-${key}`
2466
- }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_65$1)) : field.type === "file" && __props.render.fileRoutePath(detailRecord.value[key]) ? (openBlock(), createBlock(_component_router_link, {
2196
+ }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_66$1)) : field.type === "file" && __props.render.fileRoutePath(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2467
2197
  key: 12,
2468
- to: __props.render.fileRoutePath(detailRecord.value[key]) ?? "",
2198
+ href: __props.render.fileRoutePath(detailRecord.value[key]) ?? void 0,
2469
2199
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
2470
- "data-testid": `collections-detail-file-${key}`
2471
- }, {
2472
- default: withCtx(() => [createTextVNode(toDisplayString(String(detailRecord.value[key])), 1)]),
2473
- _: 2
2474
- }, 1032, ["to", "data-testid"])) : (openBlock(), createElementBlock("span", _hoisted_66$1, toDisplayString(__props.render.formatCell(detailRecord.value[key], field.type)), 1))], 8, _hoisted_47$1))], 2)) : createCommentVNode("", true)], 64);
2475
- }), 128)), editing.value && __props.saveError ? (openBlock(), createElementBlock("p", _hoisted_67$1, toDisplayString(__props.saveError), 1)) : createCommentVNode("", true)])
2200
+ "data-testid": `collections-detail-file-${key}`,
2201
+ onClick: withModifiers(($event) => unref(cui).navigate?.(__props.render.fileRoutePath(detailRecord.value[key]) ?? ""), ["exact", "prevent"])
2202
+ }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_67$1)) : (openBlock(), createElementBlock("span", _hoisted_68$1, toDisplayString(__props.render.formatCell(detailRecord.value[key], field.type)), 1))], 8, _hoisted_47$1))], 2)) : createCommentVNode("", true)], 64);
2203
+ }), 128)), editing.value && __props.saveError ? (openBlock(), createElementBlock("p", _hoisted_69$1, toDisplayString(__props.saveError), 1)) : createCommentVNode("", true)])
2476
2204
  ]),
2477
2205
  _: 1
2478
2206
  }, 40, ["data-testid"]);
@@ -2481,14 +2209,14 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2481
2209
  });
2482
2210
  //#endregion
2483
2211
  //#region src/vue/components/CollectionViewConfigModal.vue?vue&type=script&setup=true&lang.ts
2484
- var _hoisted_1$4 = {
2212
+ var _hoisted_1$6 = {
2485
2213
  "data-testid": "collection-config-modal",
2486
2214
  class: "flex flex-col overflow-hidden"
2487
2215
  };
2488
- var _hoisted_2$4 = { class: "flex items-center justify-between gap-2 border-b border-slate-100 px-5 py-3" };
2489
- var _hoisted_3$4 = { class: "text-sm font-bold text-slate-700" };
2490
- var _hoisted_4$4 = ["title", "aria-label"];
2491
- var _hoisted_5$3 = { class: "overflow-y-auto px-5 py-4" };
2216
+ var _hoisted_2$5 = { class: "flex items-center justify-between gap-2 border-b border-slate-100 px-5 py-3" };
2217
+ var _hoisted_3$5 = { class: "text-sm font-bold text-slate-700" };
2218
+ var _hoisted_4$5 = ["title", "aria-label"];
2219
+ var _hoisted_5$4 = { class: "overflow-y-auto px-5 py-4" };
2492
2220
  var _hoisted_6$3 = { class: "mb-2 text-[10px] font-bold uppercase tracking-wider text-slate-400" };
2493
2221
  var _hoisted_7$3 = {
2494
2222
  key: 0,
@@ -2553,14 +2281,14 @@ var CollectionViewConfigModal_default = /* @__PURE__ */ defineComponent({
2553
2281
  }
2554
2282
  return (_ctx, _cache) => {
2555
2283
  return openBlock(), createBlock(CollectionRecordModal_default, { onClose: _cache[1] || (_cache[1] = ($event) => emit("close")) }, {
2556
- default: withCtx(() => [createElementVNode("div", _hoisted_1$4, [createElementVNode("header", _hoisted_2$4, [createElementVNode("h2", _hoisted_3$4, toDisplayString(unref(t)("collectionsView.config.title", { title: __props.title })), 1), createElementVNode("button", {
2284
+ default: withCtx(() => [createElementVNode("div", _hoisted_1$6, [createElementVNode("header", _hoisted_2$5, [createElementVNode("h2", _hoisted_3$5, toDisplayString(unref(t)("collectionsView.config.title", { title: __props.title })), 1), createElementVNode("button", {
2557
2285
  type: "button",
2558
2286
  class: "h-8 w-8 flex items-center justify-center rounded text-slate-400 hover:bg-slate-50 hover:text-slate-600",
2559
2287
  title: unref(t)("common.close"),
2560
2288
  "aria-label": unref(t)("common.close"),
2561
2289
  "data-testid": "collection-config-close",
2562
2290
  onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
2563
- }, [..._cache[2] || (_cache[2] = [createElementVNode("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_4$4)]), createElementVNode("div", _hoisted_5$3, [
2291
+ }, [..._cache[2] || (_cache[2] = [createElementVNode("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_4$5)]), createElementVNode("div", _hoisted_5$4, [
2564
2292
  createElementVNode("h3", _hoisted_6$3, toDisplayString(unref(t)("collectionsView.config.viewsHeading")), 1),
2565
2293
  error.value ? (openBlock(), createElementBlock("p", _hoisted_7$3, toDisplayString(error.value), 1)) : createCommentVNode("", true),
2566
2294
  __props.views.length > 0 ? (openBlock(), createElementBlock("ul", _hoisted_8$3, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.views, (view) => {
@@ -2589,19 +2317,19 @@ var CollectionViewConfigModal_default = /* @__PURE__ */ defineComponent({
2589
2317
  });
2590
2318
  //#endregion
2591
2319
  //#region src/vue/components/CollectionCustomView.vue?vue&type=script&setup=true&lang.ts
2592
- var _hoisted_1$3 = { class: "custom-view-container" };
2593
- var _hoisted_2$3 = {
2320
+ var _hoisted_1$5 = { class: "custom-view-container" };
2321
+ var _hoisted_2$4 = {
2594
2322
  key: 0,
2595
2323
  class: "custom-view-message",
2596
2324
  role: "alert",
2597
2325
  "data-testid": "collection-custom-view-error"
2598
2326
  };
2599
- var _hoisted_3$3 = {
2327
+ var _hoisted_3$4 = {
2600
2328
  key: 1,
2601
2329
  class: "custom-view-message",
2602
2330
  "data-testid": "collection-custom-view-loading"
2603
2331
  };
2604
- var _hoisted_4$3 = ["title", "srcdoc"];
2332
+ var _hoisted_4$4 = ["title", "srcdoc"];
2605
2333
  var REMINT_LEAD_MS = 6e4;
2606
2334
  var MIN_REMINT_DELAY_MS = 1e4;
2607
2335
  var CollectionCustomView_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
@@ -2657,46 +2385,365 @@ var CollectionCustomView_vue_vue_type_script_setup_true_lang_default = /* @__PUR
2657
2385
  dataUrl: mint.data.dataUrl,
2658
2386
  origin: window.location.origin
2659
2387
  });
2660
- } catch (err) {
2661
- if (!stale()) error.value = errorMessage(err);
2662
- } finally {
2663
- if (!stale()) loading.value = false;
2388
+ } catch (err) {
2389
+ if (!stale()) error.value = errorMessage(err);
2390
+ } finally {
2391
+ if (!stale()) loading.value = false;
2392
+ }
2393
+ }
2394
+ watch([() => props.slug, () => props.view.id], () => void load(), { immediate: true });
2395
+ onBeforeUnmount(clearRefresh);
2396
+ return (_ctx, _cache) => {
2397
+ return openBlock(), createElementBlock("div", _hoisted_1$5, [error.value ? (openBlock(), createElementBlock("div", _hoisted_2$4, toDisplayString(unref(t)("collectionsView.customViewError", { error: error.value })), 1)) : loading.value ? (openBlock(), createElementBlock("div", _hoisted_3$4, toDisplayString(unref(t)("collectionsView.customViewLoading")), 1)) : srcdoc.value ? (openBlock(), createElementBlock("iframe", {
2398
+ key: __props.view.id,
2399
+ "data-testid": "collection-custom-view-iframe",
2400
+ title: __props.view.label,
2401
+ srcdoc: srcdoc.value,
2402
+ sandbox: "allow-scripts allow-popups allow-popups-to-escape-sandbox",
2403
+ class: "w-full h-full border-0"
2404
+ }, null, 8, _hoisted_4$4)) : createCommentVNode("", true)]);
2405
+ };
2406
+ }
2407
+ });
2408
+ //#endregion
2409
+ //#region \0plugin-vue:export-helper
2410
+ var _plugin_vue_export_helper_default = (sfc, props) => {
2411
+ const target = sfc.__vccOpts || sfc;
2412
+ for (const [key, val] of props) target[key] = val;
2413
+ return target;
2414
+ };
2415
+ //#endregion
2416
+ //#region src/vue/components/CollectionCustomView.vue
2417
+ var CollectionCustomView_default = /* @__PURE__ */ _plugin_vue_export_helper_default(CollectionCustomView_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-3ab71997"]]);
2418
+ //#endregion
2419
+ //#region src/vue/useCollectionRendering.ts
2420
+ function useCollectionRendering(collection, locale) {
2421
+ const refCache = ref({});
2422
+ const refRecordCache = ref({});
2423
+ const embedCache = ref({});
2424
+ function resetLinkedCaches() {
2425
+ refCache.value = {};
2426
+ refRecordCache.value = {};
2427
+ embedCache.value = {};
2428
+ }
2429
+ function uniqueRefTargets(schema) {
2430
+ const targets = /* @__PURE__ */ new Set();
2431
+ const walk = (fields) => {
2432
+ for (const field of Object.values(fields)) {
2433
+ if (field.type === "ref" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
2434
+ if (field.type === "table" && field.of) walk(field.of);
2435
+ }
2436
+ };
2437
+ walk(schema.fields);
2438
+ return [...targets];
2439
+ }
2440
+ function uniqueEmbedTargets(schema) {
2441
+ const targets = /* @__PURE__ */ new Set();
2442
+ for (const field of Object.values(schema.fields)) if (field.type === "embed" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
2443
+ return [...targets];
2444
+ }
2445
+ function buildRefDisplayMap(detail) {
2446
+ const { fields, primaryKey } = detail.collection.schema;
2447
+ const displayField = "name" in fields ? "name" : "title" in fields ? "title" : primaryKey;
2448
+ const map = {};
2449
+ for (const item of detail.items) {
2450
+ const slugRaw = item[primaryKey];
2451
+ if (typeof slugRaw !== "string" || slugRaw.length === 0) continue;
2452
+ const displayRaw = item[displayField];
2453
+ map[slugRaw] = typeof displayRaw === "string" && displayRaw.length > 0 ? displayRaw : slugRaw;
2454
+ }
2455
+ return map;
2456
+ }
2457
+ function buildRefRecordMap(detail) {
2458
+ const { schema } = detail.collection;
2459
+ const map = {};
2460
+ for (const item of detail.items) {
2461
+ const slugRaw = item[schema.primaryKey];
2462
+ if (typeof slugRaw === "string" && slugRaw.length > 0) map[slugRaw] = deriveAll(schema, item, {});
2463
+ }
2464
+ return map;
2465
+ }
2466
+ async function loadLinkedCollections(schema, expectedSlug) {
2467
+ const refTargets = new Set(uniqueRefTargets(schema));
2468
+ const embedTargets = new Set(uniqueEmbedTargets(schema));
2469
+ const allTargets = [...new Set([...refTargets, ...embedTargets])];
2470
+ if (allTargets.length === 0) return;
2471
+ const binding = collectionUi();
2472
+ const results = await Promise.all(allTargets.map(async (target) => {
2473
+ try {
2474
+ return {
2475
+ target,
2476
+ result: await binding.fetchCollectionDetail(target)
2477
+ };
2478
+ } catch {
2479
+ return {
2480
+ target,
2481
+ result: { ok: false }
2482
+ };
2483
+ }
2484
+ }));
2485
+ if (collection.value?.slug !== expectedSlug) return;
2486
+ const nextRef = {};
2487
+ const nextRefRecords = {};
2488
+ const nextEmbed = {};
2489
+ for (const { target, result } of results) {
2490
+ if (!result.ok) continue;
2491
+ if (refTargets.has(target)) {
2492
+ nextRef[target] = buildRefDisplayMap(result.data);
2493
+ nextRefRecords[target] = buildRefRecordMap(result.data);
2494
+ }
2495
+ if (embedTargets.has(target)) nextEmbed[target] = {
2496
+ schema: result.data.collection.schema,
2497
+ items: result.data.items
2498
+ };
2499
+ }
2500
+ refCache.value = nextRef;
2501
+ refRecordCache.value = nextRefRecords;
2502
+ embedCache.value = nextEmbed;
2503
+ }
2504
+ function refDisplay(targetSlug, itemSlug) {
2505
+ const map = refCache.value[targetSlug];
2506
+ return map && map[itemSlug] || itemSlug;
2507
+ }
2508
+ function refOptions(targetSlug) {
2509
+ const map = refCache.value[targetSlug];
2510
+ if (!map) return [];
2511
+ return Object.entries(map).map(([slug, display]) => ({
2512
+ slug,
2513
+ display
2514
+ })).sort((left, right) => left.display.localeCompare(right.display));
2515
+ }
2516
+ function resolveEmbed(field) {
2517
+ if (field.type !== "embed" || !field.to || !field.id) return {
2518
+ schema: null,
2519
+ item: null
2520
+ };
2521
+ const data = embedCache.value[field.to];
2522
+ if (!data) return {
2523
+ schema: null,
2524
+ item: null
2525
+ };
2526
+ const item = data.items.find((entry) => String(entry[data.schema.primaryKey] ?? "") === field.id) ?? null;
2527
+ return {
2528
+ schema: data.schema,
2529
+ item
2530
+ };
2531
+ }
2532
+ function embedValue(field, value, record) {
2533
+ if (field.type === "money") return formatMoney(value, resolveCurrency(field, record), locale.value);
2534
+ return detailText(value);
2535
+ }
2536
+ const embedViews = computed(() => {
2537
+ const out = {};
2538
+ if (!collection.value) return out;
2539
+ for (const [key, field] of Object.entries(collection.value.schema.fields)) {
2540
+ if (field.type !== "embed") continue;
2541
+ const { schema, item } = resolveEmbed(field);
2542
+ const rows = [];
2543
+ if (schema && item) for (const [subKey, subField] of Object.entries(schema.fields)) {
2544
+ const value = item[subKey];
2545
+ if (value === void 0 || value === null || value === "") continue;
2546
+ rows.push({
2547
+ key: subKey,
2548
+ label: subField.label,
2549
+ type: subField.type,
2550
+ value,
2551
+ display: embedValue(subField, value, item)
2552
+ });
2664
2553
  }
2554
+ out[key] = {
2555
+ found: Boolean(item),
2556
+ rows,
2557
+ targetSlug: field.to ?? "",
2558
+ recordId: field.id ?? ""
2559
+ };
2665
2560
  }
2666
- watch([() => props.slug, () => props.view.id], () => void load(), { immediate: true });
2667
- onBeforeUnmount(clearRefresh);
2668
- return (_ctx, _cache) => {
2669
- return openBlock(), createElementBlock("div", _hoisted_1$3, [error.value ? (openBlock(), createElementBlock("div", _hoisted_2$3, toDisplayString(unref(t)("collectionsView.customViewError", { error: error.value })), 1)) : loading.value ? (openBlock(), createElementBlock("div", _hoisted_3$3, toDisplayString(unref(t)("collectionsView.customViewLoading")), 1)) : srcdoc.value ? (openBlock(), createElementBlock("iframe", {
2670
- key: __props.view.id,
2671
- "data-testid": "collection-custom-view-iframe",
2672
- title: __props.view.label,
2673
- srcdoc: srcdoc.value,
2674
- sandbox: "allow-scripts allow-popups allow-popups-to-escape-sandbox",
2675
- class: "w-full h-full border-0"
2676
- }, null, 8, _hoisted_4$3)) : createCommentVNode("", true)]);
2677
- };
2561
+ return out;
2562
+ });
2563
+ function resolveCurrency(field, record) {
2564
+ if (field.currencyField && record) {
2565
+ const code = record[field.currencyField];
2566
+ if (typeof code === "string" && code.trim().length > 0) return code;
2567
+ }
2568
+ return field.currency;
2678
2569
  }
2679
- });
2680
- //#endregion
2681
- //#region \0plugin-vue:export-helper
2682
- var _plugin_vue_export_helper_default = (sfc, props) => {
2683
- const target = sfc.__vccOpts || sfc;
2684
- for (const [key, val] of props) target[key] = val;
2685
- return target;
2686
- };
2570
+ function currencySymbol(currency) {
2571
+ const code = currency && currency.length > 0 ? currency : "USD";
2572
+ try {
2573
+ return new Intl.NumberFormat(locale.value, {
2574
+ style: "currency",
2575
+ currency: code
2576
+ }).formatToParts(0).find((entry) => entry.type === "currency")?.value ?? code;
2577
+ } catch {
2578
+ return code;
2579
+ }
2580
+ }
2581
+ function formatMoney(value, currency, displayLocale) {
2582
+ if (value === void 0 || value === "") return "—";
2583
+ const amount = typeof value === "number" ? value : Number(value);
2584
+ if (!Number.isFinite(amount)) return String(value);
2585
+ const currencyCode = currency && currency.length > 0 ? currency : "USD";
2586
+ try {
2587
+ return new Intl.NumberFormat(displayLocale, {
2588
+ style: "currency",
2589
+ currency: currencyCode
2590
+ }).format(amount);
2591
+ } catch {
2592
+ return String(amount);
2593
+ }
2594
+ }
2595
+ function formatCell(value, type) {
2596
+ if (value === void 0 || value === null || value === "") return "—";
2597
+ if (type === "markdown" && typeof value === "string") return value.length > 80 ? `${value.slice(0, 80)}…` : value;
2598
+ if (typeof value === "string" || typeof value === "number") return String(value);
2599
+ return JSON.stringify(value);
2600
+ }
2601
+ function isExternalUrl(value) {
2602
+ return typeof value === "string" && /^https?:\/\//i.test(value);
2603
+ }
2604
+ function artifactUrl(value) {
2605
+ return collectionUi().fileAssetUrl(value);
2606
+ }
2607
+ function fileRoutePath(value) {
2608
+ return collectionUi().fileRoutePath(value);
2609
+ }
2610
+ function detailText(value) {
2611
+ if (value === void 0 || value === null || value === "") return "—";
2612
+ return String(value);
2613
+ }
2614
+ function tableRows(value) {
2615
+ if (!Array.isArray(value)) return [];
2616
+ return value.filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row));
2617
+ }
2618
+ function hasTableRows(value) {
2619
+ return tableRows(value).length > 0;
2620
+ }
2621
+ function formatSubCell(subField, value, record) {
2622
+ if (subField.type === "money") return formatMoney(value, resolveCurrency(subField, record), locale.value);
2623
+ if (subField.type === "ref" && subField.to && typeof value === "string" && value.length > 0) return refDisplay(subField.to, value);
2624
+ return formatCell(value, subField.type);
2625
+ }
2626
+ function inputTypeFor(type) {
2627
+ if (type === "email") return "email";
2628
+ if (type === "number") return "number";
2629
+ if (type === "money") return "number";
2630
+ if (type === "date") return "date";
2631
+ if (type === "datetime") return "datetime-local";
2632
+ return "text";
2633
+ }
2634
+ function evaluateDerivedAgainstItem(field, fieldKey, item) {
2635
+ if (!field.formula || !collection.value) return null;
2636
+ const result = deriveAll(collection.value.schema, item, refRecordCache.value)[fieldKey];
2637
+ return typeof result === "number" && Number.isFinite(result) ? result : null;
2638
+ }
2639
+ function derivedDisplay(field, computedValue, record) {
2640
+ if (computedValue === null || computedValue === void 0) return "—";
2641
+ if (field.display === "money") return formatMoney(computedValue, resolveCurrency(field, record), locale.value);
2642
+ return formatCell(computedValue, field.display ?? "number");
2643
+ }
2644
+ return {
2645
+ refCache,
2646
+ refRecordCache,
2647
+ embedCache,
2648
+ resetLinkedCaches,
2649
+ loadLinkedCollections,
2650
+ refDisplay,
2651
+ refOptions,
2652
+ embedViews,
2653
+ resolveCurrency,
2654
+ currencySymbol,
2655
+ formatMoney,
2656
+ formatCell,
2657
+ detailText,
2658
+ isExternalUrl,
2659
+ artifactUrl,
2660
+ fileRoutePath,
2661
+ tableRows,
2662
+ hasTableRows,
2663
+ formatSubCell,
2664
+ inputTypeFor,
2665
+ deriveAll,
2666
+ evaluateDerivedAgainstItem,
2667
+ derivedDisplay
2668
+ };
2669
+ }
2687
2670
  //#endregion
2688
- //#region src/vue/components/CollectionCustomView.vue
2689
- var CollectionCustomView_default = /* @__PURE__ */ _plugin_vue_export_helper_default(CollectionCustomView_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-3ab71997"]]);
2671
+ //#region src/vue/collectionViewMode.ts
2672
+ var STORAGE_KEY = "collection_view_modes";
2673
+ var SORT_STORAGE_KEY = "collection_sorts";
2674
+ var BUILT_IN_MODES = [
2675
+ "table",
2676
+ "calendar",
2677
+ "kanban"
2678
+ ];
2679
+ /** A persisted mode is valid if it's a known built-in OR any `custom:<id>`
2680
+ * key (the id is validated against the live schema at render time, so an
2681
+ * unknown custom id simply collapses to the table there). Takes `unknown`
2682
+ * and type-guards `string` first: a corrupted localStorage entry could hold a
2683
+ * number/object, and calling `.startsWith` on that would throw. */
2684
+ function isValidViewMode(value) {
2685
+ return typeof value === "string" && (BUILT_IN_MODES.includes(value) || value.startsWith("custom:"));
2686
+ }
2687
+ function readAll() {
2688
+ try {
2689
+ const raw = localStorage.getItem(STORAGE_KEY);
2690
+ if (!raw) return {};
2691
+ const parsed = JSON.parse(raw);
2692
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
2693
+ } catch {
2694
+ return {};
2695
+ }
2696
+ }
2697
+ function readCollectionViewMode(slug) {
2698
+ const stored = readAll()[slug];
2699
+ return isValidViewMode(stored) ? stored : null;
2700
+ }
2701
+ function writeCollectionViewMode(slug, view) {
2702
+ try {
2703
+ const all = readAll();
2704
+ all[slug] = view;
2705
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(all));
2706
+ } catch {}
2707
+ }
2708
+ function isSortState(value) {
2709
+ if (!value || typeof value !== "object") return false;
2710
+ const rec = value;
2711
+ return typeof rec.field === "string" && (rec.direction === "asc" || rec.direction === "desc");
2712
+ }
2713
+ function readAllSorts() {
2714
+ try {
2715
+ const raw = localStorage.getItem(SORT_STORAGE_KEY);
2716
+ if (!raw) return {};
2717
+ const parsed = JSON.parse(raw);
2718
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
2719
+ const out = {};
2720
+ for (const [slug, value] of Object.entries(parsed)) if (isSortState(value)) out[slug] = value;
2721
+ return out;
2722
+ } catch {
2723
+ return {};
2724
+ }
2725
+ }
2726
+ function readCollectionSort(slug) {
2727
+ return readAllSorts()[slug] ?? null;
2728
+ }
2729
+ /** Persist (or, when `sort` is null, clear) the slug's active column sort. */
2730
+ function writeCollectionSort(slug, sort) {
2731
+ try {
2732
+ const all = Object.fromEntries(Object.entries(readAllSorts()).filter(([key]) => key !== slug));
2733
+ if (sort) all[slug] = sort;
2734
+ localStorage.setItem(SORT_STORAGE_KEY, JSON.stringify(all));
2735
+ } catch {}
2736
+ }
2690
2737
  //#endregion
2691
2738
  //#region src/vue/components/CollectionView.vue?vue&type=script&setup=true&lang.ts
2692
- var _hoisted_1$2 = { class: "h-full flex flex-col bg-slate-50/30" };
2693
- var _hoisted_2$2 = { class: "flex items-center gap-3 px-6 py-2 border-b border-slate-200 bg-white" };
2694
- var _hoisted_3$2 = ["title", "aria-label"];
2695
- var _hoisted_4$2 = {
2739
+ var _hoisted_1$4 = { class: "h-full flex flex-col bg-slate-50/30" };
2740
+ var _hoisted_2$3 = { class: "flex items-center gap-3 px-6 py-2 border-b border-slate-200 bg-white" };
2741
+ var _hoisted_3$3 = ["title", "aria-label"];
2742
+ var _hoisted_4$3 = {
2696
2743
  key: 1,
2697
2744
  class: "h-9 w-9 flex items-center justify-center rounded-xl bg-indigo-50 text-indigo-600 border border-indigo-100"
2698
2745
  };
2699
- var _hoisted_5$2 = { class: "material-symbols-outlined text-xl" };
2746
+ var _hoisted_5$3 = { class: "material-symbols-outlined text-xl" };
2700
2747
  var _hoisted_6$2 = { class: "flex-1 min-w-0" };
2701
2748
  var _hoisted_7$2 = { class: "text-base font-bold text-slate-800 truncate" };
2702
2749
  var _hoisted_8$2 = {
@@ -2843,48 +2890,58 @@ var _hoisted_65 = {
2843
2890
  class: "block truncate"
2844
2891
  };
2845
2892
  var _hoisted_66 = [
2893
+ "href",
2894
+ "data-testid",
2895
+ "onClick"
2896
+ ];
2897
+ var _hoisted_67 = [
2846
2898
  "value",
2847
2899
  "disabled",
2848
2900
  "data-testid",
2849
2901
  "aria-label",
2850
2902
  "onChange"
2851
2903
  ];
2852
- var _hoisted_67 = {
2904
+ var _hoisted_68 = {
2853
2905
  key: 0,
2854
2906
  value: ""
2855
2907
  };
2856
- var _hoisted_68 = ["value"];
2857
- var _hoisted_69 = {
2908
+ var _hoisted_69 = ["value"];
2909
+ var _hoisted_70 = {
2858
2910
  key: 4,
2859
2911
  class: "block truncate tabular-nums font-semibold text-slate-900"
2860
2912
  };
2861
- var _hoisted_70 = {
2913
+ var _hoisted_71 = {
2862
2914
  key: 5,
2863
2915
  class: "inline-flex items-center gap-1 px-2 py-0.5 rounded-lg text-[10px] font-bold bg-slate-100 text-slate-600 border border-slate-200/40"
2864
2916
  };
2865
- var _hoisted_71 = {
2917
+ var _hoisted_72 = {
2866
2918
  key: 6,
2867
2919
  class: "inline-block truncate tabular-nums font-bold text-indigo-900 bg-indigo-50/50 px-1.5 py-0.5 rounded border border-indigo-100/50"
2868
2920
  };
2869
- var _hoisted_72 = ["href", "data-testid"];
2870
2921
  var _hoisted_73 = ["href", "data-testid"];
2871
- var _hoisted_74 = {
2922
+ var _hoisted_74 = ["href", "data-testid"];
2923
+ var _hoisted_75 = [
2924
+ "href",
2925
+ "data-testid",
2926
+ "onClick"
2927
+ ];
2928
+ var _hoisted_76 = {
2872
2929
  key: 10,
2873
2930
  class: "block truncate text-slate-600"
2874
2931
  };
2875
- var _hoisted_75 = { class: "bg-white rounded-2xl shadow-2xl w-full max-w-xl flex flex-col border border-slate-200 overflow-hidden" };
2876
- var _hoisted_76 = { class: "px-6 py-4 border-b border-slate-100 flex items-center gap-3 bg-slate-50/50" };
2877
- var _hoisted_77 = { class: "flex-1" };
2878
- var _hoisted_78 = {
2932
+ var _hoisted_77 = { class: "bg-white rounded-2xl shadow-2xl w-full max-w-xl flex flex-col border border-slate-200 overflow-hidden" };
2933
+ var _hoisted_78 = { class: "px-6 py-4 border-b border-slate-100 flex items-center gap-3 bg-slate-50/50" };
2934
+ var _hoisted_79 = { class: "flex-1" };
2935
+ var _hoisted_80 = {
2879
2936
  id: "collections-chat-title",
2880
2937
  class: "text-sm font-bold text-slate-800 uppercase tracking-wide"
2881
2938
  };
2882
- var _hoisted_79 = { class: "text-xs text-slate-400 font-semibold" };
2883
- var _hoisted_80 = ["aria-label"];
2884
- var _hoisted_81 = { class: "px-6 py-5" };
2885
- var _hoisted_82 = ["placeholder", "onKeydown"];
2886
- var _hoisted_83 = { class: "px-6 py-3.5 border-t border-slate-100 flex items-center justify-end gap-2 bg-slate-50/50" };
2887
- var _hoisted_84 = ["disabled"];
2939
+ var _hoisted_81 = { class: "text-xs text-slate-400 font-semibold" };
2940
+ var _hoisted_82 = ["aria-label"];
2941
+ var _hoisted_83 = { class: "px-6 py-5" };
2942
+ var _hoisted_84 = ["placeholder", "onKeydown"];
2943
+ var _hoisted_85 = { class: "px-6 py-3.5 border-t border-slate-100 flex items-center justify-end gap-2 bg-slate-50/50" };
2944
+ var _hoisted_86 = ["disabled"];
2888
2945
  //#endregion
2889
2946
  //#region src/vue/components/CollectionView.vue
2890
2947
  var CollectionView_default = /* @__PURE__ */ defineComponent({
@@ -2905,6 +2962,18 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
2905
2962
  const cui = collectionUi();
2906
2963
  const { confirm: openConfirm, unpin, pinToggle, startChat } = cui;
2907
2964
  const appApi = { startNewChat: startChat };
2965
+ function onRefLinkClick(event, targetSlug, recordId) {
2966
+ event.stopPropagation();
2967
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
2968
+ event.preventDefault();
2969
+ cui.navigateToRecord(targetSlug, recordId);
2970
+ }
2971
+ function onFileLinkClick(event, path) {
2972
+ event.stopPropagation();
2973
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
2974
+ event.preventDefault();
2975
+ cui.navigate?.(path);
2976
+ }
2908
2977
  /** Embedded when a `slug` prop is supplied; standalone (route-driven)
2909
2978
  * otherwise. Switches the slug/selected source and the open/close
2910
2979
  * navigation behaviour. */
@@ -3851,9 +3920,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
3851
3920
  openDay.value = viewing.value ? dayOfItem(viewing.value) : null;
3852
3921
  });
3853
3922
  return (_ctx, _cache) => {
3854
- const _component_router_link = resolveComponent("router-link");
3855
- return openBlock(), createElementBlock("div", _hoisted_1$2, [
3856
- createElementVNode("header", _hoisted_2$2, [
3923
+ return openBlock(), createElementBlock("div", _hoisted_1$4, [
3924
+ createElementVNode("header", _hoisted_2$3, [
3857
3925
  !embedded.value ? (openBlock(), createElementBlock("button", {
3858
3926
  key: 0,
3859
3927
  type: "button",
@@ -3862,8 +3930,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
3862
3930
  "aria-label": unref(t)("collectionsView.backToIndex"),
3863
3931
  "data-testid": "collections-back",
3864
3932
  onClick: goBack
3865
- }, [..._cache[25] || (_cache[25] = [createElementVNode("span", { class: "material-icons text-lg" }, "arrow_back", -1)])], 8, _hoisted_3$2)) : createCommentVNode("", true),
3866
- collection.value ? (openBlock(), createElementBlock("div", _hoisted_4$2, [createElementVNode("span", _hoisted_5$2, toDisplayString(collection.value.icon), 1)])) : createCommentVNode("", true),
3933
+ }, [..._cache[23] || (_cache[23] = [createElementVNode("span", { class: "material-icons text-lg" }, "arrow_back", -1)])], 8, _hoisted_3$3)) : createCommentVNode("", true),
3934
+ collection.value ? (openBlock(), createElementBlock("div", _hoisted_4$3, [createElementVNode("span", _hoisted_5$3, toDisplayString(collection.value.icon), 1)])) : createCommentVNode("", true),
3867
3935
  createElementVNode("div", _hoisted_6$2, [createElementVNode("h1", _hoisted_7$2, toDisplayString(collection.value?.title ?? unref(t)("collectionsView.title")), 1), collection.value ? (openBlock(), createElementBlock("span", _hoisted_8$2, toDisplayString(collection.value.slug), 1)) : createCommentVNode("", true)]),
3868
3936
  collection.value && !embedded.value ? (openBlock(), createBlock(resolveDynamicComponent(unref(pinToggle)), {
3869
3937
  key: 2,
@@ -3891,7 +3959,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
3891
3959
  class: "h-8 px-2.5 flex items-center gap-1 rounded border border-indigo-200 bg-white hover:bg-indigo-50 text-indigo-600 font-bold text-xs transition-colors",
3892
3960
  "data-testid": "collections-chat",
3893
3961
  onClick: openChat
3894
- }, [_cache[26] || (_cache[26] = createElementVNode("span", { class: "material-icons text-sm" }, "forum", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.chat")), 1)])) : createCommentVNode("", true),
3962
+ }, [_cache[24] || (_cache[24] = createElementVNode("span", { class: "material-icons text-sm" }, "forum", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.chat")), 1)])) : createCommentVNode("", true),
3895
3963
  (openBlock(true), createElementBlock(Fragment, null, renderList(collectionActions.value, (action) => {
3896
3964
  return openBlock(), createElementBlock("button", {
3897
3965
  key: action.id,
@@ -3908,7 +3976,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
3908
3976
  class: "h-8 px-2.5 flex items-center gap-1 rounded bg-indigo-600 hover:bg-indigo-700 text-white font-bold text-xs transition-colors shadow-sm",
3909
3977
  "data-testid": "collections-add-item",
3910
3978
  onClick: openCreate
3911
- }, [_cache[27] || (_cache[27] = createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.add")), 1)])) : createCommentVNode("", true),
3979
+ }, [_cache[25] || (_cache[25] = createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.add")), 1)])) : createCommentVNode("", true),
3912
3980
  canDeleteCollection.value && !embedded.value ? (openBlock(), createElementBlock("button", {
3913
3981
  key: 6,
3914
3982
  type: "button",
@@ -3917,7 +3985,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
3917
3985
  "aria-label": unref(t)("collectionsView.deleteCollection"),
3918
3986
  "data-testid": "collections-delete",
3919
3987
  onClick: confirmCollectionDelete
3920
- }, [..._cache[28] || (_cache[28] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_13$2)) : createCommentVNode("", true),
3988
+ }, [..._cache[26] || (_cache[26] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_13$2)) : createCommentVNode("", true),
3921
3989
  canDeleteFeed.value && !embedded.value ? (openBlock(), createElementBlock("button", {
3922
3990
  key: 7,
3923
3991
  type: "button",
@@ -3926,10 +3994,10 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
3926
3994
  "aria-label": unref(t)("collectionsView.deleteFeed"),
3927
3995
  "data-testid": "feeds-delete",
3928
3996
  onClick: confirmFeedDelete
3929
- }, [..._cache[29] || (_cache[29] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_14$2)) : createCommentVNode("", true)
3997
+ }, [..._cache[27] || (_cache[27] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_14$2)) : createCommentVNode("", true)
3930
3998
  ]),
3931
3999
  collection.value && (items.value.length > 0 || hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value) ? (openBlock(), createElementBlock("div", _hoisted_15$2, [items.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_16$1, [
3932
- _cache[31] || (_cache[31] = createElementVNode("span", { class: "absolute inset-y-0 left-0 flex items-center pl-3 text-slate-400 pointer-events-none" }, [createElementVNode("span", { class: "material-icons text-lg" }, "search")], -1)),
4000
+ _cache[29] || (_cache[29] = createElementVNode("span", { class: "absolute inset-y-0 left-0 flex items-center pl-3 text-slate-400 pointer-events-none" }, [createElementVNode("span", { class: "material-icons text-lg" }, "search")], -1)),
3933
4001
  withDirectives(createElementVNode("input", {
3934
4002
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchQuery.value = $event),
3935
4003
  type: "text",
@@ -3943,7 +4011,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
3943
4011
  "aria-label": unref(t)("collectionsView.clearSearch"),
3944
4012
  class: "absolute inset-y-0 right-0 flex items-center pr-2.5 text-slate-400 hover:text-slate-600",
3945
4013
  onClick: _cache[1] || (_cache[1] = ($event) => searchQuery.value = "")
3946
- }, [..._cache[30] || (_cache[30] = [createElementVNode("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_18$1)) : createCommentVNode("", true)
4014
+ }, [..._cache[28] || (_cache[28] = [createElementVNode("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_18$1)) : createCommentVNode("", true)
3947
4015
  ])) : createCommentVNode("", true), createElementVNode("div", _hoisted_19$1, [
3948
4016
  hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value ? (openBlock(), createElementBlock("div", {
3949
4017
  key: 0,
@@ -3957,7 +4025,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
3957
4025
  "aria-pressed": activeView.value === "table",
3958
4026
  "data-testid": "collection-view-toggle-table",
3959
4027
  onClick: _cache[2] || (_cache[2] = ($event) => setView("table"))
3960
- }, [_cache[32] || (_cache[32] = createElementVNode("span", { class: "material-icons text-sm" }, "table_rows", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewTable")), 1)], 10, _hoisted_21$1),
4028
+ }, [_cache[30] || (_cache[30] = createElementVNode("span", { class: "material-icons text-sm" }, "table_rows", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewTable")), 1)], 10, _hoisted_21$1),
3961
4029
  hasCalendar.value ? (openBlock(), createElementBlock("button", {
3962
4030
  key: 0,
3963
4031
  type: "button",
@@ -3965,7 +4033,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
3965
4033
  "aria-pressed": activeView.value === "calendar",
3966
4034
  "data-testid": "collection-view-toggle-calendar",
3967
4035
  onClick: _cache[3] || (_cache[3] = ($event) => setView("calendar"))
3968
- }, [_cache[33] || (_cache[33] = createElementVNode("span", { class: "material-icons text-sm" }, "calendar_month", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewCalendar")), 1)], 10, _hoisted_22$1)) : createCommentVNode("", true),
4036
+ }, [_cache[31] || (_cache[31] = createElementVNode("span", { class: "material-icons text-sm" }, "calendar_month", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewCalendar")), 1)], 10, _hoisted_22$1)) : createCommentVNode("", true),
3969
4037
  hasKanban.value ? (openBlock(), createElementBlock("button", {
3970
4038
  key: 1,
3971
4039
  type: "button",
@@ -3973,7 +4041,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
3973
4041
  "aria-pressed": activeView.value === "kanban",
3974
4042
  "data-testid": "collection-view-toggle-kanban",
3975
4043
  onClick: _cache[4] || (_cache[4] = ($event) => setView("kanban"))
3976
- }, [_cache[34] || (_cache[34] = createElementVNode("span", { class: "material-icons text-sm" }, "view_kanban", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewKanban")), 1)], 10, _hoisted_23$1)) : createCommentVNode("", true),
4044
+ }, [_cache[32] || (_cache[32] = createElementVNode("span", { class: "material-icons text-sm" }, "view_kanban", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewKanban")), 1)], 10, _hoisted_23$1)) : createCommentVNode("", true),
3977
4045
  (openBlock(true), createElementBlock(Fragment, null, renderList(customViews.value, (cv) => {
3978
4046
  return openBlock(), createElementBlock("button", {
3979
4047
  key: cv.id,
@@ -3992,7 +4060,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
3992
4060
  "aria-label": unref(t)("collectionsView.addView"),
3993
4061
  "data-testid": "collection-view-add",
3994
4062
  onClick: addCustomView
3995
- }, [..._cache[35] || (_cache[35] = [createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)])], 8, _hoisted_26)) : createCommentVNode("", true),
4063
+ }, [..._cache[33] || (_cache[33] = [createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)])], 8, _hoisted_26)) : createCommentVNode("", true),
3996
4064
  canConfigureViews.value ? (openBlock(), createElementBlock("button", {
3997
4065
  key: 3,
3998
4066
  type: "button",
@@ -4001,7 +4069,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4001
4069
  "aria-label": unref(t)("collectionsView.config.open"),
4002
4070
  "data-testid": "collection-config-open",
4003
4071
  onClick: _cache[5] || (_cache[5] = ($event) => configOpen.value = true)
4004
- }, [..._cache[36] || (_cache[36] = [createElementVNode("span", { class: "material-icons text-sm" }, "settings", -1)])], 8, _hoisted_27)) : createCommentVNode("", true)
4072
+ }, [..._cache[34] || (_cache[34] = [createElementVNode("span", { class: "material-icons text-sm" }, "settings", -1)])], 8, _hoisted_27)) : createCommentVNode("", true)
4005
4073
  ], 8, _hoisted_20$1)) : createCommentVNode("", true),
4006
4074
  calendarActive.value && dateFields.value.length > 1 ? (openBlock(), createElementBlock("select", {
4007
4075
  key: 1,
@@ -4035,16 +4103,16 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4035
4103
  })), 1)) : createCommentVNode("", true)
4036
4104
  ])])) : createCommentVNode("", true),
4037
4105
  collection.value && dataIssues.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_33, [
4038
- _cache[38] || (_cache[38] = createElementVNode("span", { class: "material-icons text-amber-600" }, "warning", -1)),
4106
+ _cache[36] || (_cache[36] = createElementVNode("span", { class: "material-icons text-amber-600" }, "warning", -1)),
4039
4107
  createElementVNode("span", _hoisted_34, toDisplayString(unref(t)("collectionsView.dataIssuesDetected", { count: dataIssues.value.length })), 1),
4040
4108
  createElementVNode("button", {
4041
4109
  type: "button",
4042
4110
  class: "h-8 px-2.5 flex items-center gap-1 rounded border border-amber-300 bg-white hover:bg-amber-100 text-amber-700 font-bold text-xs transition-colors",
4043
4111
  "data-testid": "collections-repair",
4044
4112
  onClick: repairCollection
4045
- }, [_cache[37] || (_cache[37] = createElementVNode("span", { class: "material-icons text-sm" }, "build", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.repair")), 1)])
4113
+ }, [_cache[35] || (_cache[35] = createElementVNode("span", { class: "material-icons text-sm" }, "build", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.repair")), 1)])
4046
4114
  ])) : createCommentVNode("", true),
4047
- createElementVNode("div", _hoisted_35, [loading.value ? (openBlock(), createElementBlock("div", _hoisted_36, [_cache[39] || (_cache[39] = createElementVNode("div", { class: "h-8 w-8 border-2 border-indigo-600/20 border-t-indigo-600 rounded-full animate-spin" }, null, -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.loading")), 1)])) : loadError.value ? (openBlock(), createElementBlock("div", _hoisted_37, [_cache[40] || (_cache[40] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)), createElementVNode("span", null, toDisplayString(loadError.value === "not-found" ? unref(t)("collectionsView.notFound") : `${unref(t)("collectionsView.loadFailed")}: ${loadError.value}`), 1)])) : !collection.value ? (openBlock(), createElementBlock("div", _hoisted_38)) : calendarActive.value ? (openBlock(), createElementBlock("div", _hoisted_39, [createVNode(CollectionCalendarView_default, {
4115
+ createElementVNode("div", _hoisted_35, [loading.value ? (openBlock(), createElementBlock("div", _hoisted_36, [_cache[37] || (_cache[37] = createElementVNode("div", { class: "h-8 w-8 border-2 border-indigo-600/20 border-t-indigo-600 rounded-full animate-spin" }, null, -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.loading")), 1)])) : loadError.value ? (openBlock(), createElementBlock("div", _hoisted_37, [_cache[38] || (_cache[38] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)), createElementVNode("span", null, toDisplayString(loadError.value === "not-found" ? unref(t)("collectionsView.notFound") : `${unref(t)("collectionsView.loadFailed")}: ${loadError.value}`), 1)])) : !collection.value ? (openBlock(), createElementBlock("div", _hoisted_38)) : calendarActive.value ? (openBlock(), createElementBlock("div", _hoisted_39, [createVNode(CollectionCalendarView_default, {
4048
4116
  schema: collection.value.schema,
4049
4117
  items: filteredItems.value,
4050
4118
  "anchor-field": calendarAnchorField.value,
@@ -4129,14 +4197,14 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4129
4197
  "can-create",
4130
4198
  "show-detail"
4131
4199
  ])) : createCommentVNode("", true)])) : kanbanActive.value ? (openBlock(), createElementBlock("div", _hoisted_40, [inlineError.value ? (openBlock(), createElementBlock("div", _hoisted_41, [
4132
- _cache[42] || (_cache[42] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
4200
+ _cache[40] || (_cache[40] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
4133
4201
  createElementVNode("span", _hoisted_42, toDisplayString(unref(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
4134
4202
  createElementVNode("button", {
4135
4203
  type: "button",
4136
4204
  class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
4137
4205
  "aria-label": unref(t)("common.close"),
4138
4206
  onClick: _cache[10] || (_cache[10] = ($event) => inlineError.value = null)
4139
- }, [..._cache[41] || (_cache[41] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_43)
4207
+ }, [..._cache[39] || (_cache[39] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_43)
4140
4208
  ])) : createCommentVNode("", true), createElementVNode("div", _hoisted_44, [createVNode(CollectionKanbanView_default, {
4141
4209
  schema: collection.value.schema,
4142
4210
  items: filteredItems.value,
@@ -4154,8 +4222,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4154
4222
  ])])])) : activeCustomView.value ? (openBlock(), createElementBlock("div", _hoisted_45, [createVNode(CollectionCustomView_default, {
4155
4223
  slug: collection.value.slug,
4156
4224
  view: activeCustomView.value
4157
- }, null, 8, ["slug", "view"])])) : items.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_46, [_cache[43] || (_cache[43] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "folder_open", -1)), createElementVNode("p", _hoisted_47, toDisplayString(unref(t)("collectionsView.itemsEmpty")), 1)])) : filteredItems.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_48, [
4158
- _cache[44] || (_cache[44] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "search_off", -1)),
4225
+ }, null, 8, ["slug", "view"])])) : items.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_46, [_cache[41] || (_cache[41] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "folder_open", -1)), createElementVNode("p", _hoisted_47, toDisplayString(unref(t)("collectionsView.itemsEmpty")), 1)])) : filteredItems.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_48, [
4226
+ _cache[42] || (_cache[42] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "search_off", -1)),
4159
4227
  createElementVNode("p", _hoisted_49, toDisplayString(unref(t)("collectionsView.noMatchingItems")), 1),
4160
4228
  createElementVNode("button", {
4161
4229
  type: "button",
@@ -4163,14 +4231,14 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4163
4231
  onClick: _cache[11] || (_cache[11] = ($event) => searchQuery.value = "")
4164
4232
  }, toDisplayString(unref(t)("collectionsView.clearSearch")), 1)
4165
4233
  ])) : (openBlock(), createElementBlock("div", _hoisted_50, [inlineError.value ? (openBlock(), createElementBlock("div", _hoisted_51, [
4166
- _cache[46] || (_cache[46] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
4234
+ _cache[44] || (_cache[44] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
4167
4235
  createElementVNode("span", _hoisted_52, toDisplayString(unref(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
4168
4236
  createElementVNode("button", {
4169
4237
  type: "button",
4170
4238
  class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
4171
4239
  "aria-label": unref(t)("common.close"),
4172
4240
  onClick: _cache[12] || (_cache[12] = ($event) => inlineError.value = null)
4173
- }, [..._cache[45] || (_cache[45] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_53)
4241
+ }, [..._cache[43] || (_cache[43] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_53)
4174
4242
  ])) : createCommentVNode("", true), createElementVNode("table", _hoisted_54, [createElementVNode("thead", null, [createElementVNode("tr", _hoisted_55, [(openBlock(true), createElementBlock(Fragment, null, renderList(listColumnFields.value, ([key, field]) => {
4175
4243
  return openBlock(), createElementBlock("th", {
4176
4244
  key,
@@ -4223,57 +4291,48 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4223
4291
  "aria-label": field.label,
4224
4292
  onClick: _cache[15] || (_cache[15] = withModifiers(() => {}, ["stop"])),
4225
4293
  onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.checked)
4226
- }, null, 40, _hoisted_64)) : field.type === "ref" && field.to && typeof item[key] === "string" && item[key] ? (openBlock(), createElementBlock("span", _hoisted_65, [createVNode(_component_router_link, {
4227
- to: {
4228
- path: `/collections/${field.to}`,
4229
- query: { selected: String(item[key]) }
4230
- },
4294
+ }, null, 40, _hoisted_64)) : field.type === "ref" && field.to && typeof item[key] === "string" && item[key] ? (openBlock(), createElementBlock("span", _hoisted_65, [createElementVNode("a", {
4295
+ href: unref(cui).recordHref?.(field.to, String(item[key])),
4231
4296
  class: "text-indigo-600 hover:text-indigo-800 hover:underline font-semibold",
4232
4297
  "data-testid": `collections-ref-link-${key}-${item[key]}`,
4233
- onClick: _cache[16] || (_cache[16] = withModifiers(() => {}, ["stop"]))
4234
- }, {
4235
- default: withCtx(() => [createTextVNode(toDisplayString(unref(refDisplay)(field.to, String(item[key]))), 1)]),
4236
- _: 2
4237
- }, 1032, ["to", "data-testid"])])) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? (openBlock(), createElementBlock("select", {
4298
+ onClick: ($event) => onRefLinkClick($event, field.to, String(item[key]))
4299
+ }, toDisplayString(unref(refDisplay)(field.to, String(item[key]))), 9, _hoisted_66)])) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? (openBlock(), createElementBlock("select", {
4238
4300
  key: 3,
4239
4301
  value: item[key] == null ? "" : String(item[key]),
4240
4302
  disabled: isRowInlineSaving(item),
4241
4303
  class: normalizeClass(["rounded-lg border px-2 py-0.5 text-[11px] font-semibold focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed", enumControlClass(String(key), item[key])]),
4242
4304
  "data-testid": `collections-inline-enum-${key}-${item[collection.value.schema.primaryKey]}`,
4243
4305
  "aria-label": field.label,
4244
- onClick: _cache[17] || (_cache[17] = withModifiers(() => {}, ["stop"])),
4306
+ onClick: _cache[16] || (_cache[16] = withModifiers(() => {}, ["stop"])),
4245
4307
  onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.value)
4246
- }, [showEnumPlaceholder(item, String(key)) ? (openBlock(), createElementBlock("option", _hoisted_67, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(field.values, (value) => {
4308
+ }, [showEnumPlaceholder(item, String(key)) ? (openBlock(), createElementBlock("option", _hoisted_68, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(field.values, (value) => {
4247
4309
  return openBlock(), createElementBlock("option", {
4248
4310
  key: value,
4249
4311
  value
4250
- }, toDisplayString(value), 9, _hoisted_68);
4251
- }), 128))], 42, _hoisted_66)) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_69, toDisplayString(unref(formatMoney)(item[key], unref(resolveCurrency)(field, item), unref(locale))), 1)) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_70, [_cache[47] || (_cache[47] = createElementVNode("span", { class: "material-icons text-[11px]" }, "list", -1)), createElementVNode("span", null, toDisplayString(tableSummary(item[key])), 1)])) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_71, toDisplayString(unref(derivedDisplay)(field, unref(evaluateDerivedAgainstItem)(field, String(key), item), item)), 1)) : field.type !== "file" && unref(isExternalUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
4312
+ }, toDisplayString(value), 9, _hoisted_69);
4313
+ }), 128))], 42, _hoisted_67)) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_70, toDisplayString(unref(formatMoney)(item[key], unref(resolveCurrency)(field, item), unref(locale))), 1)) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_71, [_cache[45] || (_cache[45] = createElementVNode("span", { class: "material-icons text-[11px]" }, "list", -1)), createElementVNode("span", null, toDisplayString(tableSummary(item[key])), 1)])) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_72, toDisplayString(unref(derivedDisplay)(field, unref(evaluateDerivedAgainstItem)(field, String(key), item), item)), 1)) : field.type !== "file" && unref(isExternalUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
4252
4314
  key: 7,
4253
4315
  href: String(item[key]),
4254
4316
  target: "_blank",
4255
4317
  rel: "noopener noreferrer",
4256
4318
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
4257
4319
  "data-testid": `collections-url-link-${key}-${item[collection.value.schema.primaryKey]}`,
4258
- onClick: _cache[18] || (_cache[18] = withModifiers(() => {}, ["stop"]))
4259
- }, toDisplayString(String(item[key])), 9, _hoisted_72)) : field.type === "file" && unref(artifactUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
4320
+ onClick: _cache[17] || (_cache[17] = withModifiers(() => {}, ["stop"]))
4321
+ }, toDisplayString(String(item[key])), 9, _hoisted_73)) : field.type === "file" && unref(artifactUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
4260
4322
  key: 8,
4261
4323
  href: unref(artifactUrl)(item[key]) ?? void 0,
4262
4324
  target: "_blank",
4263
4325
  rel: "noopener noreferrer",
4264
4326
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
4265
4327
  "data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
4266
- onClick: _cache[19] || (_cache[19] = withModifiers(() => {}, ["stop"]))
4267
- }, toDisplayString(String(item[key])), 9, _hoisted_73)) : field.type === "file" && unref(fileRoutePath)(item[key]) ? (openBlock(), createBlock(_component_router_link, {
4328
+ onClick: _cache[18] || (_cache[18] = withModifiers(() => {}, ["stop"]))
4329
+ }, toDisplayString(String(item[key])), 9, _hoisted_74)) : field.type === "file" && unref(fileRoutePath)(item[key]) ? (openBlock(), createElementBlock("a", {
4268
4330
  key: 9,
4269
- to: unref(fileRoutePath)(item[key]) ?? "",
4331
+ href: unref(fileRoutePath)(item[key]) ?? void 0,
4270
4332
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
4271
4333
  "data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
4272
- onClick: _cache[20] || (_cache[20] = withModifiers(() => {}, ["stop"]))
4273
- }, {
4274
- default: withCtx(() => [createTextVNode(toDisplayString(String(item[key])), 1)]),
4275
- _: 2
4276
- }, 1032, ["to", "data-testid"])) : (openBlock(), createElementBlock("span", _hoisted_74, toDisplayString(unref(formatCell)(item[key], field.type)), 1))], 64)) : createCommentVNode("", true)]);
4334
+ onClick: ($event) => onFileLinkClick($event, unref(fileRoutePath)(item[key]) ?? "")
4335
+ }, toDisplayString(String(item[key])), 9, _hoisted_75)) : (openBlock(), createElementBlock("span", _hoisted_76, toDisplayString(unref(formatCell)(item[key], field.type)), 1))], 64)) : createCommentVNode("", true)]);
4277
4336
  }), 128))], 42, _hoisted_62);
4278
4337
  }), 128))])])]))]),
4279
4338
  collection.value && (viewing.value || editing.value) && !(calendarActive.value && openDay.value) ? (openBlock(), createBlock(CollectionRecordModal_default, {
@@ -4282,7 +4341,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4282
4341
  }, {
4283
4342
  default: withCtx(() => [createVNode(CollectionRecordPanel_default, {
4284
4343
  editing: editing.value,
4285
- "onUpdate:editing": _cache[21] || (_cache[21] = ($event) => editing.value = $event),
4344
+ "onUpdate:editing": _cache[19] || (_cache[19] = ($event) => editing.value = $event),
4286
4345
  collection: collection.value,
4287
4346
  viewing: viewing.value,
4288
4347
  saving: saving.value,
@@ -4300,7 +4359,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4300
4359
  onCancel: cancelEditor,
4301
4360
  onEdit: editFromView,
4302
4361
  onClose: closeView,
4303
- onDelete: _cache[22] || (_cache[22] = ($event) => viewing.value && confirmDelete(viewing.value)),
4362
+ onDelete: _cache[20] || (_cache[20] = ($event) => viewing.value && confirmDelete(viewing.value)),
4304
4363
  onRunAction: runAction
4305
4364
  }, null, 8, [
4306
4365
  "editing",
@@ -4326,7 +4385,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4326
4385
  title: collection.value.title,
4327
4386
  views: customViews.value,
4328
4387
  onChanged: onViewsChanged,
4329
- onClose: _cache[23] || (_cache[23] = ($event) => configOpen.value = false)
4388
+ onClose: _cache[21] || (_cache[21] = ($event) => configOpen.value = false)
4330
4389
  }, null, 8, [
4331
4390
  "slug",
4332
4391
  "title",
@@ -4341,29 +4400,29 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4341
4400
  "data-testid": "collections-chat-modal",
4342
4401
  onClick: withModifiers(closeChat, ["self"]),
4343
4402
  onKeydown: withKeys(closeChat, ["esc"])
4344
- }, [createElementVNode("div", _hoisted_75, [
4345
- createElementVNode("header", _hoisted_76, [
4346
- _cache[49] || (_cache[49] = createElementVNode("div", { class: "h-9 w-9 flex items-center justify-center rounded-xl bg-indigo-50 text-indigo-600 border border-indigo-100/50" }, [createElementVNode("span", { class: "material-icons text-lg" }, "forum")], -1)),
4347
- createElementVNode("div", _hoisted_77, [createElementVNode("h2", _hoisted_78, toDisplayString(unref(t)("collectionsView.chatTitle")), 1), createElementVNode("span", _hoisted_79, toDisplayString(collection.value.title), 1)]),
4403
+ }, [createElementVNode("div", _hoisted_77, [
4404
+ createElementVNode("header", _hoisted_78, [
4405
+ _cache[47] || (_cache[47] = createElementVNode("div", { class: "h-9 w-9 flex items-center justify-center rounded-xl bg-indigo-50 text-indigo-600 border border-indigo-100/50" }, [createElementVNode("span", { class: "material-icons text-lg" }, "forum")], -1)),
4406
+ createElementVNode("div", _hoisted_79, [createElementVNode("h2", _hoisted_80, toDisplayString(unref(t)("collectionsView.chatTitle")), 1), createElementVNode("span", _hoisted_81, toDisplayString(collection.value.title), 1)]),
4348
4407
  createElementVNode("button", {
4349
4408
  type: "button",
4350
4409
  class: "h-8 w-8 flex items-center justify-center rounded text-slate-400 hover:bg-slate-200/50 hover:text-slate-600 transition-colors",
4351
4410
  "aria-label": unref(t)("common.close"),
4352
4411
  "data-testid": "collections-chat-close",
4353
4412
  onClick: closeChat
4354
- }, [..._cache[48] || (_cache[48] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_80)
4413
+ }, [..._cache[46] || (_cache[46] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_82)
4355
4414
  ]),
4356
- createElementVNode("div", _hoisted_81, [withDirectives(createElementVNode("textarea", {
4415
+ createElementVNode("div", _hoisted_83, [withDirectives(createElementVNode("textarea", {
4357
4416
  ref_key: "chatInputEl",
4358
4417
  ref: chatInputEl,
4359
- "onUpdate:modelValue": _cache[24] || (_cache[24] = ($event) => chatMessage.value = $event),
4418
+ "onUpdate:modelValue": _cache[22] || (_cache[22] = ($event) => chatMessage.value = $event),
4360
4419
  rows: "4",
4361
4420
  placeholder: unref(t)("collectionsView.chatPlaceholder"),
4362
4421
  class: "w-full bg-slate-50 border border-slate-200/80 rounded-xl px-3 py-2.5 text-sm placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-500 focus:bg-white transition-all resize-none",
4363
4422
  "data-testid": "collections-chat-input",
4364
4423
  onKeydown: [withKeys(withModifiers(submitChat, ["meta"]), ["enter"]), withKeys(withModifiers(submitChat, ["ctrl"]), ["enter"])]
4365
- }, null, 40, _hoisted_82), [[vModelText, chatMessage.value]])]),
4366
- createElementVNode("footer", _hoisted_83, [createElementVNode("button", {
4424
+ }, null, 40, _hoisted_84), [[vModelText, chatMessage.value]])]),
4425
+ createElementVNode("footer", _hoisted_85, [createElementVNode("button", {
4367
4426
  type: "button",
4368
4427
  class: "h-8 px-2.5 rounded text-xs font-bold text-slate-500 hover:bg-slate-200/50 transition-colors",
4369
4428
  "data-testid": "collections-chat-cancel",
@@ -4374,13 +4433,121 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4374
4433
  disabled: !chatMessage.value.trim(),
4375
4434
  "data-testid": "collections-chat-send",
4376
4435
  onClick: submitChat
4377
- }, toDisplayString(unref(t)("collectionsView.chatStart")), 9, _hoisted_84)])
4436
+ }, toDisplayString(unref(t)("collectionsView.chatStart")), 9, _hoisted_86)])
4378
4437
  ])], 32)) : createCommentVNode("", true)
4379
4438
  ]);
4380
4439
  };
4381
4440
  }
4382
4441
  });
4383
4442
  //#endregion
4443
+ //#region src/vue/chat/View.vue?vue&type=script&setup=true&lang.ts
4444
+ var _hoisted_1$3 = {
4445
+ class: "w-full h-full",
4446
+ "data-testid": "present-collection"
4447
+ };
4448
+ //#endregion
4449
+ //#region src/vue/chat/View.vue
4450
+ var View_default = /* @__PURE__ */ defineComponent({
4451
+ __name: "View",
4452
+ props: {
4453
+ selectedResult: {},
4454
+ sendTextMessage: { type: Function }
4455
+ },
4456
+ emits: ["updateResult"],
4457
+ setup(__props, { emit: __emit }) {
4458
+ const props = __props;
4459
+ const emit = __emit;
4460
+ const data = computed(() => props.selectedResult?.data ?? props.selectedResult?.jsonData ?? null);
4461
+ const slug = computed(() => data.value?.collectionSlug);
4462
+ const viewState = computed(() => props.selectedResult?.viewState ?? null);
4463
+ /** Open record: the card-local `viewState.selected` once the user has
4464
+ * navigated within the card (including an explicit close → null), else
4465
+ * the tool's initial `itemId`. */
4466
+ const selected = computed(() => {
4467
+ const state = viewState.value;
4468
+ if (state && "selected" in state) return state.selected ?? void 0;
4469
+ return data.value?.itemId;
4470
+ });
4471
+ function onSelect(itemId) {
4472
+ if (!props.selectedResult) return;
4473
+ emit("updateResult", {
4474
+ ...props.selectedResult,
4475
+ viewState: {
4476
+ ...viewState.value,
4477
+ selected: itemId
4478
+ }
4479
+ });
4480
+ }
4481
+ function onViewStateChange(state) {
4482
+ if (!props.selectedResult) return;
4483
+ const current = viewState.value;
4484
+ if (current?.view === state.view && current?.anchorField === state.anchorField && current?.groupField === state.groupField) return;
4485
+ emit("updateResult", {
4486
+ ...props.selectedResult,
4487
+ viewState: {
4488
+ ...current,
4489
+ view: state.view,
4490
+ anchorField: state.anchorField,
4491
+ groupField: state.groupField
4492
+ }
4493
+ });
4494
+ }
4495
+ return (_ctx, _cache) => {
4496
+ return openBlock(), createElementBlock("div", _hoisted_1$3, [slug.value ? (openBlock(), createBlock(CollectionView_default, {
4497
+ key: 0,
4498
+ slug: slug.value,
4499
+ selected: selected.value,
4500
+ "initial-view": viewState.value?.view,
4501
+ "initial-anchor-field": viewState.value?.anchorField,
4502
+ "initial-group-field": viewState.value?.groupField,
4503
+ "send-text-message": __props.sendTextMessage,
4504
+ onSelect,
4505
+ onViewStateChange
4506
+ }, null, 8, [
4507
+ "slug",
4508
+ "selected",
4509
+ "initial-view",
4510
+ "initial-anchor-field",
4511
+ "initial-group-field",
4512
+ "send-text-message"
4513
+ ])) : createCommentVNode("", true)]);
4514
+ };
4515
+ }
4516
+ });
4517
+ //#endregion
4518
+ //#region src/vue/chat/Preview.vue?vue&type=script&setup=true&lang.ts
4519
+ var _hoisted_1$2 = { class: "w-full h-full flex flex-col items-center justify-center p-4 bg-gradient-to-br from-indigo-50 to-slate-50 rounded-lg border-2 border-gray-200" };
4520
+ var _hoisted_2$2 = { class: "text-center" };
4521
+ var _hoisted_3$2 = { class: "text-gray-900 font-bold text-lg mb-1 line-clamp-2" };
4522
+ var _hoisted_4$2 = {
4523
+ key: 0,
4524
+ class: "text-gray-600 text-sm"
4525
+ };
4526
+ var _hoisted_5$2 = {
4527
+ key: 1,
4528
+ class: "text-gray-500 text-sm"
4529
+ };
4530
+ //#endregion
4531
+ //#region src/vue/chat/Preview.vue
4532
+ var Preview_default = /* @__PURE__ */ defineComponent({
4533
+ __name: "Preview",
4534
+ props: { result: {} },
4535
+ setup(__props) {
4536
+ const { t } = useCollectionI18n();
4537
+ const props = __props;
4538
+ const data = computed(() => props.result?.data ?? props.result?.jsonData ?? null);
4539
+ const collectionSlug = computed(() => data.value?.collectionSlug ?? "");
4540
+ const itemId = computed(() => data.value?.itemId);
4541
+ return (_ctx, _cache) => {
4542
+ return openBlock(), createElementBlock("div", _hoisted_1$2, [createElementVNode("div", _hoisted_2$2, [
4543
+ _cache[0] || (_cache[0] = createElementVNode("span", { class: "material-icons text-4xl text-indigo-600 mb-2" }, "collections_bookmark", -1)),
4544
+ createElementVNode("h3", _hoisted_3$2, toDisplayString(collectionSlug.value || unref(t)("pluginPresentCollection.fallbackTitle")), 1),
4545
+ itemId.value ? (openBlock(), createElementBlock("p", _hoisted_4$2, toDisplayString(unref(t)("pluginPresentCollection.itemLabel", { id: itemId.value })), 1)) : (openBlock(), createElementBlock("p", _hoisted_5$2, toDisplayString(unref(t)("pluginPresentCollection.listLabel")), 1))
4546
+ ])]);
4547
+ };
4548
+ }
4549
+ });
4550
+ //#endregion
4384
4551
  //#region src/vue/components/CollectionsIndexView.vue?vue&type=script&setup=true&lang.ts
4385
4552
  var _hoisted_1$1 = {
4386
4553
  class: "h-full overflow-y-auto bg-slate-50/50 px-6 py-6",
@@ -4688,6 +4855,16 @@ var FeedsView_default = /* @__PURE__ */ defineComponent({
4688
4855
  }
4689
4856
  });
4690
4857
  //#endregion
4691
- export { CollectionCalendarView_default as CollectionCalendarView, CollectionCustomView_default as CollectionCustomView, CollectionDayView_default as CollectionDayView, CollectionEmbedView_default as CollectionEmbedView, CollectionKanbanView_default as CollectionKanbanView, CollectionRecordModal_default as CollectionRecordModal, CollectionRecordPanel_default as CollectionRecordPanel, CollectionView_default as CollectionView, CollectionViewConfigModal_default as CollectionViewConfigModal, CollectionsIndexView_default as CollectionsIndexView, FeedsView_default as FeedsView, collectionUi, configureCollectionUi, readCollectionSort, readCollectionViewMode, useCollectionRendering, writeCollectionSort, writeCollectionViewMode };
4858
+ //#region src/vue/index.ts
4859
+ var plugin = {
4860
+ toolDefinition: TOOL_DEFINITION,
4861
+ execute: executePresentCollection,
4862
+ generatingMessage: "Loading collection...",
4863
+ isEnabled: () => true,
4864
+ viewComponent: View_default,
4865
+ previewComponent: Preview_default
4866
+ };
4867
+ //#endregion
4868
+ export { CollectionCalendarView_default as CollectionCalendarView, CollectionCustomView_default as CollectionCustomView, CollectionDayView_default as CollectionDayView, CollectionEmbedView_default as CollectionEmbedView, CollectionKanbanView_default as CollectionKanbanView, CollectionRecordModal_default as CollectionRecordModal, CollectionRecordPanel_default as CollectionRecordPanel, CollectionView_default as CollectionView, CollectionViewConfigModal_default as CollectionViewConfigModal, CollectionsIndexView_default as CollectionsIndexView, FeedsView_default as FeedsView, Preview_default as PresentCollectionPreview, View_default as PresentCollectionView, collectionUi, configureCollectionUi, plugin, readCollectionSort, readCollectionViewMode, useCollectionRendering, writeCollectionSort, writeCollectionViewMode };
4692
4869
 
4693
4870
  //# sourceMappingURL=vue.js.map