@mulmoclaude/collection-plugin 0.7.3 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vue.js CHANGED
@@ -118,6 +118,8 @@ var i18n = createI18n({
118
118
  kanbanUncategorized: "Uncategorized",
119
119
  kanbanOpenCard: "Open {label}",
120
120
  addView: "Add view",
121
+ addViewDesktop: "Custom view",
122
+ addViewMobile: "Phone view",
121
123
  config: {
122
124
  open: "Collection settings",
123
125
  title: "{title} · settings",
@@ -129,6 +131,7 @@ var i18n = createI18n({
129
131
  customViewLoading: "Loading view…",
130
132
  customViewError: "Couldn't load this view: {error}",
131
133
  addViewPrompt: "I want to add a custom view to the \"{title}\" collection. Ask me what I want to see or edit, then author the HTML view file at {base}/views/your-view.html and register it in {base}/schema.json under `views[]` (capabilities [\"read\"] for a read-only view, [\"read\",\"write\"] if it edits records). Follow the custom-view help for the data contract.",
134
+ addMobileViewPrompt: "I want to add a phone (remote app) custom view to the \"{title}\" collection. Ask me what I want to see or edit, then author the HTML view file at {base}/views/your-view.html and register it in {base}/schema.json under `views[]` with `target: \"mobile\"` (read-only by default; declare `editableFields` / `allowDelete` only if it edits records). Follow the custom-view-remote help for the postMessage data contract — no fetch of any kind in the view.",
132
135
  repair: "Repair",
133
136
  dataIssuesDetected: "{count} record file(s) have data problems and may be missing from this view.",
134
137
  repairPrompt: "The \"{title}\" collection has {count} record file(s) with data problems that keep them from appearing. Fix each one — Read the file, correct it, then Write it back:\n{issues}\n\nWhen you're done, call presentCollection to confirm the records load.",
@@ -251,6 +254,8 @@ var i18n = createI18n({
251
254
  kanbanUncategorized: "未分類",
252
255
  kanbanOpenCard: "{label} を開く",
253
256
  addView: "ビューを追加",
257
+ addViewDesktop: "カスタムビュー",
258
+ addViewMobile: "スマホビュー",
254
259
  config: {
255
260
  open: "コレクション設定",
256
261
  title: "{title} · 設定",
@@ -262,6 +267,7 @@ var i18n = createI18n({
262
267
  customViewLoading: "ビューを読み込み中…",
263
268
  customViewError: "このビューを読み込めませんでした: {error}",
264
269
  addViewPrompt: "「{title}」コレクションにカスタムビューを追加したい。何を見たい/編集したいか質問してから、HTML ビューファイルを {base}/views/your-view.html に作成し、{base}/schema.json の `views[]` に登録して(読み取り専用なら capabilities [\"read\"]、レコードを編集するなら [\"read\",\"write\"])。データ契約は custom-view ヘルプに従ってください。",
270
+ addMobileViewPrompt: "「{title}」コレクションにスマホ(リモートアプリ)用カスタムビューを追加したい。何を見たい/編集したいか質問してから、HTML ビューファイルを {base}/views/your-view.html に作成し、{base}/schema.json の `views[]` に `target: \"mobile\"` 付きで登録して(デフォルトは読み取り専用。レコードを編集する場合のみ `editableFields` / `allowDelete` を宣言)。データ契約は custom-view-remote ヘルプに従ってください — ビュー内での fetch は一切禁止です。",
265
271
  repair: "修復",
266
272
  dataIssuesDetected: "{count} 件のレコードファイルにデータの問題があり、この表示に出てこない可能性があります。",
267
273
  repairPrompt: "コレクション「{title}」に、表示されない原因となるデータの問題を持つレコードファイルが {count} 件あります。それぞれを修正してください — ファイルを Read し、修正してから Write し直します:\n{issues}\n\n完了したら presentCollection を呼び出して、レコードが読み込めることを確認してください。",
@@ -384,6 +390,8 @@ var i18n = createI18n({
384
390
  kanbanUncategorized: "未分类",
385
391
  kanbanOpenCard: "打开 {label}",
386
392
  addView: "添加视图",
393
+ addViewDesktop: "自定义视图",
394
+ addViewMobile: "手机视图",
387
395
  config: {
388
396
  open: "集合设置",
389
397
  title: "{title} · 设置",
@@ -395,6 +403,7 @@ var i18n = createI18n({
395
403
  customViewLoading: "正在加载视图…",
396
404
  customViewError: "无法加载此视图:{error}",
397
405
  addViewPrompt: "我想为“{title}”集合添加一个自定义视图。先问我想查看或编辑什么,然后在 {base}/views/your-view.html 创建 HTML 视图文件,并在 {base}/schema.json 的 `views[]` 中注册(只读视图用 capabilities [\"read\"],需要编辑记录则用 [\"read\",\"write\"])。数据契约请遵循 custom-view 帮助文档。",
406
+ addMobileViewPrompt: "我想为“{title}”集合添加一个手机(远程应用)自定义视图。先问我想查看或编辑什么,然后在 {base}/views/your-view.html 创建 HTML 视图文件,并在 {base}/schema.json 的 `views[]` 中以 `target: \"mobile\"` 注册(默认只读;仅在需要编辑记录时声明 `editableFields` / `allowDelete`)。数据契约请遵循 custom-view-remote 帮助文档 — 视图内禁止任何 fetch。",
398
407
  repair: "修复",
399
408
  dataIssuesDetected: "有 {count} 个记录文件存在数据问题,可能未显示在此视图中。",
400
409
  repairPrompt: "集合 {title} 有 {count} 个记录文件存在导致无法显示的数据问题。请逐一修复——用 Read 读取该文件,更正后再用 Write 写回:\n{issues}\n\n完成后,调用 presentCollection 确认记录可以正常加载。",
@@ -517,6 +526,8 @@ var i18n = createI18n({
517
526
  kanbanUncategorized: "미분류",
518
527
  kanbanOpenCard: "{label} 열기",
519
528
  addView: "보기 추가",
529
+ addViewDesktop: "사용자 지정 보기",
530
+ addViewMobile: "스마트폰 보기",
520
531
  config: {
521
532
  open: "컬렉션 설정",
522
533
  title: "{title} · 설정",
@@ -528,6 +539,7 @@ var i18n = createI18n({
528
539
  customViewLoading: "보기를 불러오는 중…",
529
540
  customViewError: "이 보기를 불러오지 못했습니다: {error}",
530
541
  addViewPrompt: "{title} 컬렉션에 사용자 지정 보기를 추가하고 싶어요. 무엇을 보거나 편집하고 싶은지 먼저 물어본 뒤, {base}/views/your-view.html 에 HTML 보기 파일을 만들고 {base}/schema.json의 `views[]`에 등록해 주세요(읽기 전용 보기는 capabilities [\"read\"], 레코드를 편집하면 [\"read\",\"write\"]). 데이터 계약은 custom-view 도움말을 따르세요.",
542
+ addMobileViewPrompt: "{title} 컬렉션에 스마트폰(리모트 앱)용 사용자 지정 보기를 추가하고 싶어요. 무엇을 보거나 편집하고 싶은지 먼저 물어본 뒤, {base}/views/your-view.html 에 HTML 보기 파일을 만들고 {base}/schema.json의 `views[]`에 `target: \"mobile\"`과 함께 등록해 주세요(기본은 읽기 전용, 레코드를 편집할 때만 `editableFields` / `allowDelete` 선언). 데이터 계약은 custom-view-remote 도움말을 따르세요 — 보기 안에서 fetch는 일절 금지입니다.",
531
543
  repair: "복구",
532
544
  dataIssuesDetected: "{count}개의 레코드 파일에 데이터 문제가 있어 이 보기에 표시되지 않을 수 있습니다.",
533
545
  repairPrompt: "{title} 컬렉션에 표시되지 않는 원인이 되는 데이터 문제가 있는 레코드 파일이 {count}개 있습니다. 각 파일을 수정하세요 — Read로 파일을 읽고 수정한 뒤 Write로 다시 저장하세요:\n{issues}\n\n완료되면 presentCollection을 호출하여 레코드가 로드되는지 확인하세요.",
@@ -650,6 +662,8 @@ var i18n = createI18n({
650
662
  kanbanUncategorized: "Sin categoría",
651
663
  kanbanOpenCard: "Abrir {label}",
652
664
  addView: "Añadir vista",
665
+ addViewDesktop: "Vista personalizada",
666
+ addViewMobile: "Vista móvil",
653
667
  config: {
654
668
  open: "Ajustes de la colección",
655
669
  title: "{title} · ajustes",
@@ -661,6 +675,7 @@ var i18n = createI18n({
661
675
  customViewLoading: "Cargando vista…",
662
676
  customViewError: "No se pudo cargar esta vista: {error}",
663
677
  addViewPrompt: "Quiero añadir una vista personalizada a la colección «{title}». Pregúntame qué quiero ver o editar, luego crea el archivo HTML de la vista en {base}/views/your-view.html y regístralo en {base}/schema.json dentro de `views[]` (capabilities [\"read\"] para una vista de solo lectura, [\"read\",\"write\"] si edita registros). Sigue la ayuda custom-view para el contrato de datos.",
678
+ addMobileViewPrompt: "Quiero añadir una vista personalizada para el móvil (aplicación remota) a la colección «{title}». Pregúntame qué quiero ver o editar, luego crea el archivo HTML de la vista en {base}/views/your-view.html y regístralo en {base}/schema.json dentro de `views[]` con `target: \"mobile\"` (de solo lectura por defecto; declara `editableFields` / `allowDelete` solo si edita registros). Sigue la ayuda custom-view-remote para el contrato de datos por postMessage — nada de fetch en la vista.",
664
679
  repair: "Reparar",
665
680
  dataIssuesDetected: "{count} archivo(s) de registro tienen problemas de datos y podrían no aparecer en esta vista.",
666
681
  repairPrompt: "La colección {title} tiene {count} archivo(s) de registro con problemas de datos que impiden que aparezcan. Corrige cada uno: lee el archivo con Read, corrígelo y vuelve a escribirlo con Write:\n{issues}\n\nCuando termines, llama a presentCollection para confirmar que los registros se cargan.",
@@ -783,6 +798,8 @@ var i18n = createI18n({
783
798
  kanbanUncategorized: "Sem categoria",
784
799
  kanbanOpenCard: "Abrir {label}",
785
800
  addView: "Adicionar visualização",
801
+ addViewDesktop: "Visualização personalizada",
802
+ addViewMobile: "Visualização para celular",
786
803
  config: {
787
804
  open: "Configurações da coleção",
788
805
  title: "{title} · configurações",
@@ -794,6 +811,7 @@ var i18n = createI18n({
794
811
  customViewLoading: "Carregando visualização…",
795
812
  customViewError: "Não foi possível carregar esta visualização: {error}",
796
813
  addViewPrompt: "Quero adicionar uma visualização personalizada à coleção \"{title}\". Pergunte o que eu quero ver ou editar, depois crie o arquivo HTML da visualização em {base}/views/your-view.html e registre-o em {base}/schema.json em `views[]` (capabilities [\"read\"] para uma visualização somente leitura, [\"read\",\"write\"] se editar registros). Siga a ajuda custom-view para o contrato de dados.",
814
+ addMobileViewPrompt: "Quero adicionar uma visualização personalizada para o celular (app remoto) à coleção \"{title}\". Pergunte o que eu quero ver ou editar, depois crie o arquivo HTML da visualização em {base}/views/your-view.html e registre-o em {base}/schema.json em `views[]` com `target: \"mobile\"` (somente leitura por padrão; declare `editableFields` / `allowDelete` apenas se editar registros). Siga a ajuda custom-view-remote para o contrato de dados via postMessage — nenhum fetch na visualização.",
797
815
  repair: "Reparar",
798
816
  dataIssuesDetected: "{count} arquivo(s) de registro têm problemas de dados e podem não aparecer nesta visualização.",
799
817
  repairPrompt: "A coleção {title} tem {count} arquivo(s) de registro com problemas de dados que impedem que apareçam. Corrija cada um: leia o arquivo com Read, corrija-o e grave-o novamente com Write:\n{issues}\n\nQuando terminar, chame presentCollection para confirmar que os registros carregam.",
@@ -916,6 +934,8 @@ var i18n = createI18n({
916
934
  kanbanUncategorized: "Non classé",
917
935
  kanbanOpenCard: "Ouvrir {label}",
918
936
  addView: "Ajouter une vue",
937
+ addViewDesktop: "Vue personnalisée",
938
+ addViewMobile: "Vue mobile",
919
939
  config: {
920
940
  open: "Paramètres de la collection",
921
941
  title: "{title} · paramètres",
@@ -927,6 +947,7 @@ var i18n = createI18n({
927
947
  customViewLoading: "Chargement de la vue…",
928
948
  customViewError: "Impossible de charger cette vue : {error}",
929
949
  addViewPrompt: "Je veux ajouter une vue personnalisée à la collection « {title} ». Demande-moi ce que je veux voir ou modifier, puis crée le fichier HTML de la vue dans {base}/views/your-view.html et enregistre-le dans {base}/schema.json sous `views[]` (capabilities [\"read\"] pour une vue en lecture seule, [\"read\",\"write\"] si elle modifie des enregistrements). Suis l'aide custom-view pour le contrat de données.",
950
+ addMobileViewPrompt: "Je veux ajouter une vue personnalisée pour le mobile (application distante) à la collection « {title} ». Demande-moi ce que je veux voir ou modifier, puis crée le fichier HTML de la vue dans {base}/views/your-view.html et enregistre-le dans {base}/schema.json sous `views[]` avec `target: \"mobile\"` (en lecture seule par défaut ; déclare `editableFields` / `allowDelete` uniquement si elle modifie des enregistrements). Suis l'aide custom-view-remote pour le contrat de données par postMessage — aucun fetch dans la vue.",
930
951
  repair: "Réparer",
931
952
  dataIssuesDetected: "{count} fichier(s) d'enregistrement présentent des problèmes de données et peuvent être absents de cette vue.",
932
953
  repairPrompt: "La collection « {title} » comporte {count} fichier(s) d'enregistrement présentant des problèmes de données qui les empêchent d'apparaître. Corrigez chacun : lisez le fichier avec Read, corrigez-le, puis réécrivez-le avec Write :\n{issues}\n\nUne fois terminé, appelez presentCollection pour confirmer que les enregistrements se chargent.",
@@ -1049,6 +1070,8 @@ var i18n = createI18n({
1049
1070
  kanbanUncategorized: "Nicht kategorisiert",
1050
1071
  kanbanOpenCard: "{label} öffnen",
1051
1072
  addView: "Ansicht hinzufügen",
1073
+ addViewDesktop: "Benutzerdefinierte Ansicht",
1074
+ addViewMobile: "Smartphone-Ansicht",
1052
1075
  config: {
1053
1076
  open: "Sammlungseinstellungen",
1054
1077
  title: "{title} · Einstellungen",
@@ -1060,6 +1083,7 @@ var i18n = createI18n({
1060
1083
  customViewLoading: "Ansicht wird geladen…",
1061
1084
  customViewError: "Diese Ansicht konnte nicht geladen werden: {error}",
1062
1085
  addViewPrompt: "Ich möchte der Sammlung {title} eine benutzerdefinierte Ansicht hinzufügen. Frag mich, was ich sehen oder bearbeiten möchte, erstelle dann die HTML-Ansichtsdatei unter {base}/views/your-view.html und registriere sie in {base}/schema.json unter `views[]` (capabilities [\"read\"] für eine schreibgeschützte Ansicht, [\"read\",\"write\"] wenn sie Datensätze bearbeitet). Folge der custom-view-Hilfe für den Datenvertrag.",
1086
+ addMobileViewPrompt: "Ich möchte der Sammlung {title} eine benutzerdefinierte Ansicht für das Smartphone (Remote-App) hinzufügen. Frag mich, was ich sehen oder bearbeiten möchte, erstelle dann die HTML-Ansichtsdatei unter {base}/views/your-view.html und registriere sie in {base}/schema.json unter `views[]` mit `target: \"mobile\"` (standardmäßig schreibgeschützt; deklariere `editableFields` / `allowDelete` nur, wenn sie Datensätze bearbeitet). Folge der custom-view-remote-Hilfe für den postMessage-Datenvertrag — kein fetch jeglicher Art in der Ansicht.",
1063
1087
  repair: "Reparieren",
1064
1088
  dataIssuesDetected: "{count} Datensatzdatei(en) haben Datenprobleme und fehlen möglicherweise in dieser Ansicht.",
1065
1089
  repairPrompt: "Die Sammlung {title} hat {count} Datensatzdatei(en) mit Datenproblemen, die ihr Erscheinen verhindern. Korrigiere jede — die Datei mit Read lesen, korrigieren und mit Write zurückschreiben:\n{issues}\n\nRufe anschließend presentCollection auf, um zu bestätigen, dass die Datensätze geladen werden.",
@@ -2844,7 +2868,7 @@ var CollectionCustomView_vue_vue_type_script_setup_true_lang_default = /*@__PURE
2844
2868
  "data-testid": "collection-custom-view-iframe",
2845
2869
  title: __props.view.label,
2846
2870
  srcdoc: srcdoc.value,
2847
- sandbox: "allow-scripts allow-popups allow-popups-to-escape-sandbox",
2871
+ sandbox: "allow-scripts allow-popups allow-popups-to-escape-sandbox allow-downloads",
2848
2872
  class: "w-full h-full border-0"
2849
2873
  }, null, 8, _hoisted_4$7)) : createCommentVNode("", true)]);
2850
2874
  };
@@ -2859,7 +2883,7 @@ var _plugin_vue_export_helper_default = (sfc, props) => {
2859
2883
  };
2860
2884
  //#endregion
2861
2885
  //#region src/vue/components/CollectionCustomView.vue
2862
- var CollectionCustomView_default = /*#__PURE__*/ _plugin_vue_export_helper_default(CollectionCustomView_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-b22228db"]]);
2886
+ var CollectionCustomView_default = /*#__PURE__*/ _plugin_vue_export_helper_default(CollectionCustomView_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-02ff1e01"]]);
2863
2887
  //#endregion
2864
2888
  //#region src/vue/components/CollectionRemoteViewPreview.vue?vue&type=script&setup=true&lang.ts
2865
2889
  var _hoisted_1$7 = {
@@ -2981,18 +3005,151 @@ var CollectionRemoteViewPreview_default = /*#__PURE__*/ _plugin_vue_export_helpe
2981
3005
  "data-testid": "collection-remote-view-iframe",
2982
3006
  title: __props.view.label,
2983
3007
  srcdoc: srcdoc.value,
2984
- sandbox: "allow-scripts allow-popups allow-popups-to-escape-sandbox",
3008
+ sandbox: "allow-scripts allow-popups allow-popups-to-escape-sandbox allow-downloads",
2985
3009
  class: "phone-screen"
2986
3010
  }, null, 8, _hoisted_5$6))]), createElementVNode("div", _hoisted_6$5, toDisplayString(sizeCaption.value), 1)], 64)) : createCommentVNode("", true)]);
2987
3011
  };
2988
3012
  }
2989
- }), [["__scopeId", "data-v-cd23d935"]]);
3013
+ }), [["__scopeId", "data-v-965ade6c"]]);
2990
3014
  //#endregion
2991
- //#region src/vue/useCollectionRendering.ts
3015
+ //#region src/vue/useCollectionRendering.helpers.ts
3016
+ var EM_DASH = "—";
3017
+ var DEFAULT_CURRENCY = "USD";
3018
+ var MARKDOWN_CELL_PREVIEW_MAX = 80;
2992
3019
  function stepForFieldType(type) {
2993
3020
  if (type === "money") return "0.01";
2994
3021
  if (type === "number") return "any";
2995
3022
  }
3023
+ function inputTypeFor(type) {
3024
+ if (type === "email") return "email";
3025
+ if (type === "number") return "number";
3026
+ if (type === "money") return "number";
3027
+ if (type === "date") return "date";
3028
+ if (type === "datetime") return "datetime-local";
3029
+ return "text";
3030
+ }
3031
+ function isExternalUrl(value) {
3032
+ return typeof value === "string" && /^https?:\/\//i.test(value);
3033
+ }
3034
+ function detailText(value) {
3035
+ if (value === void 0 || value === null || value === "") return EM_DASH;
3036
+ return String(value);
3037
+ }
3038
+ function formatCell(value, type) {
3039
+ if (value === void 0 || value === null || value === "") return EM_DASH;
3040
+ if (type === "markdown" && typeof value === "string") return value.length > MARKDOWN_CELL_PREVIEW_MAX ? `${value.slice(0, MARKDOWN_CELL_PREVIEW_MAX)}…` : value;
3041
+ if (typeof value === "string" || typeof value === "number") return String(value);
3042
+ return JSON.stringify(value);
3043
+ }
3044
+ /** Resolve the ISO 4217 code for a money field: a per-record
3045
+ * `currencyField` (when present and non-blank) wins over the field's
3046
+ * literal `currency`. */
3047
+ function resolveCurrency(field, record) {
3048
+ if (field.currencyField && record) {
3049
+ const code = record[field.currencyField];
3050
+ if (typeof code === "string" && code.trim().length > 0) return code;
3051
+ }
3052
+ return field.currency;
3053
+ }
3054
+ function formatMoney(value, currency, displayLocale) {
3055
+ if (value === void 0 || value === "") return EM_DASH;
3056
+ const amount = typeof value === "number" ? value : Number(value);
3057
+ if (!Number.isFinite(amount)) return String(value);
3058
+ const currencyCode = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
3059
+ try {
3060
+ return new Intl.NumberFormat(displayLocale, {
3061
+ style: "currency",
3062
+ currency: currencyCode
3063
+ }).format(amount);
3064
+ } catch {
3065
+ return String(amount);
3066
+ }
3067
+ }
3068
+ function currencySymbolForLocale(currency, locale) {
3069
+ const code = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
3070
+ try {
3071
+ return new Intl.NumberFormat(locale, {
3072
+ style: "currency",
3073
+ currency: code
3074
+ }).formatToParts(0).find((entry) => entry.type === "currency")?.value ?? code;
3075
+ } catch {
3076
+ return code;
3077
+ }
3078
+ }
3079
+ function tableRows(value) {
3080
+ if (!Array.isArray(value)) return [];
3081
+ return value.filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row));
3082
+ }
3083
+ function hasTableRows(value) {
3084
+ return tableRows(value).length > 0;
3085
+ }
3086
+ /** Pick the field used to label a referenced/embedded record: prefer a
3087
+ * `name` field, then `title`, else fall back to the primary key. */
3088
+ function displayFieldFor(fields, primaryKey) {
3089
+ if ("name" in fields) return "name";
3090
+ if ("title" in fields) return "title";
3091
+ return primaryKey;
3092
+ }
3093
+ function uniqueRefTargets(schema) {
3094
+ const targets = /* @__PURE__ */ new Set();
3095
+ const walk = (fields) => {
3096
+ for (const field of Object.values(fields)) {
3097
+ if (field.type === "ref" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
3098
+ if (field.type === "table" && field.of) walk(field.of);
3099
+ }
3100
+ };
3101
+ walk(schema.fields);
3102
+ return [...targets];
3103
+ }
3104
+ function uniqueEmbedTargets(schema) {
3105
+ const targets = /* @__PURE__ */ new Set();
3106
+ for (const field of Object.values(schema.fields)) if (field.type === "embed" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
3107
+ return [...targets];
3108
+ }
3109
+ function buildRefDisplayMap(detail) {
3110
+ const { fields, primaryKey } = detail.collection.schema;
3111
+ const displayField = displayFieldFor(fields, primaryKey);
3112
+ const map = {};
3113
+ for (const item of detail.items) {
3114
+ const slugRaw = item[primaryKey];
3115
+ if (typeof slugRaw !== "string" || slugRaw.length === 0) continue;
3116
+ const displayRaw = item[displayField];
3117
+ map[slugRaw] = typeof displayRaw === "string" && displayRaw.length > 0 ? displayRaw : slugRaw;
3118
+ }
3119
+ return map;
3120
+ }
3121
+ function buildRefRecordMap(detail) {
3122
+ const { schema } = detail.collection;
3123
+ const map = {};
3124
+ for (const item of detail.items) {
3125
+ const slugRaw = item[schema.primaryKey];
3126
+ if (typeof slugRaw === "string" && slugRaw.length > 0) map[slugRaw] = deriveAll(schema, item, {});
3127
+ }
3128
+ return map;
3129
+ }
3130
+ function sortedRefOptions(map) {
3131
+ return Object.entries(map).map(([slug, display]) => ({
3132
+ slug,
3133
+ display
3134
+ })).sort((left, right) => left.display.localeCompare(right.display));
3135
+ }
3136
+ /** Dropdown options for an `embed` field's per-record picker: every
3137
+ * record in the target collection, labelled by its name/title (or
3138
+ * primary key), skipping records without a slug and sorted by label. */
3139
+ function buildEmbedOptions(schema, items) {
3140
+ const { fields, primaryKey } = schema;
3141
+ const displayField = displayFieldFor(fields, primaryKey);
3142
+ return items.map((item) => {
3143
+ const slug = String(item[primaryKey] ?? "");
3144
+ const labelRaw = item[displayField];
3145
+ return {
3146
+ slug,
3147
+ display: typeof labelRaw === "string" && labelRaw.length > 0 ? labelRaw : slug
3148
+ };
3149
+ }).filter((opt) => opt.slug.length > 0).sort((left, right) => left.display.localeCompare(right.display));
3150
+ }
3151
+ //#endregion
3152
+ //#region src/vue/useCollectionRendering.ts
2996
3153
  function useCollectionRendering(collection, locale) {
2997
3154
  const refCache = ref({});
2998
3155
  const refRecordCache = ref({});
@@ -3002,43 +3159,6 @@ function useCollectionRendering(collection, locale) {
3002
3159
  refRecordCache.value = {};
3003
3160
  embedCache.value = {};
3004
3161
  }
3005
- function uniqueRefTargets(schema) {
3006
- const targets = /* @__PURE__ */ new Set();
3007
- const walk = (fields) => {
3008
- for (const field of Object.values(fields)) {
3009
- if (field.type === "ref" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
3010
- if (field.type === "table" && field.of) walk(field.of);
3011
- }
3012
- };
3013
- walk(schema.fields);
3014
- return [...targets];
3015
- }
3016
- function uniqueEmbedTargets(schema) {
3017
- const targets = /* @__PURE__ */ new Set();
3018
- for (const field of Object.values(schema.fields)) if (field.type === "embed" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
3019
- return [...targets];
3020
- }
3021
- function buildRefDisplayMap(detail) {
3022
- const { fields, primaryKey } = detail.collection.schema;
3023
- const displayField = "name" in fields ? "name" : "title" in fields ? "title" : primaryKey;
3024
- const map = {};
3025
- for (const item of detail.items) {
3026
- const slugRaw = item[primaryKey];
3027
- if (typeof slugRaw !== "string" || slugRaw.length === 0) continue;
3028
- const displayRaw = item[displayField];
3029
- map[slugRaw] = typeof displayRaw === "string" && displayRaw.length > 0 ? displayRaw : slugRaw;
3030
- }
3031
- return map;
3032
- }
3033
- function buildRefRecordMap(detail) {
3034
- const { schema } = detail.collection;
3035
- const map = {};
3036
- for (const item of detail.items) {
3037
- const slugRaw = item[schema.primaryKey];
3038
- if (typeof slugRaw === "string" && slugRaw.length > 0) map[slugRaw] = deriveAll(schema, item, {});
3039
- }
3040
- return map;
3041
- }
3042
3162
  async function loadLinkedCollections(schema, expectedSlug) {
3043
3163
  const refTargets = new Set(uniqueRefTargets(schema));
3044
3164
  const embedTargets = new Set(uniqueEmbedTargets(schema));
@@ -3083,11 +3203,7 @@ function useCollectionRendering(collection, locale) {
3083
3203
  }
3084
3204
  function refOptions(targetSlug) {
3085
3205
  const map = refCache.value[targetSlug];
3086
- if (!map) return [];
3087
- return Object.entries(map).map(([slug, display]) => ({
3088
- slug,
3089
- display
3090
- })).sort((left, right) => left.display.localeCompare(right.display));
3206
+ return map ? sortedRefOptions(map) : [];
3091
3207
  }
3092
3208
  /** Dropdown options for an `embed` field's per-record picker (`idField`):
3093
3209
  * every record in the target collection, labelled by its name/title (or
@@ -3095,17 +3211,7 @@ function useCollectionRendering(collection, locale) {
3095
3211
  * that aren't also `ref` targets (the profile collection, say). */
3096
3212
  function embedOptions(targetSlug) {
3097
3213
  const data = embedCache.value[targetSlug];
3098
- if (!data) return [];
3099
- const { fields, primaryKey } = data.schema;
3100
- const displayField = "name" in fields ? "name" : "title" in fields ? "title" : primaryKey;
3101
- return data.items.map((item) => {
3102
- const slug = String(item[primaryKey] ?? "");
3103
- const labelRaw = item[displayField];
3104
- return {
3105
- slug,
3106
- display: typeof labelRaw === "string" && labelRaw.length > 0 ? labelRaw : slug
3107
- };
3108
- }).filter((opt) => opt.slug.length > 0).sort((left, right) => left.display.localeCompare(right.display));
3214
+ return data ? buildEmbedOptions(data.schema, data.items) : [];
3109
3215
  }
3110
3216
  function resolveEmbed(field, record) {
3111
3217
  if (field.type !== "embed" || !field.to) return {
@@ -3158,46 +3264,8 @@ function useCollectionRendering(collection, locale) {
3158
3264
  }
3159
3265
  return out;
3160
3266
  }
3161
- function resolveCurrency(field, record) {
3162
- if (field.currencyField && record) {
3163
- const code = record[field.currencyField];
3164
- if (typeof code === "string" && code.trim().length > 0) return code;
3165
- }
3166
- return field.currency;
3167
- }
3168
3267
  function currencySymbol(currency) {
3169
- const code = currency && currency.length > 0 ? currency : "USD";
3170
- try {
3171
- return new Intl.NumberFormat(locale.value, {
3172
- style: "currency",
3173
- currency: code
3174
- }).formatToParts(0).find((entry) => entry.type === "currency")?.value ?? code;
3175
- } catch {
3176
- return code;
3177
- }
3178
- }
3179
- function formatMoney(value, currency, displayLocale) {
3180
- if (value === void 0 || value === "") return "—";
3181
- const amount = typeof value === "number" ? value : Number(value);
3182
- if (!Number.isFinite(amount)) return String(value);
3183
- const currencyCode = currency && currency.length > 0 ? currency : "USD";
3184
- try {
3185
- return new Intl.NumberFormat(displayLocale, {
3186
- style: "currency",
3187
- currency: currencyCode
3188
- }).format(amount);
3189
- } catch {
3190
- return String(amount);
3191
- }
3192
- }
3193
- function formatCell(value, type) {
3194
- if (value === void 0 || value === null || value === "") return "—";
3195
- if (type === "markdown" && typeof value === "string") return value.length > 80 ? `${value.slice(0, 80)}…` : value;
3196
- if (typeof value === "string" || typeof value === "number") return String(value);
3197
- return JSON.stringify(value);
3198
- }
3199
- function isExternalUrl(value) {
3200
- return typeof value === "string" && /^https?:\/\//i.test(value);
3268
+ return currencySymbolForLocale(currency, locale.value);
3201
3269
  }
3202
3270
  function artifactUrl(value) {
3203
3271
  return collectionUi().fileAssetUrl(value);
@@ -3205,30 +3273,11 @@ function useCollectionRendering(collection, locale) {
3205
3273
  function fileRoutePath(value) {
3206
3274
  return collectionUi().fileRoutePath(value);
3207
3275
  }
3208
- function detailText(value) {
3209
- if (value === void 0 || value === null || value === "") return "—";
3210
- return String(value);
3211
- }
3212
- function tableRows(value) {
3213
- if (!Array.isArray(value)) return [];
3214
- return value.filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row));
3215
- }
3216
- function hasTableRows(value) {
3217
- return tableRows(value).length > 0;
3218
- }
3219
3276
  function formatSubCell(subField, value, record) {
3220
3277
  if (subField.type === "money") return formatMoney(value, resolveCurrency(subField, record), locale.value);
3221
3278
  if (subField.type === "ref" && subField.to && typeof value === "string" && value.length > 0) return refDisplay(subField.to, value);
3222
3279
  return formatCell(value, subField.type);
3223
3280
  }
3224
- function inputTypeFor(type) {
3225
- if (type === "email") return "email";
3226
- if (type === "number") return "number";
3227
- if (type === "money") return "number";
3228
- if (type === "date") return "date";
3229
- if (type === "datetime") return "datetime-local";
3230
- return "text";
3231
- }
3232
3281
  const stepFor = stepForFieldType;
3233
3282
  function evaluateDerivedAgainstItem(field, fieldKey, item) {
3234
3283
  if (!field.formula || !collection.value) return null;
@@ -3412,166 +3461,175 @@ var _hoisted_26$1 = [
3412
3461
  "onClick"
3413
3462
  ];
3414
3463
  var _hoisted_27$1 = { class: "material-icons text-sm" };
3415
- var _hoisted_28 = ["title", "aria-label"];
3416
- var _hoisted_29 = ["title", "aria-label"];
3417
- var _hoisted_30 = ["value", "aria-label"];
3418
- var _hoisted_31 = ["value"];
3419
- var _hoisted_32 = ["value", "aria-label"];
3420
- var _hoisted_33 = ["value"];
3421
- var _hoisted_34 = {
3464
+ var _hoisted_28 = [
3465
+ "title",
3466
+ "aria-label",
3467
+ "aria-expanded"
3468
+ ];
3469
+ var _hoisted_29 = {
3470
+ key: 0,
3471
+ class: "absolute left-0 top-full mt-1 z-20 min-w-max rounded border border-slate-200 bg-white shadow-lg py-1",
3472
+ "data-testid": "collection-view-add-menu"
3473
+ };
3474
+ var _hoisted_30 = ["title", "aria-label"];
3475
+ var _hoisted_31 = ["value", "aria-label"];
3476
+ var _hoisted_32 = ["value"];
3477
+ var _hoisted_33 = ["value", "aria-label"];
3478
+ var _hoisted_34 = ["value"];
3479
+ var _hoisted_35 = {
3422
3480
  key: 3,
3423
3481
  class: "text-[10px] text-slate-400 font-bold uppercase tracking-wider select-none"
3424
3482
  };
3425
- var _hoisted_35 = {
3483
+ var _hoisted_36 = {
3426
3484
  key: 3,
3427
3485
  class: "mx-6 mt-4 rounded-xl border border-amber-200 bg-amber-50/60 p-4 text-sm text-amber-900 shadow-sm flex items-center gap-3",
3428
3486
  "data-testid": "collections-data-issues"
3429
3487
  };
3430
- var _hoisted_36 = { class: "flex-1" };
3431
- var _hoisted_37 = { class: "flex-1 overflow-auto" };
3432
- var _hoisted_38 = {
3488
+ var _hoisted_37 = { class: "flex-1" };
3489
+ var _hoisted_38 = { class: "flex-1 overflow-auto" };
3490
+ var _hoisted_39 = {
3433
3491
  key: 0,
3434
3492
  class: "flex flex-col items-center justify-center py-20 text-sm text-slate-500 gap-3"
3435
3493
  };
3436
- var _hoisted_39 = {
3494
+ var _hoisted_40 = {
3437
3495
  key: 1,
3438
3496
  class: "m-6 rounded-xl border border-red-200 bg-red-50/50 p-4 text-sm text-red-800 shadow-sm flex items-center gap-3"
3439
3497
  };
3440
- var _hoisted_40 = { key: 2 };
3441
- var _hoisted_41 = {
3498
+ var _hoisted_41 = { key: 2 };
3499
+ var _hoisted_42 = {
3442
3500
  key: 3,
3443
3501
  class: "p-4"
3444
3502
  };
3445
- var _hoisted_42 = {
3503
+ var _hoisted_43 = {
3446
3504
  key: 4,
3447
3505
  class: "h-full flex flex-col"
3448
3506
  };
3449
- var _hoisted_43 = {
3507
+ var _hoisted_44 = {
3450
3508
  key: 0,
3451
3509
  class: "m-3 mb-0 rounded-xl border border-red-200 bg-red-50/50 p-4 text-sm text-red-800 shadow-sm flex items-center gap-3",
3452
3510
  "data-testid": "collections-inline-error"
3453
3511
  };
3454
- var _hoisted_44 = { class: "flex-1" };
3455
- var _hoisted_45 = ["aria-label"];
3456
- var _hoisted_46 = { class: "flex-1 min-h-0 px-3 py-2" };
3457
- var _hoisted_47 = {
3512
+ var _hoisted_45 = { class: "flex-1" };
3513
+ var _hoisted_46 = ["aria-label"];
3514
+ var _hoisted_47 = { class: "flex-1 min-h-0 px-3 py-2" };
3515
+ var _hoisted_48 = {
3458
3516
  key: 5,
3459
3517
  class: "h-full",
3460
3518
  "data-testid": "collection-custom-view-body"
3461
3519
  };
3462
- var _hoisted_48 = {
3520
+ var _hoisted_49 = {
3463
3521
  key: 6,
3464
3522
  class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
3465
3523
  };
3466
- var _hoisted_49 = { class: "font-semibold text-slate-600" };
3467
- var _hoisted_50 = {
3524
+ var _hoisted_50 = { class: "font-semibold text-slate-600" };
3525
+ var _hoisted_51 = {
3468
3526
  key: 7,
3469
3527
  class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
3470
3528
  };
3471
- var _hoisted_51 = { class: "font-semibold text-slate-600" };
3472
- var _hoisted_52 = {
3529
+ var _hoisted_52 = { class: "font-semibold text-slate-600" };
3530
+ var _hoisted_53 = {
3473
3531
  key: 8,
3474
3532
  class: "overflow-x-auto [container-type:inline-size]"
3475
3533
  };
3476
- var _hoisted_53 = {
3534
+ var _hoisted_54 = {
3477
3535
  key: 0,
3478
3536
  class: "m-4 rounded-xl border border-red-200 bg-red-50/50 p-4 text-sm text-red-800 shadow-sm flex items-center gap-3",
3479
3537
  "data-testid": "collections-inline-error"
3480
3538
  };
3481
- var _hoisted_54 = { class: "flex-1" };
3482
- var _hoisted_55 = ["aria-label"];
3483
- var _hoisted_56 = { class: "min-w-full text-xs" };
3484
- var _hoisted_57 = { class: "bg-slate-50 border-b border-slate-200" };
3485
- var _hoisted_58 = ["aria-sort"];
3486
- var _hoisted_59 = { class: "flex items-center gap-1" };
3487
- var _hoisted_60 = ["title"];
3488
- var _hoisted_61 = [
3539
+ var _hoisted_55 = { class: "flex-1" };
3540
+ var _hoisted_56 = ["aria-label"];
3541
+ var _hoisted_57 = { class: "min-w-full text-xs" };
3542
+ var _hoisted_58 = { class: "bg-slate-50 border-b border-slate-200" };
3543
+ var _hoisted_59 = ["aria-sort"];
3544
+ var _hoisted_60 = { class: "flex items-center gap-1" };
3545
+ var _hoisted_61 = ["title"];
3546
+ var _hoisted_62 = [
3489
3547
  "data-testid",
3490
3548
  "aria-label",
3491
3549
  "onClick",
3492
3550
  "onPointerenter"
3493
3551
  ];
3494
- var _hoisted_62 = { class: "material-icons text-base align-middle" };
3495
- var _hoisted_63 = { class: "divide-y divide-slate-100 bg-white" };
3496
- var _hoisted_64 = [
3552
+ var _hoisted_63 = { class: "material-icons text-base align-middle" };
3553
+ var _hoisted_64 = { class: "divide-y divide-slate-100 bg-white" };
3554
+ var _hoisted_65 = [
3497
3555
  "aria-label",
3498
3556
  "data-testid",
3499
3557
  "onClick",
3500
3558
  "onKeydown"
3501
3559
  ];
3502
- var _hoisted_65 = [
3560
+ var _hoisted_66 = [
3503
3561
  "checked",
3504
3562
  "disabled",
3505
3563
  "data-testid",
3506
3564
  "aria-label",
3507
3565
  "onChange"
3508
3566
  ];
3509
- var _hoisted_66 = [
3567
+ var _hoisted_67 = [
3510
3568
  "checked",
3511
3569
  "disabled",
3512
3570
  "data-testid",
3513
3571
  "aria-label",
3514
3572
  "onChange"
3515
3573
  ];
3516
- var _hoisted_67 = {
3574
+ var _hoisted_68 = {
3517
3575
  key: 2,
3518
3576
  class: "block truncate"
3519
3577
  };
3520
- var _hoisted_68 = [
3578
+ var _hoisted_69 = [
3521
3579
  "href",
3522
3580
  "tabindex",
3523
3581
  "data-testid",
3524
3582
  "onClick",
3525
3583
  "onKeydown"
3526
3584
  ];
3527
- var _hoisted_69 = [
3585
+ var _hoisted_70 = [
3528
3586
  "value",
3529
3587
  "disabled",
3530
3588
  "data-testid",
3531
3589
  "aria-label",
3532
3590
  "onChange"
3533
3591
  ];
3534
- var _hoisted_70 = {
3592
+ var _hoisted_71 = {
3535
3593
  key: 0,
3536
3594
  value: ""
3537
3595
  };
3538
- var _hoisted_71 = ["value"];
3539
- var _hoisted_72 = {
3596
+ var _hoisted_72 = ["value"];
3597
+ var _hoisted_73 = {
3540
3598
  key: 4,
3541
3599
  class: "block truncate tabular-nums font-semibold text-slate-900"
3542
3600
  };
3543
- var _hoisted_73 = {
3601
+ var _hoisted_74 = {
3544
3602
  key: 5,
3545
3603
  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"
3546
3604
  };
3547
- var _hoisted_74 = {
3605
+ var _hoisted_75 = {
3548
3606
  key: 6,
3549
3607
  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"
3550
3608
  };
3551
- var _hoisted_75 = ["href", "data-testid"];
3552
3609
  var _hoisted_76 = ["href", "data-testid"];
3553
- var _hoisted_77 = [
3610
+ var _hoisted_77 = ["href", "data-testid"];
3611
+ var _hoisted_78 = [
3554
3612
  "href",
3555
3613
  "data-testid",
3556
3614
  "onClick"
3557
3615
  ];
3558
- var _hoisted_78 = {
3616
+ var _hoisted_79 = {
3559
3617
  key: 10,
3560
3618
  class: "block truncate text-slate-600"
3561
3619
  };
3562
- var _hoisted_79 = { class: "bg-white rounded-2xl shadow-2xl w-full max-w-xl flex flex-col border border-slate-200 overflow-hidden" };
3563
- var _hoisted_80 = { class: "px-6 py-4 border-b border-slate-100 flex items-center gap-3 bg-slate-50/50" };
3564
- var _hoisted_81 = { class: "flex-1" };
3565
- var _hoisted_82 = {
3620
+ var _hoisted_80 = { class: "bg-white rounded-2xl shadow-2xl w-full max-w-xl flex flex-col border border-slate-200 overflow-hidden" };
3621
+ var _hoisted_81 = { class: "px-6 py-4 border-b border-slate-100 flex items-center gap-3 bg-slate-50/50" };
3622
+ var _hoisted_82 = { class: "flex-1" };
3623
+ var _hoisted_83 = {
3566
3624
  id: "collections-chat-title",
3567
3625
  class: "text-sm font-bold text-slate-800 uppercase tracking-wide"
3568
3626
  };
3569
- var _hoisted_83 = { class: "text-xs text-slate-400 font-semibold" };
3570
- var _hoisted_84 = ["aria-label"];
3571
- var _hoisted_85 = { class: "px-6 py-5" };
3572
- var _hoisted_86 = ["placeholder", "onKeydown"];
3573
- var _hoisted_87 = { class: "px-6 py-3.5 border-t border-slate-100 flex items-center justify-end gap-2 bg-slate-50/50" };
3574
- var _hoisted_88 = ["disabled"];
3627
+ var _hoisted_84 = { class: "text-xs text-slate-400 font-semibold" };
3628
+ var _hoisted_85 = ["aria-label"];
3629
+ var _hoisted_86 = { class: "px-6 py-5" };
3630
+ var _hoisted_87 = ["placeholder", "onKeydown"];
3631
+ var _hoisted_88 = { class: "px-6 py-3.5 border-t border-slate-100 flex items-center justify-end gap-2 bg-slate-50/50" };
3632
+ var _hoisted_89 = ["disabled"];
3575
3633
  /** `slug` / `selected` are supplied only in EMBEDDED mode (the
3576
3634
  * `presentCollection` chat card mounts this component and drives both
3577
3635
  * from the tool result). In standalone route mode (the
@@ -4097,16 +4155,41 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4097
4155
  * page only (the seed starts a chat). Feeds qualify too — their views are
4098
4156
  * authored under feeds/<slug>/ and the seed prompt points there. */
4099
4157
  const canAddCustomView = computed(() => Boolean(collection.value) && !embedded.value);
4158
+ const addMenuOpen = ref(false);
4159
+ const addMenuRef = ref(null);
4160
+ /** Whether authoring a phone (remote app) view is worth offering — mirrors
4161
+ * the selector filter above: without the host's `fetchRemoteView` binding a
4162
+ * mobile view could be authored but never shown here. */
4163
+ const canAddMobileView = computed(() => Boolean(cui.fetchRemoteView));
4164
+ /** "+" click: open the target chooser, or skip the one-item menu and seed
4165
+ * the desktop prompt directly when mobile views aren't available. */
4166
+ function onAddViewClick() {
4167
+ if (!canAddMobileView.value) {
4168
+ addCustomView("desktop");
4169
+ return;
4170
+ }
4171
+ addMenuOpen.value = !addMenuOpen.value;
4172
+ }
4173
+ function closeAddMenuOnOutsideClick(event) {
4174
+ if (!addMenuRef.value?.contains(event.target)) addMenuOpen.value = false;
4175
+ }
4176
+ watch(addMenuOpen, (open) => {
4177
+ if (open) document.addEventListener("mousedown", closeAddMenuOnOutsideClick);
4178
+ else document.removeEventListener("mousedown", closeAddMenuOnOutsideClick);
4179
+ });
4100
4180
  /** Seed a chat asking Claude to author a new custom view for this collection.
4101
4181
  * Reuses the same chat-seed path as collection actions — the host injects a
4102
4182
  * templated prompt; Claude asks, authors the HTML, and registers it. The
4103
4183
  * authoring base is source-aware: a feed lives under `feeds/<slug>/`, every
4104
- * other collection under the `data/skills/<slug>/` staging dir. */
4105
- function addCustomView() {
4184
+ * other collection under the `data/skills/<slug>/` staging dir. The prompt
4185
+ * is target-aware: phone views follow the custom-view-remote contract and
4186
+ * register with `target: "mobile"`. */
4187
+ function addCustomView(target) {
4188
+ addMenuOpen.value = false;
4106
4189
  const current = collection.value;
4107
4190
  if (!current) return;
4108
4191
  const base = current.source === "feed" ? `feeds/${current.slug}` : `data/skills/${current.slug}`;
4109
- const prompt = t("collectionsView.addViewPrompt", {
4192
+ const prompt = t(target === "mobile" ? "collectionsView.addMobileViewPrompt" : "collectionsView.addViewPrompt", {
4110
4193
  title: current.title,
4111
4194
  base
4112
4195
  });
@@ -4582,6 +4665,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4582
4665
  view.value = slug && readCollectionViewMode(slug) || "table";
4583
4666
  anchorOverride.value = null;
4584
4667
  kanbanOverride.value = null;
4668
+ addMenuOpen.value = false;
4585
4669
  sortState.value = storedSortFor(slug);
4586
4670
  }
4587
4671
  if (slug) loadCollection(slug);
@@ -4630,6 +4714,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4630
4714
  changeUnsub = null;
4631
4715
  clearLiveRefreshTimer();
4632
4716
  if (refreshNoteTimer !== void 0) clearTimeout(refreshNoteTimer);
4717
+ document.removeEventListener("mousedown", closeAddMenuOnOutsideClick);
4633
4718
  });
4634
4719
  watch([
4635
4720
  activeView,
@@ -4664,7 +4749,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4664
4749
  "aria-label": unref(t)("collectionsView.backToIndex"),
4665
4750
  "data-testid": "collections-back",
4666
4751
  onClick: goBack
4667
- }, [..._cache[23] || (_cache[23] = [createElementVNode("span", { class: "material-icons text-lg" }, "arrow_back", -1)])], 8, _hoisted_3$5)) : createCommentVNode("", true),
4752
+ }, [..._cache[25] || (_cache[25] = [createElementVNode("span", { class: "material-icons text-lg" }, "arrow_back", -1)])], 8, _hoisted_3$5)) : createCommentVNode("", true),
4668
4753
  collection.value ? (openBlock(), createElementBlock("div", _hoisted_4$5, [createElementVNode("span", _hoisted_5$5, toDisplayString(collection.value.icon), 1)])) : createCommentVNode("", true),
4669
4754
  createElementVNode("div", _hoisted_6$4, [createElementVNode("h1", _hoisted_7$4, toDisplayString(collection.value?.title ?? unref(t)("collectionsView.title")), 1), collection.value ? (openBlock(), createElementBlock("span", _hoisted_8$4, toDisplayString(collection.value.slug), 1)) : createCommentVNode("", true)]),
4670
4755
  collection.value && !embedded.value ? (openBlock(), createBlock(resolveDynamicComponent(unref(pinToggle)), {
@@ -4693,7 +4778,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4693
4778
  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",
4694
4779
  "data-testid": "collections-chat",
4695
4780
  onClick: openChat
4696
- }, [_cache[24] || (_cache[24] = createElementVNode("span", { class: "material-icons text-sm" }, "forum", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.chat")), 1)])) : createCommentVNode("", true),
4781
+ }, [_cache[26] || (_cache[26] = createElementVNode("span", { class: "material-icons text-sm" }, "forum", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.chat")), 1)])) : createCommentVNode("", true),
4697
4782
  (openBlock(true), createElementBlock(Fragment, null, renderList(collectionActions.value, (action) => {
4698
4783
  return openBlock(), createElementBlock("button", {
4699
4784
  key: action.id,
@@ -4710,7 +4795,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4710
4795
  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",
4711
4796
  "data-testid": "collections-add-item",
4712
4797
  onClick: openCreate
4713
- }, [_cache[25] || (_cache[25] = createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.add")), 1)])) : createCommentVNode("", true),
4798
+ }, [_cache[27] || (_cache[27] = createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.add")), 1)])) : createCommentVNode("", true),
4714
4799
  canDeleteCollection.value && !embedded.value ? (openBlock(), createElementBlock("button", {
4715
4800
  key: 6,
4716
4801
  type: "button",
@@ -4719,7 +4804,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4719
4804
  "aria-label": unref(t)("collectionsView.deleteCollection"),
4720
4805
  "data-testid": "collections-delete",
4721
4806
  onClick: confirmCollectionDelete
4722
- }, [..._cache[26] || (_cache[26] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_13$4)) : createCommentVNode("", true),
4807
+ }, [..._cache[28] || (_cache[28] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_13$4)) : createCommentVNode("", true),
4723
4808
  canDeleteFeed.value && !embedded.value ? (openBlock(), createElementBlock("button", {
4724
4809
  key: 7,
4725
4810
  type: "button",
@@ -4728,11 +4813,11 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4728
4813
  "aria-label": unref(t)("collectionsView.deleteFeed"),
4729
4814
  "data-testid": "feeds-delete",
4730
4815
  onClick: confirmFeedDelete
4731
- }, [..._cache[27] || (_cache[27] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_14$4)) : createCommentVNode("", true)
4816
+ }, [..._cache[29] || (_cache[29] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_14$4)) : createCommentVNode("", true)
4732
4817
  ])) : createCommentVNode("", true),
4733
- refreshNote.value ? (openBlock(), createElementBlock("div", _hoisted_15$4, [_cache[28] || (_cache[28] = createElementVNode("span", { class: "material-icons text-base text-indigo-600" }, "hourglass_top", -1)), createElementVNode("span", _hoisted_16$4, toDisplayString(refreshNote.value), 1)])) : createCommentVNode("", true),
4818
+ refreshNote.value ? (openBlock(), createElementBlock("div", _hoisted_15$4, [_cache[30] || (_cache[30] = createElementVNode("span", { class: "material-icons text-base text-indigo-600" }, "hourglass_top", -1)), createElementVNode("span", _hoisted_16$4, toDisplayString(refreshNote.value), 1)])) : createCommentVNode("", true),
4734
4819
  collection.value && (!__props.hideSearch && items.value.length > 0 || !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value)) ? (openBlock(), createElementBlock("div", _hoisted_17$4, [!__props.hideSearch && items.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_18$4, [
4735
- _cache[30] || (_cache[30] = 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)),
4820
+ _cache[32] || (_cache[32] = 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)),
4736
4821
  withDirectives(createElementVNode("input", {
4737
4822
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchQuery.value = $event),
4738
4823
  type: "text",
@@ -4746,7 +4831,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4746
4831
  "aria-label": unref(t)("collectionsView.clearSearch"),
4747
4832
  class: "absolute inset-y-0 right-0 flex items-center pr-2.5 text-slate-400 hover:text-slate-600",
4748
4833
  onClick: _cache[1] || (_cache[1] = ($event) => searchQuery.value = "")
4749
- }, [..._cache[29] || (_cache[29] = [createElementVNode("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_20$2)) : createCommentVNode("", true)
4834
+ }, [..._cache[31] || (_cache[31] = [createElementVNode("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_20$2)) : createCommentVNode("", true)
4750
4835
  ])) : createCommentVNode("", true), createElementVNode("div", _hoisted_21$2, [
4751
4836
  !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value) ? (openBlock(), createElementBlock("div", {
4752
4837
  key: 0,
@@ -4760,7 +4845,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4760
4845
  "aria-pressed": activeView.value === "table",
4761
4846
  "data-testid": "collection-view-toggle-table",
4762
4847
  onClick: _cache[2] || (_cache[2] = ($event) => setView("table"))
4763
- }, [_cache[31] || (_cache[31] = createElementVNode("span", { class: "material-icons text-sm" }, "table_rows", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewTable")), 1)], 10, _hoisted_23$2),
4848
+ }, [_cache[33] || (_cache[33] = createElementVNode("span", { class: "material-icons text-sm" }, "table_rows", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewTable")), 1)], 10, _hoisted_23$2),
4764
4849
  hasCalendar.value ? (openBlock(), createElementBlock("button", {
4765
4850
  key: 0,
4766
4851
  type: "button",
@@ -4768,7 +4853,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4768
4853
  "aria-pressed": activeView.value === "calendar",
4769
4854
  "data-testid": "collection-view-toggle-calendar",
4770
4855
  onClick: _cache[3] || (_cache[3] = ($event) => setView("calendar"))
4771
- }, [_cache[32] || (_cache[32] = createElementVNode("span", { class: "material-icons text-sm" }, "calendar_month", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewCalendar")), 1)], 10, _hoisted_24$1)) : createCommentVNode("", true),
4856
+ }, [_cache[34] || (_cache[34] = createElementVNode("span", { class: "material-icons text-sm" }, "calendar_month", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewCalendar")), 1)], 10, _hoisted_24$1)) : createCommentVNode("", true),
4772
4857
  hasKanban.value ? (openBlock(), createElementBlock("button", {
4773
4858
  key: 1,
4774
4859
  type: "button",
@@ -4776,7 +4861,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4776
4861
  "aria-pressed": activeView.value === "kanban",
4777
4862
  "data-testid": "collection-view-toggle-kanban",
4778
4863
  onClick: _cache[4] || (_cache[4] = ($event) => setView("kanban"))
4779
- }, [_cache[33] || (_cache[33] = createElementVNode("span", { class: "material-icons text-sm" }, "view_kanban", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewKanban")), 1)], 10, _hoisted_25$1)) : createCommentVNode("", true),
4864
+ }, [_cache[35] || (_cache[35] = createElementVNode("span", { class: "material-icons text-sm" }, "view_kanban", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewKanban")), 1)], 10, _hoisted_25$1)) : createCommentVNode("", true),
4780
4865
  (openBlock(true), createElementBlock(Fragment, null, renderList(customViews.value, (cv) => {
4781
4866
  return openBlock(), createElementBlock("button", {
4782
4867
  key: cv.id,
@@ -4787,15 +4872,30 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4787
4872
  onClick: ($event) => setCustomView(cv.id)
4788
4873
  }, [createElementVNode("span", _hoisted_27$1, toDisplayString(cv.icon || (cv.target === "mobile" ? "smartphone" : "dashboard_customize")), 1), createElementVNode("span", null, toDisplayString(cv.label), 1)], 10, _hoisted_26$1);
4789
4874
  }), 128)),
4790
- canAddCustomView.value ? (openBlock(), createElementBlock("button", {
4875
+ canAddCustomView.value ? (openBlock(), createElementBlock("div", {
4791
4876
  key: 2,
4877
+ ref_key: "addMenuRef",
4878
+ ref: addMenuRef,
4879
+ class: "relative"
4880
+ }, [createElementVNode("button", {
4792
4881
  type: "button",
4793
4882
  class: "h-8 w-8 flex items-center justify-center rounded bg-white text-slate-500 border border-slate-200 hover:bg-slate-50",
4794
4883
  title: unref(t)("collectionsView.addView"),
4795
4884
  "aria-label": unref(t)("collectionsView.addView"),
4885
+ "aria-expanded": addMenuOpen.value,
4796
4886
  "data-testid": "collection-view-add",
4797
- onClick: addCustomView
4798
- }, [..._cache[34] || (_cache[34] = [createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)])], 8, _hoisted_28)) : createCommentVNode("", true),
4887
+ onClick: onAddViewClick
4888
+ }, [..._cache[36] || (_cache[36] = [createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)])], 8, _hoisted_28), addMenuOpen.value ? (openBlock(), createElementBlock("div", _hoisted_29, [createElementVNode("button", {
4889
+ type: "button",
4890
+ class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
4891
+ "data-testid": "collection-view-add-desktop",
4892
+ onClick: _cache[5] || (_cache[5] = ($event) => addCustomView("desktop"))
4893
+ }, [_cache[37] || (_cache[37] = createElementVNode("span", { class: "material-icons text-sm" }, "dashboard_customize", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.addViewDesktop")), 1)]), createElementVNode("button", {
4894
+ type: "button",
4895
+ class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
4896
+ "data-testid": "collection-view-add-mobile",
4897
+ onClick: _cache[6] || (_cache[6] = ($event) => addCustomView("mobile"))
4898
+ }, [_cache[38] || (_cache[38] = createElementVNode("span", { class: "material-icons text-sm" }, "smartphone", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.addViewMobile")), 1)])])) : createCommentVNode("", true)], 512)) : createCommentVNode("", true),
4799
4899
  canConfigureViews.value ? (openBlock(), createElementBlock("button", {
4800
4900
  key: 3,
4801
4901
  type: "button",
@@ -4803,8 +4903,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4803
4903
  title: unref(t)("collectionsView.config.open"),
4804
4904
  "aria-label": unref(t)("collectionsView.config.open"),
4805
4905
  "data-testid": "collection-config-open",
4806
- onClick: _cache[5] || (_cache[5] = ($event) => configOpen.value = true)
4807
- }, [..._cache[35] || (_cache[35] = [createElementVNode("span", { class: "material-icons text-sm" }, "settings", -1)])], 8, _hoisted_29)) : createCommentVNode("", true)
4906
+ onClick: _cache[7] || (_cache[7] = ($event) => configOpen.value = true)
4907
+ }, [..._cache[39] || (_cache[39] = [createElementVNode("span", { class: "material-icons text-sm" }, "settings", -1)])], 8, _hoisted_30)) : createCommentVNode("", true)
4808
4908
  ], 8, _hoisted_22$2)) : createCommentVNode("", true),
4809
4909
  calendarActive.value && dateFields.value.length > 1 ? (openBlock(), createElementBlock("select", {
4810
4910
  key: 1,
@@ -4812,42 +4912,42 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4812
4912
  class: "h-8 px-2 rounded border border-slate-200 bg-white text-xs font-semibold text-slate-600 focus:outline-none focus:border-indigo-500 cursor-pointer",
4813
4913
  "aria-label": unref(t)("collectionsView.calendarFieldLabel"),
4814
4914
  "data-testid": "collection-calendar-field",
4815
- onChange: _cache[6] || (_cache[6] = ($event) => anchorOverride.value = $event.target.value)
4915
+ onChange: _cache[8] || (_cache[8] = ($event) => anchorOverride.value = $event.target.value)
4816
4916
  }, [(openBlock(true), createElementBlock(Fragment, null, renderList(dateFields.value, (key) => {
4817
4917
  return openBlock(), createElementBlock("option", {
4818
4918
  key,
4819
4919
  value: key
4820
- }, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_31);
4821
- }), 128))], 40, _hoisted_30)) : createCommentVNode("", true),
4920
+ }, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_32);
4921
+ }), 128))], 40, _hoisted_31)) : createCommentVNode("", true),
4822
4922
  kanbanActive.value && enumFields.value.length > 1 ? (openBlock(), createElementBlock("select", {
4823
4923
  key: 2,
4824
4924
  value: kanbanGroupField.value,
4825
4925
  class: "h-8 px-2 rounded border border-slate-200 bg-white text-xs font-semibold text-slate-600 focus:outline-none focus:border-indigo-500 cursor-pointer",
4826
4926
  "aria-label": unref(t)("collectionsView.kanbanFieldLabel"),
4827
4927
  "data-testid": "collection-kanban-field",
4828
- onChange: _cache[7] || (_cache[7] = ($event) => kanbanOverride.value = $event.target.value)
4928
+ onChange: _cache[9] || (_cache[9] = ($event) => kanbanOverride.value = $event.target.value)
4829
4929
  }, [(openBlock(true), createElementBlock(Fragment, null, renderList(enumFields.value, (key) => {
4830
4930
  return openBlock(), createElementBlock("option", {
4831
4931
  key,
4832
4932
  value: key
4833
- }, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_33);
4834
- }), 128))], 40, _hoisted_32)) : createCommentVNode("", true),
4835
- items.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_34, toDisplayString(unref(t)("collectionsView.searchSummary", {
4933
+ }, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_34);
4934
+ }), 128))], 40, _hoisted_33)) : createCommentVNode("", true),
4935
+ items.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_35, toDisplayString(unref(t)("collectionsView.searchSummary", {
4836
4936
  shown: filteredItems.value.length,
4837
4937
  total: items.value.length
4838
4938
  })), 1)) : createCommentVNode("", true)
4839
4939
  ])])) : createCommentVNode("", true),
4840
- collection.value && dataIssues.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_35, [
4841
- _cache[37] || (_cache[37] = createElementVNode("span", { class: "material-icons text-amber-600" }, "warning", -1)),
4842
- createElementVNode("span", _hoisted_36, toDisplayString(unref(t)("collectionsView.dataIssuesDetected", { count: dataIssues.value.length })), 1),
4940
+ collection.value && dataIssues.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_36, [
4941
+ _cache[41] || (_cache[41] = createElementVNode("span", { class: "material-icons text-amber-600" }, "warning", -1)),
4942
+ createElementVNode("span", _hoisted_37, toDisplayString(unref(t)("collectionsView.dataIssuesDetected", { count: dataIssues.value.length })), 1),
4843
4943
  createElementVNode("button", {
4844
4944
  type: "button",
4845
4945
  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",
4846
4946
  "data-testid": "collections-repair",
4847
4947
  onClick: repairCollection
4848
- }, [_cache[36] || (_cache[36] = createElementVNode("span", { class: "material-icons text-sm" }, "build", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.repair")), 1)])
4948
+ }, [_cache[40] || (_cache[40] = createElementVNode("span", { class: "material-icons text-sm" }, "build", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.repair")), 1)])
4849
4949
  ])) : createCommentVNode("", true),
4850
- createElementVNode("div", _hoisted_37, [loading.value ? (openBlock(), createElementBlock("div", _hoisted_38, [_cache[38] || (_cache[38] = 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_39, [_cache[39] || (_cache[39] = 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_40)) : calendarActive.value ? (openBlock(), createElementBlock("div", _hoisted_41, [createVNode(CollectionCalendarView_default, {
4950
+ createElementVNode("div", _hoisted_38, [loading.value ? (openBlock(), createElementBlock("div", _hoisted_39, [_cache[42] || (_cache[42] = 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_40, [_cache[43] || (_cache[43] = 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_41)) : calendarActive.value ? (openBlock(), createElementBlock("div", _hoisted_42, [createVNode(CollectionCalendarView_default, {
4851
4951
  schema: collection.value.schema,
4852
4952
  items: filteredItems.value,
4853
4953
  "anchor-field": calendarAnchorField.value,
@@ -4883,7 +4983,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4883
4983
  }, {
4884
4984
  detail: withCtx(() => [createVNode(CollectionRecordPanel_default, {
4885
4985
  editing: editing.value,
4886
- "onUpdate:editing": _cache[8] || (_cache[8] = ($event) => editing.value = $event),
4986
+ "onUpdate:editing": _cache[10] || (_cache[10] = ($event) => editing.value = $event),
4887
4987
  collection: collection.value,
4888
4988
  viewing: viewing.value,
4889
4989
  saving: saving.value,
@@ -4901,7 +5001,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4901
5001
  onCancel: cancelEditor,
4902
5002
  onEdit: editFromView,
4903
5003
  onClose: onDayClose,
4904
- onDelete: _cache[9] || (_cache[9] = ($event) => viewing.value && confirmDelete(viewing.value)),
5004
+ onDelete: _cache[11] || (_cache[11] = ($event) => viewing.value && confirmDelete(viewing.value)),
4905
5005
  onRunAction: runAction,
4906
5006
  onItemChat
4907
5007
  }, null, 8, [
@@ -4932,16 +5032,16 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4932
5032
  "selected",
4933
5033
  "can-create",
4934
5034
  "show-detail"
4935
- ])) : createCommentVNode("", true)])) : kanbanActive.value ? (openBlock(), createElementBlock("div", _hoisted_42, [inlineError.value ? (openBlock(), createElementBlock("div", _hoisted_43, [
4936
- _cache[41] || (_cache[41] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
4937
- createElementVNode("span", _hoisted_44, toDisplayString(unref(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
5035
+ ])) : createCommentVNode("", true)])) : kanbanActive.value ? (openBlock(), createElementBlock("div", _hoisted_43, [inlineError.value ? (openBlock(), createElementBlock("div", _hoisted_44, [
5036
+ _cache[45] || (_cache[45] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
5037
+ createElementVNode("span", _hoisted_45, toDisplayString(unref(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
4938
5038
  createElementVNode("button", {
4939
5039
  type: "button",
4940
5040
  class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
4941
5041
  "aria-label": unref(t)("common.close"),
4942
- onClick: _cache[10] || (_cache[10] = ($event) => inlineError.value = null)
4943
- }, [..._cache[40] || (_cache[40] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_45)
4944
- ])) : createCommentVNode("", true), createElementVNode("div", _hoisted_46, [createVNode(CollectionKanbanView_default, {
5042
+ onClick: _cache[12] || (_cache[12] = ($event) => inlineError.value = null)
5043
+ }, [..._cache[44] || (_cache[44] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_46)
5044
+ ])) : createCommentVNode("", true), createElementVNode("div", _hoisted_47, [createVNode(CollectionKanbanView_default, {
4945
5045
  schema: collection.value.schema,
4946
5046
  items: filteredItems.value,
4947
5047
  "group-field": kanbanGroupField.value,
@@ -4955,7 +5055,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4955
5055
  "group-field",
4956
5056
  "selected",
4957
5057
  "notified"
4958
- ])])])) : activeCustomView.value ? (openBlock(), createElementBlock("div", _hoisted_47, [activeCustomView.value.target === "mobile" ? (openBlock(), createBlock(CollectionRemoteViewPreview_default, {
5058
+ ])])])) : activeCustomView.value ? (openBlock(), createElementBlock("div", _hoisted_48, [activeCustomView.value.target === "mobile" ? (openBlock(), createBlock(CollectionRemoteViewPreview_default, {
4959
5059
  key: 0,
4960
5060
  slug: collection.value.slug,
4961
5061
  view: activeCustomView.value,
@@ -4966,32 +5066,32 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4966
5066
  view: activeCustomView.value,
4967
5067
  onOpenItem: onCustomViewOpenItem,
4968
5068
  onStartChat: onCustomViewStartChat
4969
- }, null, 8, ["slug", "view"]))])) : items.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_48, [_cache[42] || (_cache[42] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "folder_open", -1)), createElementVNode("p", _hoisted_49, toDisplayString(unref(t)("collectionsView.itemsEmpty")), 1)])) : filteredItems.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_50, [
4970
- _cache[43] || (_cache[43] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "search_off", -1)),
4971
- createElementVNode("p", _hoisted_51, toDisplayString(unref(t)("collectionsView.noMatchingItems")), 1),
5069
+ }, null, 8, ["slug", "view"]))])) : items.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_49, [_cache[46] || (_cache[46] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "folder_open", -1)), createElementVNode("p", _hoisted_50, toDisplayString(unref(t)("collectionsView.itemsEmpty")), 1)])) : filteredItems.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_51, [
5070
+ _cache[47] || (_cache[47] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "search_off", -1)),
5071
+ createElementVNode("p", _hoisted_52, toDisplayString(unref(t)("collectionsView.noMatchingItems")), 1),
4972
5072
  createElementVNode("button", {
4973
5073
  type: "button",
4974
5074
  class: "text-xs text-indigo-600 font-semibold hover:underline",
4975
- onClick: _cache[11] || (_cache[11] = ($event) => searchQuery.value = "")
5075
+ onClick: _cache[13] || (_cache[13] = ($event) => searchQuery.value = "")
4976
5076
  }, toDisplayString(unref(t)("collectionsView.clearSearch")), 1)
4977
- ])) : (openBlock(), createElementBlock("div", _hoisted_52, [inlineError.value ? (openBlock(), createElementBlock("div", _hoisted_53, [
4978
- _cache[45] || (_cache[45] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
4979
- createElementVNode("span", _hoisted_54, toDisplayString(unref(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
5077
+ ])) : (openBlock(), createElementBlock("div", _hoisted_53, [inlineError.value ? (openBlock(), createElementBlock("div", _hoisted_54, [
5078
+ _cache[49] || (_cache[49] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
5079
+ createElementVNode("span", _hoisted_55, toDisplayString(unref(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
4980
5080
  createElementVNode("button", {
4981
5081
  type: "button",
4982
5082
  class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
4983
5083
  "aria-label": unref(t)("common.close"),
4984
- onClick: _cache[12] || (_cache[12] = ($event) => inlineError.value = null)
4985
- }, [..._cache[44] || (_cache[44] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_55)
4986
- ])) : createCommentVNode("", true), createElementVNode("table", _hoisted_56, [createElementVNode("thead", null, [createElementVNode("tr", _hoisted_57, [(openBlock(true), createElementBlock(Fragment, null, renderList(listColumnFields.value, ([key, field]) => {
5084
+ onClick: _cache[14] || (_cache[14] = ($event) => inlineError.value = null)
5085
+ }, [..._cache[48] || (_cache[48] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_56)
5086
+ ])) : createCommentVNode("", true), createElementVNode("table", _hoisted_57, [createElementVNode("thead", null, [createElementVNode("tr", _hoisted_58, [(openBlock(true), createElementBlock(Fragment, null, renderList(listColumnFields.value, ([key, field]) => {
4987
5087
  return openBlock(), createElementBlock("th", {
4988
5088
  key,
4989
5089
  "aria-sort": unref(isSortableField)(field) ? sortAriaValue(key) : void 0,
4990
5090
  class: "px-5 py-3 font-bold text-slate-500 text-left uppercase tracking-wider whitespace-nowrap"
4991
- }, [createElementVNode("div", _hoisted_59, [createElementVNode("span", {
5091
+ }, [createElementVNode("div", _hoisted_60, [createElementVNode("span", {
4992
5092
  class: "truncate max-w-[14rem]",
4993
5093
  title: field.label
4994
- }, toDisplayString(field.label), 9, _hoisted_60), unref(isSortableField)(field) ? (openBlock(), createElementBlock("button", {
5094
+ }, toDisplayString(field.label), 9, _hoisted_61), unref(isSortableField)(field) ? (openBlock(), createElementBlock("button", {
4995
5095
  key: 0,
4996
5096
  type: "button",
4997
5097
  class: normalizeClass(["inline-flex items-center justify-center rounded p-0.5 -my-1 leading-none transition-colors", sortButtonClass(key)]),
@@ -4999,9 +5099,9 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4999
5099
  "aria-label": unref(t)("collectionsView.sortBy", { field: field.label }),
5000
5100
  onClick: withModifiers(($event) => cycleSort(key), ["stop"]),
5001
5101
  onPointerenter: ($event) => hoveredSortKey.value = key,
5002
- onPointerleave: _cache[13] || (_cache[13] = ($event) => hoveredSortKey.value = null)
5003
- }, [createElementVNode("span", _hoisted_62, toDisplayString(sortIconName(key)), 1)], 42, _hoisted_61)) : createCommentVNode("", true)])], 8, _hoisted_58);
5004
- }), 128))])]), createElementVNode("tbody", _hoisted_63, [(openBlock(true), createElementBlock(Fragment, null, renderList(sortedItems.value, (item) => {
5102
+ onPointerleave: _cache[15] || (_cache[15] = ($event) => hoveredSortKey.value = null)
5103
+ }, [createElementVNode("span", _hoisted_63, toDisplayString(sortIconName(key)), 1)], 42, _hoisted_62)) : createCommentVNode("", true)])], 8, _hoisted_59);
5104
+ }), 128))])]), createElementVNode("tbody", _hoisted_64, [(openBlock(true), createElementBlock(Fragment, null, renderList(sortedItems.value, (item) => {
5005
5105
  return openBlock(), createElementBlock("tr", {
5006
5106
  key: String(item[collection.value.schema.primaryKey] ?? ""),
5007
5107
  class: normalizeClass(["hover:bg-slate-50/70 cursor-pointer transition-colors focus:outline-none focus:bg-indigo-50/30", isRowOpen(item) || isEditingRow(item) ? "bg-indigo-50/40" : ""]),
@@ -5023,9 +5123,9 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5023
5123
  class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer align-middle disabled:opacity-50 disabled:cursor-not-allowed",
5024
5124
  "data-testid": `collections-inline-toggle-${key}-${item[collection.value.schema.primaryKey]}`,
5025
5125
  "aria-label": field.label,
5026
- onClick: _cache[14] || (_cache[14] = withModifiers(() => {}, ["stop"])),
5126
+ onClick: _cache[16] || (_cache[16] = withModifiers(() => {}, ["stop"])),
5027
5127
  onChange: ($event) => commitToggle(item, field)
5028
- }, null, 40, _hoisted_65)) : field.type === "boolean" ? (openBlock(), createElementBlock("input", {
5128
+ }, null, 40, _hoisted_66)) : field.type === "boolean" ? (openBlock(), createElementBlock("input", {
5029
5129
  key: 1,
5030
5130
  type: "checkbox",
5031
5131
  checked: item[key] === true,
@@ -5033,9 +5133,9 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5033
5133
  class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer align-middle disabled:opacity-50 disabled:cursor-not-allowed",
5034
5134
  "data-testid": `collections-inline-bool-${key}-${item[collection.value.schema.primaryKey]}`,
5035
5135
  "aria-label": field.label,
5036
- onClick: _cache[15] || (_cache[15] = withModifiers(() => {}, ["stop"])),
5136
+ onClick: _cache[17] || (_cache[17] = withModifiers(() => {}, ["stop"])),
5037
5137
  onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.checked)
5038
- }, null, 40, _hoisted_66)) : field.type === "ref" && field.to && typeof item[key] === "string" && item[key] ? (openBlock(), createElementBlock("span", _hoisted_67, [createElementVNode("a", {
5138
+ }, null, 40, _hoisted_67)) : field.type === "ref" && field.to && typeof item[key] === "string" && item[key] ? (openBlock(), createElementBlock("span", _hoisted_68, [createElementVNode("a", {
5039
5139
  href: unref(cui).recordHref?.(field.to, String(item[key])),
5040
5140
  tabindex: unref(cui).recordHref?.(field.to, String(item[key])) ? void 0 : 0,
5041
5141
  role: "link",
@@ -5043,44 +5143,44 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5043
5143
  "data-testid": `collections-ref-link-${key}-${item[key]}`,
5044
5144
  onClick: ($event) => unref(activateRefLink)($event, field.to, String(item[key]), true),
5045
5145
  onKeydown: [withKeys(($event) => unref(activateRefLink)($event, field.to, String(item[key]), true), ["enter"]), withKeys(($event) => unref(activateRefLink)($event, field.to, String(item[key]), true), ["space"])]
5046
- }, toDisplayString(unref(refDisplay)(field.to, String(item[key]))), 41, _hoisted_68)])) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? (openBlock(), createElementBlock("select", {
5146
+ }, toDisplayString(unref(refDisplay)(field.to, String(item[key]))), 41, _hoisted_69)])) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? (openBlock(), createElementBlock("select", {
5047
5147
  key: 3,
5048
5148
  value: item[key] == null ? "" : String(item[key]),
5049
5149
  disabled: isRowInlineSaving(item),
5050
5150
  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])]),
5051
5151
  "data-testid": `collections-inline-enum-${key}-${item[collection.value.schema.primaryKey]}`,
5052
5152
  "aria-label": field.label,
5053
- onClick: _cache[16] || (_cache[16] = withModifiers(() => {}, ["stop"])),
5153
+ onClick: _cache[18] || (_cache[18] = withModifiers(() => {}, ["stop"])),
5054
5154
  onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.value)
5055
- }, [showEnumPlaceholder(item, String(key)) ? (openBlock(), createElementBlock("option", _hoisted_70, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(field.values, (value) => {
5155
+ }, [showEnumPlaceholder(item, String(key)) ? (openBlock(), createElementBlock("option", _hoisted_71, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(field.values, (value) => {
5056
5156
  return openBlock(), createElementBlock("option", {
5057
5157
  key: value,
5058
5158
  value
5059
- }, toDisplayString(value), 9, _hoisted_71);
5060
- }), 128))], 42, _hoisted_69)) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_72, toDisplayString(unref(formatMoney)(item[key], unref(resolveCurrency)(field, item), unref(locale))), 1)) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_73, [_cache[46] || (_cache[46] = createElementVNode("span", { class: "material-icons text-[11px]" }, "list", -1)), createElementVNode("span", null, toDisplayString(tableSummary(item[key])), 1)])) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_74, toDisplayString(unref(derivedDisplay)(field, unref(evaluateDerivedAgainstItem)(field, String(key), item), item)), 1)) : field.type !== "file" && unref(isExternalUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
5159
+ }, toDisplayString(value), 9, _hoisted_72);
5160
+ }), 128))], 42, _hoisted_70)) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_73, toDisplayString(unref(formatMoney)(item[key], unref(resolveCurrency)(field, item), unref(locale))), 1)) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_74, [_cache[50] || (_cache[50] = createElementVNode("span", { class: "material-icons text-[11px]" }, "list", -1)), createElementVNode("span", null, toDisplayString(tableSummary(item[key])), 1)])) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_75, toDisplayString(unref(derivedDisplay)(field, unref(evaluateDerivedAgainstItem)(field, String(key), item), item)), 1)) : field.type !== "file" && unref(isExternalUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
5061
5161
  key: 7,
5062
5162
  href: String(item[key]),
5063
5163
  target: "_blank",
5064
5164
  rel: "noopener noreferrer",
5065
5165
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
5066
5166
  "data-testid": `collections-url-link-${key}-${item[collection.value.schema.primaryKey]}`,
5067
- onClick: _cache[17] || (_cache[17] = withModifiers(() => {}, ["stop"]))
5068
- }, toDisplayString(String(item[key])), 9, _hoisted_75)) : field.type === "file" && unref(artifactUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
5167
+ onClick: _cache[19] || (_cache[19] = withModifiers(() => {}, ["stop"]))
5168
+ }, toDisplayString(String(item[key])), 9, _hoisted_76)) : field.type === "file" && unref(artifactUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
5069
5169
  key: 8,
5070
5170
  href: unref(artifactUrl)(item[key]) ?? void 0,
5071
5171
  target: "_blank",
5072
5172
  rel: "noopener noreferrer",
5073
5173
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
5074
5174
  "data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
5075
- onClick: _cache[18] || (_cache[18] = withModifiers(() => {}, ["stop"]))
5076
- }, toDisplayString(String(item[key])), 9, _hoisted_76)) : field.type === "file" && unref(fileRoutePath)(item[key]) ? (openBlock(), createElementBlock("a", {
5175
+ onClick: _cache[20] || (_cache[20] = withModifiers(() => {}, ["stop"]))
5176
+ }, toDisplayString(String(item[key])), 9, _hoisted_77)) : field.type === "file" && unref(fileRoutePath)(item[key]) ? (openBlock(), createElementBlock("a", {
5077
5177
  key: 9,
5078
5178
  href: unref(fileRoutePath)(item[key]) ?? void 0,
5079
5179
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
5080
5180
  "data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
5081
5181
  onClick: ($event) => unref(activatePathLink)($event, unref(fileRoutePath)(item[key]) ?? "", true)
5082
- }, toDisplayString(String(item[key])), 9, _hoisted_77)) : (openBlock(), createElementBlock("span", _hoisted_78, toDisplayString(unref(formatCell)(item[key], field.type)), 1))], 64)) : createCommentVNode("", true)]);
5083
- }), 128))], 42, _hoisted_64);
5182
+ }, toDisplayString(String(item[key])), 9, _hoisted_78)) : (openBlock(), createElementBlock("span", _hoisted_79, toDisplayString(unref(formatCell)(item[key], field.type)), 1))], 64)) : createCommentVNode("", true)]);
5183
+ }), 128))], 42, _hoisted_65);
5084
5184
  }), 128))])])]))]),
5085
5185
  collection.value && (viewing.value || editing.value) && !(calendarActive.value && openDay.value) ? (openBlock(), createBlock(CollectionRecordModal_default, {
5086
5186
  key: 4,
@@ -5088,7 +5188,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5088
5188
  }, {
5089
5189
  default: withCtx(() => [createVNode(CollectionRecordPanel_default, {
5090
5190
  editing: editing.value,
5091
- "onUpdate:editing": _cache[19] || (_cache[19] = ($event) => editing.value = $event),
5191
+ "onUpdate:editing": _cache[21] || (_cache[21] = ($event) => editing.value = $event),
5092
5192
  collection: collection.value,
5093
5193
  viewing: viewing.value,
5094
5194
  saving: saving.value,
@@ -5106,7 +5206,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5106
5206
  onCancel: cancelEditor,
5107
5207
  onEdit: editFromView,
5108
5208
  onClose: closeView,
5109
- onDelete: _cache[20] || (_cache[20] = ($event) => viewing.value && confirmDelete(viewing.value)),
5209
+ onDelete: _cache[22] || (_cache[22] = ($event) => viewing.value && confirmDelete(viewing.value)),
5110
5210
  onRunAction: runAction,
5111
5211
  onItemChat
5112
5212
  }, null, 8, [
@@ -5133,7 +5233,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5133
5233
  title: collection.value.title,
5134
5234
  views: customViews.value,
5135
5235
  onChanged: onViewsChanged,
5136
- onClose: _cache[21] || (_cache[21] = ($event) => configOpen.value = false)
5236
+ onClose: _cache[23] || (_cache[23] = ($event) => configOpen.value = false)
5137
5237
  }, null, 8, [
5138
5238
  "slug",
5139
5239
  "title",
@@ -5148,29 +5248,29 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5148
5248
  "data-testid": "collections-chat-modal",
5149
5249
  onClick: withModifiers(closeChat, ["self"]),
5150
5250
  onKeydown: withKeys(closeChat, ["esc"])
5151
- }, [createElementVNode("div", _hoisted_79, [
5152
- createElementVNode("header", _hoisted_80, [
5153
- _cache[48] || (_cache[48] = 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)),
5154
- createElementVNode("div", _hoisted_81, [createElementVNode("h2", _hoisted_82, toDisplayString(unref(t)("collectionsView.chatTitle")), 1), createElementVNode("span", _hoisted_83, toDisplayString(collection.value.title), 1)]),
5251
+ }, [createElementVNode("div", _hoisted_80, [
5252
+ createElementVNode("header", _hoisted_81, [
5253
+ _cache[52] || (_cache[52] = 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)),
5254
+ createElementVNode("div", _hoisted_82, [createElementVNode("h2", _hoisted_83, toDisplayString(unref(t)("collectionsView.chatTitle")), 1), createElementVNode("span", _hoisted_84, toDisplayString(collection.value.title), 1)]),
5155
5255
  createElementVNode("button", {
5156
5256
  type: "button",
5157
5257
  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",
5158
5258
  "aria-label": unref(t)("common.close"),
5159
5259
  "data-testid": "collections-chat-close",
5160
5260
  onClick: closeChat
5161
- }, [..._cache[47] || (_cache[47] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_84)
5261
+ }, [..._cache[51] || (_cache[51] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_85)
5162
5262
  ]),
5163
- createElementVNode("div", _hoisted_85, [withDirectives(createElementVNode("textarea", {
5263
+ createElementVNode("div", _hoisted_86, [withDirectives(createElementVNode("textarea", {
5164
5264
  ref_key: "chatInputEl",
5165
5265
  ref: chatInputEl,
5166
- "onUpdate:modelValue": _cache[22] || (_cache[22] = ($event) => chatMessage.value = $event),
5266
+ "onUpdate:modelValue": _cache[24] || (_cache[24] = ($event) => chatMessage.value = $event),
5167
5267
  rows: "4",
5168
5268
  placeholder: unref(t)("collectionsView.chatPlaceholder"),
5169
5269
  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",
5170
5270
  "data-testid": "collections-chat-input",
5171
5271
  onKeydown: [withKeys(withModifiers(submitChat, ["meta"]), ["enter"]), withKeys(withModifiers(submitChat, ["ctrl"]), ["enter"])]
5172
- }, null, 40, _hoisted_86), [[vModelText, chatMessage.value]])]),
5173
- createElementVNode("footer", _hoisted_87, [createElementVNode("button", {
5272
+ }, null, 40, _hoisted_87), [[vModelText, chatMessage.value]])]),
5273
+ createElementVNode("footer", _hoisted_88, [createElementVNode("button", {
5174
5274
  type: "button",
5175
5275
  class: "h-8 px-2.5 rounded text-xs font-bold text-slate-500 hover:bg-slate-200/50 transition-colors",
5176
5276
  "data-testid": "collections-chat-cancel",
@@ -5181,7 +5281,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5181
5281
  disabled: !chatMessage.value.trim(),
5182
5282
  "data-testid": "collections-chat-send",
5183
5283
  onClick: submitChat
5184
- }, toDisplayString(unref(t)("collectionsView.chatStart")), 9, _hoisted_88)])
5284
+ }, toDisplayString(unref(t)("collectionsView.chatStart")), 9, _hoisted_89)])
5185
5285
  ])], 32)) : createCommentVNode("", true)
5186
5286
  ]);
5187
5287
  };