@conduction/nextcloud-vue 2.137.0 → 2.139.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 (105) hide show
  1. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
  2. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +6 -4
  3. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  4. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  5. package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
  6. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
  7. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
  8. package/dist/esm/components/CnDetailCard/CnDetailCard.vue.js +1 -1
  9. package/dist/esm/components/CnDetailCard/CnDetailCard.vue2.js +6 -0
  10. package/dist/esm/components/CnDetailCard/CnDetailCard.vue2.js.map +1 -1
  11. package/dist/esm/components/CnDetailCard/CnDetailCard.vue3.js +24 -7
  12. package/dist/esm/components/CnDetailCard/CnDetailCard.vue3.js.map +1 -1
  13. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
  14. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +2 -0
  15. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  16. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  17. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
  18. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
  19. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
  20. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  21. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +43 -1
  22. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  23. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  24. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +133 -6
  25. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  26. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +25 -17
  27. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  28. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +2 -0
  29. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
  30. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +13 -2
  31. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
  32. package/dist/esm/components/CnMailTab/dashboardRegistration.js +4 -0
  33. package/dist/esm/components/CnMailTab/dashboardRegistration.js.map +1 -1
  34. package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue.js +1 -1
  35. package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue2.js.map +1 -1
  36. package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue3.js.map +1 -1
  37. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
  38. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +1 -1
  39. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  40. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  41. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
  42. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +2 -0
  43. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  44. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +2 -1
  45. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  46. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue.js +1 -1
  47. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js +6 -0
  48. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js.map +1 -1
  49. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js +3 -3
  50. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js.map +1 -1
  51. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  52. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +16 -0
  53. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  54. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +11 -5
  55. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  56. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue.js +1 -1
  57. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue2.js.map +1 -1
  58. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue3.js +1 -0
  59. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue3.js.map +1 -1
  60. package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue.js +1 -1
  61. package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js.map +1 -1
  62. package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js.map +1 -1
  63. package/dist/esm/composables/indexSources.js +78 -12
  64. package/dist/esm/composables/indexSources.js.map +1 -1
  65. package/dist/esm/l10n/en.json.js +12 -1
  66. package/dist/esm/l10n/en.json.js.map +1 -1
  67. package/dist/esm/l10n/nl.json.js +12 -1
  68. package/dist/esm/l10n/nl.json.js.map +1 -1
  69. package/dist/esm/library-style.js +1 -1
  70. package/dist/esm/nextcloud-vue.css +685 -512
  71. package/dist/esm/utils/resolveFilterTokens.js +9 -0
  72. package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
  73. package/dist/esm/utils/sentinelTokens.js +1 -1
  74. package/dist/esm/utils/sentinelTokens.js.map +1 -1
  75. package/dist/nextcloud-vue.cjs.js +580 -236
  76. package/dist/nextcloud-vue.cjs.js.map +2 -2
  77. package/dist/nextcloud-vue.css +685 -512
  78. package/l10n/en.json +12 -1
  79. package/l10n/nl.json +12 -1
  80. package/package.json +1 -1
  81. package/src/components/CnCellRenderer/CnCellRenderer.vue +6 -4
  82. package/src/components/CnChartWidget/CnChartWidget.vue +4 -0
  83. package/src/components/CnDetailCard/CnDetailCard.md +1 -0
  84. package/src/components/CnDetailCard/CnDetailCard.vue +25 -1
  85. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +2 -0
  86. package/src/components/CnFactsWidget/CnFactsWidget.vue +6 -4
  87. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +54 -1
  88. package/src/components/CnIndexPage/CnIndexPage.vue +135 -7
  89. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +10 -2
  90. package/src/components/CnMailTab/dashboardRegistration.js +4 -0
  91. package/src/components/CnNotificationMatrix/CnNotificationMatrix.vue +4 -0
  92. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +1 -1
  93. package/src/components/CnObjectSidebar/CnFilesTab.vue +3 -0
  94. package/src/components/CnOrderedListField/CnOrderedListField.vue +11 -1
  95. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +22 -3
  96. package/src/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue +1 -0
  97. package/src/components/CnUserSettingsDialog/CnUserSettingsDialog.vue +3 -0
  98. package/src/composables/indexSources.js +78 -12
  99. package/src/css/dialog.css +26 -0
  100. package/src/css/index-page.css +5 -0
  101. package/src/css/look-board-detail.css +36 -0
  102. package/src/css/look-board-index.css +21 -0
  103. package/src/css/look-board.css +47 -0
  104. package/src/utils/resolveFilterTokens.js +9 -0
  105. package/src/utils/sentinelTokens.js +1 -1
@@ -2,7 +2,7 @@ import script from './CnDetailCard.vue2.js';
2
2
  import { render } from './CnDetailCard.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-01384e36";
5
+ script.__scopeId = "data-v-26edbe9e";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -70,6 +70,12 @@ var script = {
70
70
  default: '',
71
71
  },
72
72
 
73
+ /** A muted line under the title, as given (translate before passing). */
74
+ subtitle: {
75
+ type: String,
76
+ default: '',
77
+ },
78
+
73
79
  /** Optional MDI icon component for the header */
74
80
  icon: {
75
81
  type: [Object, Function],
@@ -1 +1 @@
1
- {"version":3,"file":"CnDetailCard.vue2.js","sources":["../../../../src/components/CnDetailCard/CnDetailCard.vue"],"sourcesContent":["<!--\n CnDetailCard — A card container for detail page sections.\n\n Visually matches the dashboard widget card style (rounded border, header, content).\n Used inside CnDetailPage to organize entity detail information into cards.\n-->\n<template>\n\t<div\n\t\tclass=\"cn-detail-card\"\n\t\t:class=\"{ 'cn-detail-card--collapsed': isCollapsed, 'cn-detail-card--chromeless': chromeless }\">\n\t\t<!-- Header -->\n\t\t<div\n\t\t\tv-if=\"!chromeless && (title || $slots.icon)\"\n\t\t\tclass=\"cn-detail-card__header\"\n\t\t\t:class=\"{ 'cn-detail-card__header--clickable': collapsible }\"\n\t\t\t@click=\"collapsible && toggleCollapse()\">\n\t\t\t<div class=\"cn-detail-card__header-left\">\n\t\t\t\t<slot name=\"icon\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"icon\"\n\t\t\t\t\t\tv-if=\"icon\"\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\tclass=\"cn-detail-card__icon\" />\n\t\t\t\t</slot>\n\t\t\t\t<h3 class=\"cn-detail-card__title\">\n\t\t\t\t\t{{ title }}\n\t\t\t\t</h3>\n\t\t\t</div>\n\t\t\t<div class=\"cn-detail-card__header-right\">\n\t\t\t\t<CnWidgetHeaderActionButtons v-if=\"declaredHeaderActions.length > 0\" :actions=\"declaredHeaderActions\" />\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t<button\n\t\t\t\t\tv-if=\"collapsible\"\n\t\t\t\t\tclass=\"cn-detail-card__collapse-btn\"\n\t\t\t\t\t:aria-label=\"isCollapsed ? 'Expand' : 'Collapse'\">\n\t\t\t\t\t<ChevronDown\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\t:class=\"{ 'cn-detail-card__chevron--rotated': isCollapsed }\" />\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Content -->\n\t\t<div v-show=\"!isCollapsed\" class=\"cn-detail-card__content\" :class=\"{ 'cn-detail-card__content--flush': flush }\">\n\t\t\t<slot />\n\t\t</div>\n\n\t\t<!-- Footer -->\n\t\t<div v-if=\"$slots.footer\" v-show=\"!isCollapsed\" class=\"cn-detail-card__footer\">\n\t\t\t<slot name=\"footer\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport ChevronDown from 'vue-material-design-icons/ChevronDown.vue'\nimport CnWidgetHeaderActionButtons from '../CnWidgetWrapper/CnWidgetHeaderActionButtons.vue'\nimport { WIDGET_HEADER_ACTIONS } from '../../utils/widgetHeaderActions.js'\n\n/**\n * CnDetailCard — Card container for detail page sections.\n *\n * Basic usage\n * ```vue\n * <CnDetailCard title=\"Core Info\">\n * <div class=\"info-grid\">...</div>\n * </CnDetailCard>\n * ```\n *\n * With icon and actions\n * ```vue\n * <CnDetailCard title=\"Pipeline\" :icon=\"ChartIcon\">\n * <template #actions>\n * <NcButton>Edit</NcButton>\n * </template>\n * <PipelineProgress :stages=\"stages\" />\n * </CnDetailCard>\n * ```\n *\n * Collapsible\n * ```vue\n * <CnDetailCard title=\"Products\" :collapsible=\"true\">\n * <ProductList :items=\"products\" />\n * </CnDetailCard>\n * ```\n */\nexport default {\n\tname: 'CnDetailCard',\n\n\tcomponents: {\n\t\tChevronDown,\n\t\tCnWidgetHeaderActionButtons,\n\t},\n\n\tprovide() {\n\t\t// A card inside this one does not draw the widget's header actions again.\n\t\treturn { [WIDGET_HEADER_ACTIONS]: null }\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * The widget's manifest `headerActions`, resolved and provided by the\n\t\t * detail host. Null inside another card.\n\t\t */\n\t\tcnWidgetHeaderActions: { from: WIDGET_HEADER_ACTIONS, default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Render the card's content without the card: no border, no background,\n\t\t * no padding, and no header.\n\t\t *\n\t\t * For a surface that already supplies both, such as a tab panel whose\n\t\t * open tab names it. Drawing the card there nests a card inside a card\n\t\t * and shows the title twice.\n\t\t */\n\t\tchromeless: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Card header title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Optional MDI icon component for the header */\n\t\ticon: {\n\t\t\ttype: [Object, Function],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the card can be collapsed */\n\t\tcollapsible: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Initial collapsed state (only relevant when collapsible is true) */\n\t\tcollapsed: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Remove content padding — allows tables and lists to go edge-to-edge.\n\t\t */\n\t\tflush: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['update:collapsed'],\n\n\tdata() {\n\t\treturn {\n\t\t\tisCollapsed: this.collapsed,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The provided header actions, unwrapped.\n\t\t *\n\t\t * @return {Array<object>} The buttons, or none.\n\t\t * @spec openspec/changes/widget-header-actions/specs/widget-header-actions/spec.md#requirement-the-card-that-titles-a-widget-draws-its-header-actions\n\t\t */\n\t\tdeclaredHeaderActions() {\n\t\t\tconst provided = this.cnWidgetHeaderActions\n\t\t\tconst list = provided && typeof provided === 'object' && 'value' in provided ? provided.value : provided\n\t\t\treturn Array.isArray(list) ? list : []\n\t\t},\n\t},\n\n\twatch: {\n\t\tcollapsed(val) {\n\t\t\tthis.isCollapsed = val\n\t\t},\n\t},\n\n\tmethods: {\n\t\ttoggleCollapse() {\n\t\t\tthis.isCollapsed = !this.isCollapsed\n\t\t\tthis.$emit('update:collapsed', this.isCollapsed)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* Chromeless: the surface around it already draws the card and names it. */\n.cn-detail-card--chromeless {\n\tbackground: none;\n\tborder: none;\n\tborder-radius: 0;\n\tbox-shadow: none;\n\tpadding: 0;\n}\n\n.cn-detail-card {\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 12px);\n\toverflow: hidden;\n}\n\n.cn-detail-card__header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 12px 16px;\n\tborder-bottom: 1px solid var(--color-border);\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__header--clickable {\n\tcursor: pointer;\n\tuser-select: none;\n}\n\n.cn-detail-card__header--clickable:hover {\n\tbackground: var(--color-background-hover);\n}\n\n.cn-detail-card--collapsed .cn-detail-card__header {\n\tborder-bottom: none;\n}\n\n.cn-detail-card__header-left {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-detail-card__header-right {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__icon {\n\tcolor: var(--color-primary-element);\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__title {\n\tfont-weight: 600;\n\tfont-size: 14px;\n\tmargin: 0;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.cn-detail-card__collapse-btn {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tbackground: none;\n\tborder: none;\n\tpadding: 4px;\n\tcursor: pointer;\n\tcolor: var(--color-text-maxcontrast);\n\tborder-radius: var(--border-radius);\n}\n\n.cn-detail-card__collapse-btn:hover {\n\tbackground: var(--color-background-dark);\n}\n\n.cn-detail-card__chevron--rotated {\n\ttransform: rotate(-90deg);\n\ttransition: transform 0.2s ease;\n}\n\n.cn-detail-card__content {\n\tpadding: 16px;\n}\n\n.cn-detail-card__content--flush {\n\tpadding: 0;\n}\n\n.cn-detail-card__footer {\n\tpadding: 8px 16px;\n\tborder-top: 1px solid var(--color-border);\n}\n</style>\n"],"names":["CnWidgetHeaderActionButtons"],"mappings":";;;;AA2DA;;AAEC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAED,aAAe;AACd,CAAA,IAAI,EAAE,cAAc;;CAEpB,UAAU,EAAE;EACX,WAAW;+BACXA,UAA2B;EAC3B;;AAED,CAAA,OAAO,GAAG;;AAET,EAAA,OAAO,EAAE,CAAC,qBAAqB,GAAG,IAAK,EAAA;EACvC;;AAED,CAAA,MAAM,EAAE;AACP;;AAEC;;AAED,EAAA,qBAAqB,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM;EACrE;;AAED,CAAA,KAAK,EAAE;AACN;;;AAGC;;;;;EAKD,UAAU,EAAE;GACX,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;AAED;AACA,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;EACA,IAAI,EAAE;GACL,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;GACxB,OAAO,EAAE,IAAI;GACb;;AAED;EACA,WAAW,EAAE;GACZ,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;;EAGD,SAAS,EAAE;GACV,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;AAED;;;AAGA,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;EACD;;CAED,KAAK,EAAE,CAAC,kBAAkB,CAAC;;AAE3B,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;GACN,WAAW,EAAE,IAAI,CAAC,SAAS;AAC5B,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT;AACC;AACA;AACA;AACA;;EAED,qBAAqB,GAAG;AACvB,GAAA,MAAM,QAAS,GAAE,IAAI,CAAC,sBAAoB;AAC1C,GAAA,MAAM,IAAK,GAAE,QAAO,IAAK,OAAO,QAAO,KAAM,QAAO,IAAK,OAAM,IAAK,QAAS,GAAE,QAAQ,CAAC,KAAI,GAAI,SAAO;AACvG,GAAA,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAE,GAAE,IAAG,GAAI,EAAC;GACrC;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,SAAS,CAAC,GAAG,EAAE;AACd,GAAA,IAAI,CAAC,WAAY,GAAE,IAAE;GACrB;EACD;;AAED,CAAA,OAAO,EAAE;AACR,EAAA,cAAc,GAAG;AAChB,GAAA,IAAI,CAAC,WAAU,GAAI,CAAC,IAAI,CAAC,YAAU;GACnC,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE,IAAI,CAAC,WAAW,EAAA;GAC/C;EACD;AACF;;;;"}
1
+ {"version":3,"file":"CnDetailCard.vue2.js","sources":["../../../../src/components/CnDetailCard/CnDetailCard.vue"],"sourcesContent":["<!--\n CnDetailCard — A card container for detail page sections.\n\n Visually matches the dashboard widget card style (rounded border, header, content).\n Used inside CnDetailPage to organize entity detail information into cards.\n-->\n<template>\n\t<div\n\t\tclass=\"cn-detail-card\"\n\t\t:class=\"{ 'cn-detail-card--collapsed': isCollapsed, 'cn-detail-card--chromeless': chromeless }\">\n\t\t<!-- Header -->\n\t\t<div\n\t\t\tv-if=\"!chromeless && (title || $slots.icon)\"\n\t\t\tclass=\"cn-detail-card__header\"\n\t\t\t:class=\"{ 'cn-detail-card__header--clickable': collapsible }\"\n\t\t\t@click=\"collapsible && toggleCollapse()\">\n\t\t\t<div class=\"cn-detail-card__header-left\">\n\t\t\t\t<slot name=\"icon\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"icon\"\n\t\t\t\t\t\tv-if=\"icon\"\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\tclass=\"cn-detail-card__icon\" />\n\t\t\t\t</slot>\n\t\t\t\t<div v-if=\"subtitle\" class=\"cn-detail-card__heading\">\n\t\t\t\t\t<h3 class=\"cn-detail-card__title\">\n\t\t\t\t\t\t{{ title }}\n\t\t\t\t\t</h3>\n\t\t\t\t\t<span class=\"cn-detail-card__subtitle\" data-testid=\"cn-detail-card-subtitle\">{{ subtitle }}</span>\n\t\t\t\t</div>\n\t\t\t\t<h3 v-else class=\"cn-detail-card__title\">\n\t\t\t\t\t{{ title }}\n\t\t\t\t</h3>\n\t\t\t</div>\n\t\t\t<div class=\"cn-detail-card__header-right\">\n\t\t\t\t<CnWidgetHeaderActionButtons v-if=\"declaredHeaderActions.length > 0\" :actions=\"declaredHeaderActions\" />\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t<button\n\t\t\t\t\tv-if=\"collapsible\"\n\t\t\t\t\tclass=\"cn-detail-card__collapse-btn\"\n\t\t\t\t\t:aria-label=\"isCollapsed ? 'Expand' : 'Collapse'\">\n\t\t\t\t\t<ChevronDown\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\t:class=\"{ 'cn-detail-card__chevron--rotated': isCollapsed }\" />\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Content -->\n\t\t<div v-show=\"!isCollapsed\" class=\"cn-detail-card__content\" :class=\"{ 'cn-detail-card__content--flush': flush }\">\n\t\t\t<slot />\n\t\t</div>\n\n\t\t<!-- Footer -->\n\t\t<div v-if=\"$slots.footer\" v-show=\"!isCollapsed\" class=\"cn-detail-card__footer\">\n\t\t\t<slot name=\"footer\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport ChevronDown from 'vue-material-design-icons/ChevronDown.vue'\nimport CnWidgetHeaderActionButtons from '../CnWidgetWrapper/CnWidgetHeaderActionButtons.vue'\nimport { WIDGET_HEADER_ACTIONS } from '../../utils/widgetHeaderActions.js'\n\n/**\n * CnDetailCard — Card container for detail page sections.\n *\n * Basic usage\n * ```vue\n * <CnDetailCard title=\"Core Info\">\n * <div class=\"info-grid\">...</div>\n * </CnDetailCard>\n * ```\n *\n * With icon and actions\n * ```vue\n * <CnDetailCard title=\"Pipeline\" :icon=\"ChartIcon\">\n * <template #actions>\n * <NcButton>Edit</NcButton>\n * </template>\n * <PipelineProgress :stages=\"stages\" />\n * </CnDetailCard>\n * ```\n *\n * Collapsible\n * ```vue\n * <CnDetailCard title=\"Products\" :collapsible=\"true\">\n * <ProductList :items=\"products\" />\n * </CnDetailCard>\n * ```\n */\nexport default {\n\tname: 'CnDetailCard',\n\n\tcomponents: {\n\t\tChevronDown,\n\t\tCnWidgetHeaderActionButtons,\n\t},\n\n\tprovide() {\n\t\t// A card inside this one does not draw the widget's header actions again.\n\t\treturn { [WIDGET_HEADER_ACTIONS]: null }\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * The widget's manifest `headerActions`, resolved and provided by the\n\t\t * detail host. Null inside another card.\n\t\t */\n\t\tcnWidgetHeaderActions: { from: WIDGET_HEADER_ACTIONS, default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Render the card's content without the card: no border, no background,\n\t\t * no padding, and no header.\n\t\t *\n\t\t * For a surface that already supplies both, such as a tab panel whose\n\t\t * open tab names it. Drawing the card there nests a card inside a card\n\t\t * and shows the title twice.\n\t\t */\n\t\tchromeless: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Card header title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** A muted line under the title, as given (translate before passing). */\n\t\tsubtitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Optional MDI icon component for the header */\n\t\ticon: {\n\t\t\ttype: [Object, Function],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the card can be collapsed */\n\t\tcollapsible: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Initial collapsed state (only relevant when collapsible is true) */\n\t\tcollapsed: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Remove content padding — allows tables and lists to go edge-to-edge.\n\t\t */\n\t\tflush: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['update:collapsed'],\n\n\tdata() {\n\t\treturn {\n\t\t\tisCollapsed: this.collapsed,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The provided header actions, unwrapped.\n\t\t *\n\t\t * @return {Array<object>} The buttons, or none.\n\t\t * @spec openspec/changes/widget-header-actions/specs/widget-header-actions/spec.md#requirement-the-card-that-titles-a-widget-draws-its-header-actions\n\t\t */\n\t\tdeclaredHeaderActions() {\n\t\t\tconst provided = this.cnWidgetHeaderActions\n\t\t\tconst list = provided && typeof provided === 'object' && 'value' in provided ? provided.value : provided\n\t\t\treturn Array.isArray(list) ? list : []\n\t\t},\n\t},\n\n\twatch: {\n\t\tcollapsed(val) {\n\t\t\tthis.isCollapsed = val\n\t\t},\n\t},\n\n\tmethods: {\n\t\ttoggleCollapse() {\n\t\t\tthis.isCollapsed = !this.isCollapsed\n\t\t\tthis.$emit('update:collapsed', this.isCollapsed)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* Chromeless: the surface around it already draws the card and names it. */\n.cn-detail-card--chromeless {\n\tbackground: none;\n\tborder: none;\n\tborder-radius: 0;\n\tbox-shadow: none;\n\tpadding: 0;\n}\n\n.cn-detail-card {\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 12px);\n\toverflow: hidden;\n}\n\n.cn-detail-card__header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 12px 16px;\n\tborder-bottom: 1px solid var(--color-border);\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__header--clickable {\n\tcursor: pointer;\n\tuser-select: none;\n}\n\n.cn-detail-card__header--clickable:hover {\n\tbackground: var(--color-background-hover);\n}\n\n.cn-detail-card--collapsed .cn-detail-card__header {\n\tborder-bottom: none;\n}\n\n.cn-detail-card__header-left {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-detail-card__header-right {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__icon {\n\tcolor: var(--color-primary-element);\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__heading {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-detail-card__subtitle {\n\tfont-size: 13px;\n\tline-height: 1.3;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-detail-card__title {\n\tfont-weight: 600;\n\tfont-size: 14px;\n\tmargin: 0;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.cn-detail-card__collapse-btn {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tbackground: none;\n\tborder: none;\n\tpadding: 4px;\n\tcursor: pointer;\n\tcolor: var(--color-text-maxcontrast);\n\tborder-radius: var(--border-radius);\n}\n\n.cn-detail-card__collapse-btn:hover {\n\tbackground: var(--color-background-dark);\n}\n\n.cn-detail-card__chevron--rotated {\n\ttransform: rotate(-90deg);\n\ttransition: transform 0.2s ease;\n}\n\n.cn-detail-card__content {\n\tpadding: 16px;\n}\n\n.cn-detail-card__content--flush {\n\tpadding: 0;\n}\n\n.cn-detail-card__footer {\n\tpadding: 8px 16px;\n\tborder-top: 1px solid var(--color-border);\n}\n</style>\n"],"names":["CnWidgetHeaderActionButtons"],"mappings":";;;;AAiEA;;AAEC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAED,aAAe;AACd,CAAA,IAAI,EAAE,cAAc;;CAEpB,UAAU,EAAE;EACX,WAAW;+BACXA,UAA2B;EAC3B;;AAED,CAAA,OAAO,GAAG;;AAET,EAAA,OAAO,EAAE,CAAC,qBAAqB,GAAG,IAAK,EAAA;EACvC;;AAED,CAAA,MAAM,EAAE;AACP;;AAEC;;AAED,EAAA,qBAAqB,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM;EACrE;;AAED,CAAA,KAAK,EAAE;AACN;;;AAGC;;;;;EAKD,UAAU,EAAE;GACX,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;AAED;AACA,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;;AAGD,EAAA,QAAQ,EAAE;GACT,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;EACA,IAAI,EAAE;GACL,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;GACxB,OAAO,EAAE,IAAI;GACb;;AAED;EACA,WAAW,EAAE;GACZ,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;;EAGD,SAAS,EAAE;GACV,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;AAED;;;AAGA,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;EACD;;CAED,KAAK,EAAE,CAAC,kBAAkB,CAAC;;AAE3B,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;GACN,WAAW,EAAE,IAAI,CAAC,SAAS;AAC5B,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT;AACC;AACA;AACA;AACA;;EAED,qBAAqB,GAAG;AACvB,GAAA,MAAM,QAAS,GAAE,IAAI,CAAC,sBAAoB;AAC1C,GAAA,MAAM,IAAK,GAAE,QAAO,IAAK,OAAO,QAAO,KAAM,QAAO,IAAK,OAAM,IAAK,QAAS,GAAE,QAAQ,CAAC,KAAI,GAAI,SAAO;AACvG,GAAA,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAE,GAAE,IAAG,GAAI,EAAC;GACrC;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,SAAS,CAAC,GAAG,EAAE;AACd,GAAA,IAAI,CAAC,WAAY,GAAE,IAAE;GACrB;EACD;;AAED,CAAA,OAAO,EAAE;AACR,EAAA,cAAc,GAAG;AAChB,GAAA,IAAI,CAAC,WAAU,GAAI,CAAC,IAAI,CAAC,YAAU;GACnC,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE,IAAI,CAAC,WAAW,EAAA;GAC/C;EACD;AACF;;;;"}
@@ -1,10 +1,22 @@
1
1
  import { resolveComponent, openBlock, createElementBlock, normalizeClass, createElementVNode, renderSlot, createBlock, resolveDynamicComponent, createCommentVNode, toDisplayString, createVNode, withDirectives, vShow } from 'vue';
2
2
 
3
3
  const _hoisted_1 = { class: "cn-detail-card__header-left" };
4
- const _hoisted_2 = { class: "cn-detail-card__title" };
5
- const _hoisted_3 = { class: "cn-detail-card__header-right" };
6
- const _hoisted_4 = ["aria-label"];
4
+ const _hoisted_2 = {
5
+ key: 0,
6
+ class: "cn-detail-card__heading"
7
+ };
8
+ const _hoisted_3 = { class: "cn-detail-card__title" };
9
+ const _hoisted_4 = {
10
+ class: "cn-detail-card__subtitle",
11
+ "data-testid": "cn-detail-card-subtitle"
12
+ };
7
13
  const _hoisted_5 = {
14
+ key: 1,
15
+ class: "cn-detail-card__title"
16
+ };
17
+ const _hoisted_6 = { class: "cn-detail-card__header-right" };
18
+ const _hoisted_7 = ["aria-label"];
19
+ const _hoisted_8 = {
8
20
  key: 1,
9
21
  class: "cn-detail-card__footer"
10
22
  };
@@ -32,9 +44,14 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
32
44
  }))
33
45
  : createCommentVNode("v-if", true)
34
46
  ]),
35
- createElementVNode("h3", _hoisted_2, toDisplayString($props.title), 1 /* TEXT */)
47
+ ($props.subtitle)
48
+ ? (openBlock(), createElementBlock("div", _hoisted_2, [
49
+ createElementVNode("h3", _hoisted_3, toDisplayString($props.title), 1 /* TEXT */),
50
+ createElementVNode("span", _hoisted_4, toDisplayString($props.subtitle), 1 /* TEXT */)
51
+ ]))
52
+ : (openBlock(), createElementBlock("h3", _hoisted_5, toDisplayString($props.title), 1 /* TEXT */))
36
53
  ]),
37
- createElementVNode("div", _hoisted_3, [
54
+ createElementVNode("div", _hoisted_6, [
38
55
  ($options.declaredHeaderActions.length > 0)
39
56
  ? (openBlock(), createBlock(_component_CnWidgetHeaderActionButtons, {
40
57
  key: 0,
@@ -52,7 +69,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
52
69
  size: 20,
53
70
  class: normalizeClass({ 'cn-detail-card__chevron--rotated': $data.isCollapsed })
54
71
  }, null, 8 /* PROPS */, ["class"])
55
- ], 8 /* PROPS */, _hoisted_4))
72
+ ], 8 /* PROPS */, _hoisted_7))
56
73
  : createCommentVNode("v-if", true)
57
74
  ])
58
75
  ], 2 /* CLASS */))
@@ -65,7 +82,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
65
82
  [vShow, !$data.isCollapsed]
66
83
  ]),
67
84
  (_ctx.$slots.footer)
68
- ? withDirectives((openBlock(), createElementBlock("div", _hoisted_5, [
85
+ ? withDirectives((openBlock(), createElementBlock("div", _hoisted_8, [
69
86
  renderSlot(_ctx.$slots, "footer")
70
87
  ], 512 /* NEED_PATCH */)), [
71
88
  [vShow, !$data.isCollapsed]
@@ -1 +1 @@
1
- {"version":3,"file":"CnDetailCard.vue3.js","sources":["../../../../src/components/CnDetailCard/CnDetailCard.vue?vue&type=template&id=01384e36&lang.js"],"sourcesContent":["<!--\n CnDetailCard — A card container for detail page sections.\n\n Visually matches the dashboard widget card style (rounded border, header, content).\n Used inside CnDetailPage to organize entity detail information into cards.\n-->\n<template>\n\t<div\n\t\tclass=\"cn-detail-card\"\n\t\t:class=\"{ 'cn-detail-card--collapsed': isCollapsed, 'cn-detail-card--chromeless': chromeless }\">\n\t\t<!-- Header -->\n\t\t<div\n\t\t\tv-if=\"!chromeless && (title || $slots.icon)\"\n\t\t\tclass=\"cn-detail-card__header\"\n\t\t\t:class=\"{ 'cn-detail-card__header--clickable': collapsible }\"\n\t\t\t@click=\"collapsible && toggleCollapse()\">\n\t\t\t<div class=\"cn-detail-card__header-left\">\n\t\t\t\t<slot name=\"icon\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"icon\"\n\t\t\t\t\t\tv-if=\"icon\"\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\tclass=\"cn-detail-card__icon\" />\n\t\t\t\t</slot>\n\t\t\t\t<h3 class=\"cn-detail-card__title\">\n\t\t\t\t\t{{ title }}\n\t\t\t\t</h3>\n\t\t\t</div>\n\t\t\t<div class=\"cn-detail-card__header-right\">\n\t\t\t\t<CnWidgetHeaderActionButtons v-if=\"declaredHeaderActions.length > 0\" :actions=\"declaredHeaderActions\" />\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t<button\n\t\t\t\t\tv-if=\"collapsible\"\n\t\t\t\t\tclass=\"cn-detail-card__collapse-btn\"\n\t\t\t\t\t:aria-label=\"isCollapsed ? 'Expand' : 'Collapse'\">\n\t\t\t\t\t<ChevronDown\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\t:class=\"{ 'cn-detail-card__chevron--rotated': isCollapsed }\" />\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Content -->\n\t\t<div v-show=\"!isCollapsed\" class=\"cn-detail-card__content\" :class=\"{ 'cn-detail-card__content--flush': flush }\">\n\t\t\t<slot />\n\t\t</div>\n\n\t\t<!-- Footer -->\n\t\t<div v-if=\"$slots.footer\" v-show=\"!isCollapsed\" class=\"cn-detail-card__footer\">\n\t\t\t<slot name=\"footer\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport ChevronDown from 'vue-material-design-icons/ChevronDown.vue'\nimport CnWidgetHeaderActionButtons from '../CnWidgetWrapper/CnWidgetHeaderActionButtons.vue'\nimport { WIDGET_HEADER_ACTIONS } from '../../utils/widgetHeaderActions.js'\n\n/**\n * CnDetailCard — Card container for detail page sections.\n *\n * Basic usage\n * ```vue\n * <CnDetailCard title=\"Core Info\">\n * <div class=\"info-grid\">...</div>\n * </CnDetailCard>\n * ```\n *\n * With icon and actions\n * ```vue\n * <CnDetailCard title=\"Pipeline\" :icon=\"ChartIcon\">\n * <template #actions>\n * <NcButton>Edit</NcButton>\n * </template>\n * <PipelineProgress :stages=\"stages\" />\n * </CnDetailCard>\n * ```\n *\n * Collapsible\n * ```vue\n * <CnDetailCard title=\"Products\" :collapsible=\"true\">\n * <ProductList :items=\"products\" />\n * </CnDetailCard>\n * ```\n */\nexport default {\n\tname: 'CnDetailCard',\n\n\tcomponents: {\n\t\tChevronDown,\n\t\tCnWidgetHeaderActionButtons,\n\t},\n\n\tprovide() {\n\t\t// A card inside this one does not draw the widget's header actions again.\n\t\treturn { [WIDGET_HEADER_ACTIONS]: null }\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * The widget's manifest `headerActions`, resolved and provided by the\n\t\t * detail host. Null inside another card.\n\t\t */\n\t\tcnWidgetHeaderActions: { from: WIDGET_HEADER_ACTIONS, default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Render the card's content without the card: no border, no background,\n\t\t * no padding, and no header.\n\t\t *\n\t\t * For a surface that already supplies both, such as a tab panel whose\n\t\t * open tab names it. Drawing the card there nests a card inside a card\n\t\t * and shows the title twice.\n\t\t */\n\t\tchromeless: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Card header title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Optional MDI icon component for the header */\n\t\ticon: {\n\t\t\ttype: [Object, Function],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the card can be collapsed */\n\t\tcollapsible: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Initial collapsed state (only relevant when collapsible is true) */\n\t\tcollapsed: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Remove content padding — allows tables and lists to go edge-to-edge.\n\t\t */\n\t\tflush: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['update:collapsed'],\n\n\tdata() {\n\t\treturn {\n\t\t\tisCollapsed: this.collapsed,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The provided header actions, unwrapped.\n\t\t *\n\t\t * @return {Array<object>} The buttons, or none.\n\t\t * @spec openspec/changes/widget-header-actions/specs/widget-header-actions/spec.md#requirement-the-card-that-titles-a-widget-draws-its-header-actions\n\t\t */\n\t\tdeclaredHeaderActions() {\n\t\t\tconst provided = this.cnWidgetHeaderActions\n\t\t\tconst list = provided && typeof provided === 'object' && 'value' in provided ? provided.value : provided\n\t\t\treturn Array.isArray(list) ? list : []\n\t\t},\n\t},\n\n\twatch: {\n\t\tcollapsed(val) {\n\t\t\tthis.isCollapsed = val\n\t\t},\n\t},\n\n\tmethods: {\n\t\ttoggleCollapse() {\n\t\t\tthis.isCollapsed = !this.isCollapsed\n\t\t\tthis.$emit('update:collapsed', this.isCollapsed)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* Chromeless: the surface around it already draws the card and names it. */\n.cn-detail-card--chromeless {\n\tbackground: none;\n\tborder: none;\n\tborder-radius: 0;\n\tbox-shadow: none;\n\tpadding: 0;\n}\n\n.cn-detail-card {\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 12px);\n\toverflow: hidden;\n}\n\n.cn-detail-card__header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 12px 16px;\n\tborder-bottom: 1px solid var(--color-border);\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__header--clickable {\n\tcursor: pointer;\n\tuser-select: none;\n}\n\n.cn-detail-card__header--clickable:hover {\n\tbackground: var(--color-background-hover);\n}\n\n.cn-detail-card--collapsed .cn-detail-card__header {\n\tborder-bottom: none;\n}\n\n.cn-detail-card__header-left {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-detail-card__header-right {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__icon {\n\tcolor: var(--color-primary-element);\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__title {\n\tfont-weight: 600;\n\tfont-size: 14px;\n\tmargin: 0;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.cn-detail-card__collapse-btn {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tbackground: none;\n\tborder: none;\n\tpadding: 4px;\n\tcursor: pointer;\n\tcolor: var(--color-text-maxcontrast);\n\tborder-radius: var(--border-radius);\n}\n\n.cn-detail-card__collapse-btn:hover {\n\tbackground: var(--color-background-dark);\n}\n\n.cn-detail-card__chevron--rotated {\n\ttransform: rotate(-90deg);\n\ttransition: transform 0.2s ease;\n}\n\n.cn-detail-card__content {\n\tpadding: 16px;\n}\n\n.cn-detail-card__content--flush {\n\tpadding: 0;\n}\n\n.cn-detail-card__footer {\n\tpadding: 8px 16px;\n\tborder-top: 1px solid var(--color-border);\n}\n</style>\n"],"names":["_normalizeClass","_createElementBlock","_renderSlot","_openBlock","_createBlock","_resolveDynamicComponent","_createElementVNode","_toDisplayString"],"mappings":";;AAsBQ,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,6BAAsB,GAAA;AAQ5B,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,uBAAY,GAAA;AAIlB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,8BAA8B,GAAA;;;;;;;;;;;;SApBrC,EAACA,cAAA,CAAA,CAAA,gBAAgB,EACiB,EAAA,2BAAA,EAAA,KAAA,CAAA,WAAE,gCAAA,MAAA,CAAA,UAAA,EAAA,CAAA,CAAA;;AAGjC,IAAA,CAAA,CAAA,MAAA,CAAA,UAAI,KAAA,MAAA,CAAA,KAAA,IAAA,IAAA,CAAA,MAAA,CAAA,IAAA,CAAA;sBADVC;;UAEE,KAAE,EAAAD,cAAA,CAAA,CAAC,wBAAM,EAAA,EAAA,mCAAA,EACC,MAAA,CAAA,WAAA,EAAA,CAAA,CAAA;UACV,OAAG,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAE,MAAI,CAAA,WAAA,IAAA,QAAA,CAAA,cAAA,EAAA,CAAA,CAAA;;6BAYN,iBAAA,EAAA;AAVL,YAAAE,UAAA,CAMO,yBANP,MAMO;eAHH,MAAA,CAAA,IAAA;AAFH,mBAAAC,SAAA,EAAA,EAAAC,WAAA,CAIgCC,wBAH1B,MAAI,CAAA,IAAA,CAAA,EAAA;;AAER,oBAAA,IAAC,EAAA,EAAA;AACF,oBAAA,KAAK,EAAC,sBAAsB;;;;YAE9BC,kBAEK,CAAA,IAAA,EAFL,UAEK,EAAAC,eAAA,CADD,MAAE,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;;AAGL,UAAAD,kBAAA,CAWE,OAXF,UAWE,EAAA;AAVS,YAAA,CAAA,QAAA,CAAA,qBAAA,CAAA,MAAA,GAAA,CAAA;yCAAA,CAAA,sCAAA,EAAA;;AAAA,kBAAA,OAAA,EAAA,QAAA,CAAA,qBAAA;;;YACVJ,UAAS,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,CAAA;aAEJ,MAAC,CAAA,WAAA;gDAMF,CAAA,QAAA,EAAA;;AALL,kBAAA,KAAG,EAAA,8BAAA;AACF,kBAAA,YAAC,EAAA,KAAA,CAAA,WAAA,GAAA,QAAA,GAAA,UAAA;;6BAG8D,CAAA,sBAAA,EAAA;AAD9D,oBAAA,IAAI,EAAE,EAAE;AACR,oBAAA,KAAK,uDAAwC,KAAW,CAAA,WAAA,EAAA,CAAA;;;;;;;mBAM5DI,kBAEG,CAAA,KAAA,EAAA;MAFkB,KAAA,EAAAN,cAAA,CAAA,CAAA,yBAAA,EAAA,EAAA,gCAAA,EAAA,MAAA,CAAA,KAAA,EAAA,CAAA,CAAA;;MACrBE,UAAI,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,CAAA;;eADS,KAAQ,CAAA,WAAA,CAAA;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"CnDetailCard.vue3.js","sources":["../../../../src/components/CnDetailCard/CnDetailCard.vue?vue&type=template&id=26edbe9e&lang.js"],"sourcesContent":["<!--\n CnDetailCard — A card container for detail page sections.\n\n Visually matches the dashboard widget card style (rounded border, header, content).\n Used inside CnDetailPage to organize entity detail information into cards.\n-->\n<template>\n\t<div\n\t\tclass=\"cn-detail-card\"\n\t\t:class=\"{ 'cn-detail-card--collapsed': isCollapsed, 'cn-detail-card--chromeless': chromeless }\">\n\t\t<!-- Header -->\n\t\t<div\n\t\t\tv-if=\"!chromeless && (title || $slots.icon)\"\n\t\t\tclass=\"cn-detail-card__header\"\n\t\t\t:class=\"{ 'cn-detail-card__header--clickable': collapsible }\"\n\t\t\t@click=\"collapsible && toggleCollapse()\">\n\t\t\t<div class=\"cn-detail-card__header-left\">\n\t\t\t\t<slot name=\"icon\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"icon\"\n\t\t\t\t\t\tv-if=\"icon\"\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\tclass=\"cn-detail-card__icon\" />\n\t\t\t\t</slot>\n\t\t\t\t<div v-if=\"subtitle\" class=\"cn-detail-card__heading\">\n\t\t\t\t\t<h3 class=\"cn-detail-card__title\">\n\t\t\t\t\t\t{{ title }}\n\t\t\t\t\t</h3>\n\t\t\t\t\t<span class=\"cn-detail-card__subtitle\" data-testid=\"cn-detail-card-subtitle\">{{ subtitle }}</span>\n\t\t\t\t</div>\n\t\t\t\t<h3 v-else class=\"cn-detail-card__title\">\n\t\t\t\t\t{{ title }}\n\t\t\t\t</h3>\n\t\t\t</div>\n\t\t\t<div class=\"cn-detail-card__header-right\">\n\t\t\t\t<CnWidgetHeaderActionButtons v-if=\"declaredHeaderActions.length > 0\" :actions=\"declaredHeaderActions\" />\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t<button\n\t\t\t\t\tv-if=\"collapsible\"\n\t\t\t\t\tclass=\"cn-detail-card__collapse-btn\"\n\t\t\t\t\t:aria-label=\"isCollapsed ? 'Expand' : 'Collapse'\">\n\t\t\t\t\t<ChevronDown\n\t\t\t\t\t\t:size=\"20\"\n\t\t\t\t\t\t:class=\"{ 'cn-detail-card__chevron--rotated': isCollapsed }\" />\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Content -->\n\t\t<div v-show=\"!isCollapsed\" class=\"cn-detail-card__content\" :class=\"{ 'cn-detail-card__content--flush': flush }\">\n\t\t\t<slot />\n\t\t</div>\n\n\t\t<!-- Footer -->\n\t\t<div v-if=\"$slots.footer\" v-show=\"!isCollapsed\" class=\"cn-detail-card__footer\">\n\t\t\t<slot name=\"footer\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport ChevronDown from 'vue-material-design-icons/ChevronDown.vue'\nimport CnWidgetHeaderActionButtons from '../CnWidgetWrapper/CnWidgetHeaderActionButtons.vue'\nimport { WIDGET_HEADER_ACTIONS } from '../../utils/widgetHeaderActions.js'\n\n/**\n * CnDetailCard — Card container for detail page sections.\n *\n * Basic usage\n * ```vue\n * <CnDetailCard title=\"Core Info\">\n * <div class=\"info-grid\">...</div>\n * </CnDetailCard>\n * ```\n *\n * With icon and actions\n * ```vue\n * <CnDetailCard title=\"Pipeline\" :icon=\"ChartIcon\">\n * <template #actions>\n * <NcButton>Edit</NcButton>\n * </template>\n * <PipelineProgress :stages=\"stages\" />\n * </CnDetailCard>\n * ```\n *\n * Collapsible\n * ```vue\n * <CnDetailCard title=\"Products\" :collapsible=\"true\">\n * <ProductList :items=\"products\" />\n * </CnDetailCard>\n * ```\n */\nexport default {\n\tname: 'CnDetailCard',\n\n\tcomponents: {\n\t\tChevronDown,\n\t\tCnWidgetHeaderActionButtons,\n\t},\n\n\tprovide() {\n\t\t// A card inside this one does not draw the widget's header actions again.\n\t\treturn { [WIDGET_HEADER_ACTIONS]: null }\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * The widget's manifest `headerActions`, resolved and provided by the\n\t\t * detail host. Null inside another card.\n\t\t */\n\t\tcnWidgetHeaderActions: { from: WIDGET_HEADER_ACTIONS, default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Render the card's content without the card: no border, no background,\n\t\t * no padding, and no header.\n\t\t *\n\t\t * For a surface that already supplies both, such as a tab panel whose\n\t\t * open tab names it. Drawing the card there nests a card inside a card\n\t\t * and shows the title twice.\n\t\t */\n\t\tchromeless: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Card header title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** A muted line under the title, as given (translate before passing). */\n\t\tsubtitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Optional MDI icon component for the header */\n\t\ticon: {\n\t\t\ttype: [Object, Function],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the card can be collapsed */\n\t\tcollapsible: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Initial collapsed state (only relevant when collapsible is true) */\n\t\tcollapsed: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Remove content padding — allows tables and lists to go edge-to-edge.\n\t\t */\n\t\tflush: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['update:collapsed'],\n\n\tdata() {\n\t\treturn {\n\t\t\tisCollapsed: this.collapsed,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The provided header actions, unwrapped.\n\t\t *\n\t\t * @return {Array<object>} The buttons, or none.\n\t\t * @spec openspec/changes/widget-header-actions/specs/widget-header-actions/spec.md#requirement-the-card-that-titles-a-widget-draws-its-header-actions\n\t\t */\n\t\tdeclaredHeaderActions() {\n\t\t\tconst provided = this.cnWidgetHeaderActions\n\t\t\tconst list = provided && typeof provided === 'object' && 'value' in provided ? provided.value : provided\n\t\t\treturn Array.isArray(list) ? list : []\n\t\t},\n\t},\n\n\twatch: {\n\t\tcollapsed(val) {\n\t\t\tthis.isCollapsed = val\n\t\t},\n\t},\n\n\tmethods: {\n\t\ttoggleCollapse() {\n\t\t\tthis.isCollapsed = !this.isCollapsed\n\t\t\tthis.$emit('update:collapsed', this.isCollapsed)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* Chromeless: the surface around it already draws the card and names it. */\n.cn-detail-card--chromeless {\n\tbackground: none;\n\tborder: none;\n\tborder-radius: 0;\n\tbox-shadow: none;\n\tpadding: 0;\n}\n\n.cn-detail-card {\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 12px);\n\toverflow: hidden;\n}\n\n.cn-detail-card__header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 12px 16px;\n\tborder-bottom: 1px solid var(--color-border);\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__header--clickable {\n\tcursor: pointer;\n\tuser-select: none;\n}\n\n.cn-detail-card__header--clickable:hover {\n\tbackground: var(--color-background-hover);\n}\n\n.cn-detail-card--collapsed .cn-detail-card__header {\n\tborder-bottom: none;\n}\n\n.cn-detail-card__header-left {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-detail-card__header-right {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__icon {\n\tcolor: var(--color-primary-element);\n\tflex-shrink: 0;\n}\n\n.cn-detail-card__heading {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-detail-card__subtitle {\n\tfont-size: 13px;\n\tline-height: 1.3;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-detail-card__title {\n\tfont-weight: 600;\n\tfont-size: 14px;\n\tmargin: 0;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.cn-detail-card__collapse-btn {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tbackground: none;\n\tborder: none;\n\tpadding: 4px;\n\tcursor: pointer;\n\tcolor: var(--color-text-maxcontrast);\n\tborder-radius: var(--border-radius);\n}\n\n.cn-detail-card__collapse-btn:hover {\n\tbackground: var(--color-background-dark);\n}\n\n.cn-detail-card__chevron--rotated {\n\ttransform: rotate(-90deg);\n\ttransition: transform 0.2s ease;\n}\n\n.cn-detail-card__content {\n\tpadding: 16px;\n}\n\n.cn-detail-card__content--flush {\n\tpadding: 0;\n}\n\n.cn-detail-card__footer {\n\tpadding: 8px 16px;\n\tborder-top: 1px solid var(--color-border);\n}\n</style>\n"],"names":["_normalizeClass","_createElementBlock","_renderSlot","_openBlock","_createBlock","_resolveDynamicComponent","_createElementVNode","_toDisplayString"],"mappings":";;AAsBQ,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,6BAAsB,GAAA;;;AAQX,EAAA,KAAK,EAAC,yBAAa;;AACnC,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,uBAAA,GAAA;;AAGJ,EAAA,KAAK,EAAC,0BAA0B;AAAC,EAAA,aAAA,EAAA,yBAAA;;;;AAE7B,EAAA,KAAK,EAAC,uBAAK;;AAIlB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,8BAA8B,GAAA;;;;;;;;;;;;SA1BrC,EAACA,cAAA,CAAA,CAAA,gBAAgB,EACiB,EAAA,2BAAA,EAAA,KAAA,CAAA,WAAE,gCAAA,MAAA,CAAA,UAAA,EAAA,CAAA,CAAA;;AAGjC,IAAA,CAAA,CAAA,MAAA,CAAA,UAAI,KAAA,MAAA,CAAA,KAAA,IAAA,IAAA,CAAA,MAAA,CAAA,IAAA,CAAA;sBADVC;;UAEE,KAAE,EAAAD,cAAA,CAAA,CAAC,wBAAM,EAAA,EAAA,mCAAA,EACC,MAAA,CAAA,WAAA,EAAA,CAAA,CAAA;UACV,OAAG,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAE,MAAI,CAAA,WAAA,IAAA,QAAA,CAAA,cAAA,EAAA,CAAA,CAAA;;6BAkBN,iBAAA,EAAA;AAhBL,YAAAE,UAAA,CAMK,yBANL,MAMK;eAHG,MAAI,CAAA,IAAA;AAFX,mBAAAC,SAAA,EAAA,EAAAC,WAAA,CAIgCC,wBAH1B,MAAI,CAAA,IAAA,CAAA,EAAA;;AAER,oBAAA,IAAE,EAAA,EAAA;AACH,oBAAA,KAAK,EAAC,sBAAsB;;;;aAEnB,MAAQ,CAAA,QAAA;AAAnB,iBAAAF,SAAA,EAAA,EAAAF,kBAAA,CAKM,OALN,UAKM,EAAA;kBAJLK,kBAEG,CAAA,IAAA,EAFH,UAEG,EAAAC,eAAA,CADA,MAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;kBAEHD,kBAAuC,CAAA,MAAA,EAAvC,UAAuC,EAAAC,eAAA,CAAA,MAAA,CAAA,QAAA,CAAA,EAAA,CAAA,YAAA;;8BAExCN,kBAEK,CAAA,IAAA,EAFL,UAEK,EAAAM,eAAA,CADD,MAAE,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA,CAAA;;AAGL,UAAAD,kBAAA,CAWE,OAXF,UAWE,EAAA;AAVS,YAAA,CAAA,QAAA,CAAA,qBAAA,CAAA,MAAA,GAAA,CAAA;yCAAA,CAAA,sCAAA,EAAA;;AAAA,kBAAA,OAAA,EAAA,QAAA,CAAA,qBAAA;;;YACVJ,UAAS,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,CAAA;aAEJ,MAAC,CAAA,WAAA;gDAMF,CAAA,QAAA,EAAA;;AALL,kBAAA,KAAG,EAAA,8BAAA;AACF,kBAAA,YAAC,EAAA,KAAA,CAAA,WAAA,GAAA,QAAA,GAAA,UAAA;;6BAG8D,CAAA,sBAAA,EAAA;AAD9D,oBAAA,IAAI,EAAE,EAAE;AACR,oBAAA,KAAK,uDAAwC,KAAW,CAAA,WAAA,EAAA,CAAA;;;;;;;mBAM5DI,kBAEG,CAAA,KAAA,EAAA;MAFkB,KAAA,EAAAN,cAAA,CAAA,CAAA,yBAAA,EAAA,EAAA,gCAAA,EAAA,MAAA,CAAA,KAAA,EAAA,CAAA,CAAA;;MACrBE,UAAI,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,CAAA;;eADS,KAAQ,CAAA,WAAA,CAAA;;;;;;;;;;;;;;"}
@@ -2,7 +2,7 @@ import script from './CnDetailWidgetHost.vue2.js';
2
2
  import { render } from './CnDetailWidgetHost.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-32a82d6a";
5
+ script.__scopeId = "data-v-10c797a6";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -877,6 +877,7 @@ var script = {
877
877
  objectId: this.objectId,
878
878
  object: this.object,
879
879
  config: unwrapAppConfig(this.cnAppConfig),
880
+ context: (this.cnDetailVisibilityRows && this.cnDetailVisibilityRows.value) || null,
880
881
  })
881
882
  },
882
883
 
@@ -943,6 +944,7 @@ var script = {
943
944
  // prints its title as given.
944
945
  title: this.translateLabel(this.widget?.title || ''),
945
946
  ...this.leafTitleLabel,
947
+ ...(this.widgetSubtitle ? { subtitle: this.translateLabel(this.widgetSubtitle) } : {}),
946
948
  // A provider opting into `bareWidget` is being rendered where the
947
949
  // tab strip already supplies the card and the title, so tell it to
948
950
  // drop its own. Without this the panel gets a titled card inside