@conduction/nextcloud-vue 2.63.0 → 2.65.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 (111) hide show
  1. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +253 -10
  2. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  3. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +139 -46
  4. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +87 -0
  6. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  7. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +26 -24
  8. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  9. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +61 -16
  10. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
  11. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
  12. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +20 -0
  13. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
  14. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +3 -2
  15. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
  16. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js +13 -0
  17. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js.map +1 -1
  18. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js +2 -1
  19. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js.map +1 -1
  20. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +33 -2
  21. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  22. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  23. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +55 -2
  24. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  25. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +153 -133
  26. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  27. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +37 -1
  28. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  29. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +12 -4
  30. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  31. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +125 -14
  32. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  33. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +87 -40
  34. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  35. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +101 -7
  36. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
  37. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +22 -5
  38. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
  39. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -0
  40. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  41. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -2
  42. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  43. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +5 -1
  44. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  45. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
  46. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  47. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +63 -2
  48. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
  49. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js +96 -37
  50. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
  51. package/dist/esm/components/CnStagesWidget/stagesModel.js +5 -2
  52. package/dist/esm/components/CnStagesWidget/stagesModel.js.map +1 -1
  53. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +74 -5
  54. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  55. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +15 -8
  56. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  57. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +14 -2
  58. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  59. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +2 -1
  60. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  61. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +73 -1
  62. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
  63. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +14 -2
  64. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
  65. package/dist/esm/l10n/en.json.js +2 -1
  66. package/dist/esm/l10n/en.json.js.map +1 -1
  67. package/dist/esm/l10n/nl.json.js +2 -1
  68. package/dist/esm/l10n/nl.json.js.map +1 -1
  69. package/dist/esm/nextcloud-vue.css +495 -81
  70. package/dist/esm/store/useObjectStore.js +118 -33
  71. package/dist/esm/store/useObjectStore.js.map +1 -1
  72. package/dist/esm/utils/actionsDispatcher.js +14 -0
  73. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  74. package/dist/esm/utils/schemaRefSlug.js +19 -3
  75. package/dist/esm/utils/schemaRefSlug.js.map +1 -1
  76. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  77. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  78. package/dist/nextcloud-vue.cjs.js +7388 -6021
  79. package/dist/nextcloud-vue.cjs.js.map +2 -2
  80. package/dist/nextcloud-vue.css +495 -81
  81. package/l10n/en.json +2 -0
  82. package/l10n/nl.json +2 -0
  83. package/package.json +1 -1
  84. package/src/components/CnAppNav/CnAppNav.vue +441 -14
  85. package/src/components/CnAppRoot/CnAppRoot.md +4 -0
  86. package/src/components/CnAppRoot/CnAppRoot.vue +94 -1
  87. package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +61 -16
  88. package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +22 -1
  89. package/src/components/CnBreadcrumbs/CnBreadcrumbs.vue +14 -0
  90. package/src/components/CnCellRenderer/CnCellRenderer.vue +33 -2
  91. package/src/components/CnDashboardPage/CnDashboardPage.vue +72 -4
  92. package/src/components/CnDataTable/CnDataTable.vue +45 -1
  93. package/src/components/CnDetailPage/CnDetailPage.md +8 -0
  94. package/src/components/CnDetailPage/CnDetailPage.vue +169 -2
  95. package/src/components/CnHeaderWidget/CnHeaderWidget.vue +147 -9
  96. package/src/components/CnIndexPage/CnIndexPage.vue +32 -2
  97. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +7 -1
  98. package/src/components/CnStagesWidget/CnStagesWidget.vue +189 -2
  99. package/src/components/CnStagesWidget/stagesModel.js +5 -2
  100. package/src/components/CnStatWidget/CnStatWidget.vue +89 -7
  101. package/src/components/CnTabsWidget/CnTabsWidget.vue +15 -2
  102. package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +4 -0
  103. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +107 -1
  104. package/src/css/detail-page.css +32 -4
  105. package/src/css/kpi-card.css +71 -1
  106. package/src/css/table.css +18 -6
  107. package/src/schemas/app-manifest-v2.schema.json +134 -3
  108. package/src/store/useObjectStore.js +118 -33
  109. package/src/utils/actionsDispatcher.js +14 -0
  110. package/src/utils/schemaRefSlug.js +19 -3
  111. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -185,7 +185,7 @@
185
185
  .cn-data-table th,
186
186
  .cn-data-table td {
187
187
  padding: calc(3 * var(--default-grid-baseline));
188
- text-align: left;
188
+ text-align: start;
189
189
  border-bottom: 1px solid var(--color-border);
190
190
  vertical-align: middle;
191
191
  max-width: var(--cn-table-cell-max-width, 22rem);
@@ -204,6 +204,18 @@
204
204
  white-space: normal;
205
205
  }
206
206
 
207
+ /* The secondary line of a cell (`columns[].secondary`): muted, smaller, on its
208
+ own line under the value. Theme hooks: --cn-table-secondary-size and
209
+ --cn-table-secondary-color. */
210
+ .cn-data-table .cn-table-cell__secondary {
211
+ display: block;
212
+ color: var(--cn-table-secondary-color, var(--color-text-maxcontrast));
213
+ font-size: var(--cn-table-secondary-size, 0.9em);
214
+ line-height: 1.35;
215
+ overflow: hidden;
216
+ text-overflow: ellipsis;
217
+ }
218
+
207
219
  /* Back to wrapping, for a column holding prose rather than a label:
208
220
  `columns: [{ key: 'description', cellClass: 'cn-cell--wrap' }]`. */
209
221
  .cn-data-table th.cn-cell--wrap,
@@ -265,7 +277,7 @@
265
277
  }
266
278
 
267
279
  .cn-data-table td.cn-cell--end {
268
- text-align: right;
280
+ text-align: end;
269
281
  white-space: nowrap;
270
282
  }
271
283
 
@@ -303,7 +315,7 @@
303
315
  }
304
316
 
305
317
  .cn-table-sort-indicator {
306
- margin-left: var(--default-grid-baseline);
318
+ margin-inline-start: var(--default-grid-baseline);
307
319
  opacity: 0.6;
308
320
  }
309
321
 
@@ -413,7 +425,7 @@
413
425
  justify-content: center;
414
426
  min-width: 14px;
415
427
  height: 14px;
416
- margin-left: 2px;
428
+ margin-inline-start: 2px;
417
429
  padding: 0 3px;
418
430
  border-radius: 7px;
419
431
  background-color: var(--color-primary-element);
@@ -478,7 +490,7 @@
478
490
 
479
491
  .cn-table-col--icon {
480
492
  width: 40px;
481
- padding-right: 0;
493
+ padding-inline-end: 0;
482
494
  text-align: center;
483
495
  color: var(--color-text-maxcontrast);
484
496
  }
@@ -541,7 +553,7 @@
541
553
 
542
554
  .viewTable { width: 100%; border-collapse: collapse; background-color: var(--color-main-background); }
543
555
 
544
- .viewTable th, .viewTable td { padding: calc(3 * var(--default-grid-baseline)); text-align: left; border-bottom: 1px solid var(--color-border); vertical-align: middle; }
556
+ .viewTable th, .viewTable td { padding: calc(3 * var(--default-grid-baseline)); text-align: start; border-bottom: 1px solid var(--color-border); vertical-align: middle; }
545
557
 
546
558
  .viewTable th { background: var(--color-background-hover); font-weight: 500; color: var(--color-text-maxcontrast); background-color: var(--color-background-dark); }
547
559
 
@@ -1037,7 +1049,7 @@
1037
1049
  padding: var(--cn-kpi-padding-flat, 8px);
1038
1050
  box-sizing: border-box;
1039
1051
  overflow: hidden;
1040
- text-align: left;
1052
+ text-align: start;
1041
1053
  text-decoration: none;
1042
1054
  color: inherit;
1043
1055
  background: transparent;
@@ -1152,6 +1164,29 @@
1152
1164
  white-space: nowrap;
1153
1165
  }
1154
1166
 
1167
+ /* A caption coloured by a rule (`captionVariant` / `overrides[].captionVariant`):
1168
+ "1 due today" in the error colour. Foreground tokens, which stay readable in
1169
+ dark mode. */
1170
+ .cn-kpi-card__label--primary {
1171
+ color: var(--color-primary-element);
1172
+ font-weight: 600;
1173
+ }
1174
+
1175
+ .cn-kpi-card__label--success {
1176
+ color: var(--color-text-success, var(--color-success-text));
1177
+ font-weight: 600;
1178
+ }
1179
+
1180
+ .cn-kpi-card__label--warning {
1181
+ color: var(--color-element-warning, var(--color-warning-text));
1182
+ font-weight: 600;
1183
+ }
1184
+
1185
+ .cn-kpi-card__label--error {
1186
+ color: var(--color-text-error, var(--color-error-text));
1187
+ font-weight: 600;
1188
+ }
1189
+
1155
1190
  /* Semantic variants. Each re-points the ONE accent token, so the icon tint
1156
1191
  and the number move together by construction — there is no second place to
1157
1192
  forget. The inline KPI below shares the same modifiers for the same reason:
@@ -1248,6 +1283,53 @@
1248
1283
  font-size: var(--cn-kpi-value-size-stacked, 2rem);
1249
1284
  }
1250
1285
 
1286
+ /* Stacked: the board's tile (`content.layout: 'stacked'`). A plain muted
1287
+ label, the number at 34px/700 in the text colour, and the caption on a line
1288
+ of its own; CnStatWidget draws no icon circle in this layout. The padding
1289
+ adds up with a dashboard card-fit cell's 8px 14px to the board's 18px 20px.
1290
+ Every value is a token so a theme can move it. */
1291
+ .cn-kpi-card--stacked {
1292
+ flex-direction: column;
1293
+ align-items: stretch;
1294
+ justify-content: center;
1295
+ gap: 0;
1296
+ padding: var(--cn-kpi-stacked-padding, 10px 6px);
1297
+ }
1298
+
1299
+ .cn-kpi-card--stacked .cn-kpi-card__body {
1300
+ gap: var(--cn-kpi-stacked-gap, 6px);
1301
+ }
1302
+
1303
+ .cn-kpi-card--stacked .cn-kpi-card__title {
1304
+ font-size: var(--cn-kpi-stacked-title-size, 14px);
1305
+ font-weight: var(--cn-kpi-stacked-title-weight, 400);
1306
+ color: var(--color-text-maxcontrast);
1307
+ }
1308
+
1309
+ .cn-kpi-card--stacked .cn-kpi-card__value {
1310
+ font-size: var(--cn-kpi-stacked-value-size, 34px);
1311
+ font-weight: var(--cn-kpi-value-weight, 700);
1312
+ line-height: 1;
1313
+ letter-spacing: -0.01em;
1314
+ color: var(--cn-kpi-stacked-value-color, var(--color-main-text));
1315
+ }
1316
+
1317
+ .cn-kpi-card--stacked .cn-kpi-card__caption-line {
1318
+ flex: 0 0 auto;
1319
+ max-width: 100%;
1320
+ font-size: var(--cn-kpi-label-size, 13px);
1321
+ font-weight: 500;
1322
+ }
1323
+
1324
+ /* A linked stacked tile reads as a tile, not as underlined link text. The
1325
+ NL Design theme underlines every `a` with `!important`, so the opt-out
1326
+ needs it too; it only applies to this opt-in layout. */
1327
+ a.cn-kpi-card--stacked,
1328
+ a.cn-kpi-card--stacked:hover,
1329
+ a.cn-kpi-card--stacked:focus-visible {
1330
+ text-decoration: none !important;
1331
+ }
1332
+
1251
1333
  /* Filled: the card draws its own grey box, for a KPI that is NOT already
1252
1334
  inside a wrapper that draws one. Opt-in via `content.flat: false`. */
1253
1335
  .cn-kpi-card--filled {
@@ -2724,6 +2806,12 @@
2724
2806
  position: relative;
2725
2807
  }
2726
2808
 
2809
+ /* The breadcrumb line above the header (`config.breadcrumb`). */
2810
+ .cn-detail-page__breadcrumbs {
2811
+ margin-bottom: calc(2 * var(--default-grid-baseline));
2812
+ color: var(--color-text-maxcontrast);
2813
+ }
2814
+
2727
2815
  /* Header */
2728
2816
  .cn-detail-page__header {
2729
2817
  display: flex;
@@ -2749,6 +2837,28 @@
2749
2837
  min-width: 0;
2750
2838
  }
2751
2839
 
2840
+ /* A widget in the header (`config.headerWidget`) takes a row of its own under
2841
+ the title and the actions. */
2842
+ .cn-detail-page__header--with-widget {
2843
+ flex-wrap: wrap;
2844
+ row-gap: var(--cn-detail-header-row-gap, 22px);
2845
+ }
2846
+
2847
+ .cn-detail-page__header-widget {
2848
+ flex: 1 0 100%;
2849
+ min-width: 0;
2850
+ }
2851
+
2852
+ /* The header as a card (`config.headerCard`): the board's case header, a
2853
+ bordered box on the surface colour. The 56px inset that clears the
2854
+ navigation toggle is not needed inside a card that starts below it. */
2855
+ .cn-detail-page__header--card {
2856
+ padding: var(--cn-detail-header-card-padding, 22px 24px);
2857
+ border: 1px solid var(--color-border);
2858
+ border-radius: var(--cn-detail-header-card-radius, 12px);
2859
+ background: var(--color-main-background);
2860
+ }
2861
+
2752
2862
  .cn-detail-page__header-left {
2753
2863
  display: flex;
2754
2864
  align-items: center;
@@ -2891,7 +3001,7 @@
2891
3001
 
2892
3002
  .cn-detail-page__stats-table thead th {
2893
3003
  padding: calc(1.5 * var(--default-grid-baseline)) calc(2 * var(--default-grid-baseline));
2894
- text-align: left;
3004
+ text-align: start;
2895
3005
  font-weight: 600;
2896
3006
  font-size: 0.9em;
2897
3007
  color: var(--color-text-maxcontrast);
@@ -2916,7 +3026,7 @@
2916
3026
  }
2917
3027
 
2918
3028
  .cn-detail-page__stats-cell--indented {
2919
- padding-left: calc(5 * var(--default-grid-baseline)) !important;
3029
+ padding-inline-start: calc(5 * var(--default-grid-baseline)) !important;
2920
3030
  }
2921
3031
 
2922
3032
  .cn-detail-page__stats-cell--center {
@@ -2924,7 +3034,7 @@
2924
3034
  }
2925
3035
 
2926
3036
  .cn-detail-page__stats-cell--right {
2927
- text-align: right;
3037
+ text-align: end;
2928
3038
  }
2929
3039
 
2930
3040
  /* Body & content */
@@ -3058,7 +3168,7 @@
3058
3168
 
3059
3169
  .cn-detail-page__sidebar-toggle {
3060
3170
  position: fixed;
3061
- right: calc(5 * var(--default-grid-baseline));
3171
+ inset-inline-end: calc(5 * var(--default-grid-baseline));
3062
3172
  top: 80px;
3063
3173
  z-index: 10;
3064
3174
  }
@@ -6463,7 +6573,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6463
6573
  .cn-data-table th,
6464
6574
  .cn-data-table td {
6465
6575
  padding: calc(3 * var(--default-grid-baseline));
6466
- text-align: left;
6576
+ text-align: start;
6467
6577
  border-bottom: 1px solid var(--color-border);
6468
6578
  vertical-align: middle;
6469
6579
  max-width: var(--cn-table-cell-max-width, 22rem);
@@ -6482,6 +6592,18 @@ svg.leaflet-image-layer.leaflet-interactive path {
6482
6592
  white-space: normal;
6483
6593
  }
6484
6594
 
6595
+ /* The secondary line of a cell (`columns[].secondary`): muted, smaller, on its
6596
+ own line under the value. Theme hooks: --cn-table-secondary-size and
6597
+ --cn-table-secondary-color. */
6598
+ .cn-data-table .cn-table-cell__secondary {
6599
+ display: block;
6600
+ color: var(--cn-table-secondary-color, var(--color-text-maxcontrast));
6601
+ font-size: var(--cn-table-secondary-size, 0.9em);
6602
+ line-height: 1.35;
6603
+ overflow: hidden;
6604
+ text-overflow: ellipsis;
6605
+ }
6606
+
6485
6607
  /* Back to wrapping, for a column holding prose rather than a label:
6486
6608
  `columns: [{ key: 'description', cellClass: 'cn-cell--wrap' }]`. */
6487
6609
  .cn-data-table th.cn-cell--wrap,
@@ -6543,7 +6665,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6543
6665
  }
6544
6666
 
6545
6667
  .cn-data-table td.cn-cell--end {
6546
- text-align: right;
6668
+ text-align: end;
6547
6669
  white-space: nowrap;
6548
6670
  }
6549
6671
 
@@ -6581,7 +6703,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6581
6703
  }
6582
6704
 
6583
6705
  .cn-table-sort-indicator {
6584
- margin-left: var(--default-grid-baseline);
6706
+ margin-inline-start: var(--default-grid-baseline);
6585
6707
  opacity: 0.6;
6586
6708
  }
6587
6709
 
@@ -6691,7 +6813,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6691
6813
  justify-content: center;
6692
6814
  min-width: 14px;
6693
6815
  height: 14px;
6694
- margin-left: 2px;
6816
+ margin-inline-start: 2px;
6695
6817
  padding: 0 3px;
6696
6818
  border-radius: 7px;
6697
6819
  background-color: var(--color-primary-element);
@@ -6756,7 +6878,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6756
6878
 
6757
6879
  .cn-table-col--icon {
6758
6880
  width: 40px;
6759
- padding-right: 0;
6881
+ padding-inline-end: 0;
6760
6882
  text-align: center;
6761
6883
  color: var(--color-text-maxcontrast);
6762
6884
  }
@@ -6819,7 +6941,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6819
6941
 
6820
6942
  .viewTable { width: 100%; border-collapse: collapse; background-color: var(--color-main-background); }
6821
6943
 
6822
- .viewTable th, .viewTable td { padding: calc(3 * var(--default-grid-baseline)); text-align: left; border-bottom: 1px solid var(--color-border); vertical-align: middle; }
6944
+ .viewTable th, .viewTable td { padding: calc(3 * var(--default-grid-baseline)); text-align: start; border-bottom: 1px solid var(--color-border); vertical-align: middle; }
6823
6945
 
6824
6946
  .viewTable th { background: var(--color-background-hover); font-weight: 500; color: var(--color-text-maxcontrast); background-color: var(--color-background-dark); }
6825
6947
 
@@ -16058,6 +16180,27 @@ a.cn-xwiki-card__title[data-v-54e85fe3]:hover {
16058
16180
  flex-shrink: 0;
16059
16181
  }
16060
16182
 
16183
+ /* The header's text link (`headerLink`). Theme hooks: --cn-widget-header-link-size
16184
+ and --cn-widget-header-link-weight. */
16185
+ .cn-widget-wrapper__header-link[data-v-4dd77f59] {
16186
+ align-self: center;
16187
+ padding: 0 calc(1 * var(--default-grid-baseline));
16188
+ color: var(--color-primary-element);
16189
+ font-size: var(--cn-widget-header-link-size, 14px);
16190
+ font-weight: var(--cn-widget-header-link-weight, 600);
16191
+ text-decoration: none;
16192
+ white-space: nowrap;
16193
+ }
16194
+ .cn-widget-wrapper__header-link[data-v-4dd77f59]:hover,
16195
+ .cn-widget-wrapper__header-link[data-v-4dd77f59]:focus-visible {
16196
+ text-decoration: underline;
16197
+ }
16198
+ .cn-widget-wrapper__header-link[data-v-4dd77f59]:focus-visible {
16199
+ outline: 2px solid var(--color-primary-element);
16200
+ outline-offset: 2px;
16201
+ border-radius: var(--border-radius-small, 4px);
16202
+ }
16203
+
16061
16204
  /* Every widget's header icon is coloured — `--cn-widget-icon-color` is set on
16062
16205
  the header from titleIconStyle, and defaults to the theme colour if a
16063
16206
  wrapper is ever rendered without it. Material-design-icon components paint
@@ -16757,6 +16900,84 @@ a.cn-xwiki-card__title[data-v-54e85fe3]:hover {
16757
16900
  color: var(--color-text-maxcontrast);
16758
16901
  }
16759
16902
 
16903
+ /* The bars variant: equal columns, a thin bar per step. Theme hooks:
16904
+ --cn-stages-bar-height, --cn-stages-bar-radius, --cn-stages-bar-done,
16905
+ --cn-stages-bar-current, --cn-stages-bar-todo. */
16906
+ .cn-stages-widget__bars[data-v-358fde0f] {
16907
+ display: grid;
16908
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
16909
+ grid-auto-flow: column;
16910
+ gap: 8px;
16911
+ margin: 0;
16912
+ padding: 0;
16913
+ list-style: none;
16914
+ }
16915
+ .cn-stages-widget__bar-step[data-v-358fde0f] {
16916
+ display: flex;
16917
+ flex-direction: column;
16918
+ gap: 8px;
16919
+ min-width: 0;
16920
+ }
16921
+ .cn-stages-widget__bar[data-v-358fde0f] {
16922
+ display: block;
16923
+ height: var(--cn-stages-bar-height, 6px);
16924
+ border-radius: var(--cn-stages-bar-radius, 3px);
16925
+ background: var(--cn-stages-bar-todo, var(--color-border));
16926
+ }
16927
+ .cn-stages-widget__bar-step--done .cn-stages-widget__bar[data-v-358fde0f] {
16928
+ background: var(--cn-stages-bar-done, var(--color-primary-element));
16929
+ }
16930
+ .cn-stages-widget__bar-step--current .cn-stages-widget__bar[data-v-358fde0f] {
16931
+ background: var(--cn-stages-bar-current, var(--color-error));
16932
+ }
16933
+ .cn-stages-widget__bar-label[data-v-358fde0f] {
16934
+ display: block;
16935
+ margin: 0;
16936
+ padding: 0;
16937
+ border: 0;
16938
+ background: none;
16939
+ color: var(--color-text-maxcontrast);
16940
+ font: inherit;
16941
+ font-size: 14px;
16942
+ text-align: start;
16943
+ overflow: hidden;
16944
+ text-overflow: ellipsis;
16945
+ white-space: nowrap;
16946
+ }
16947
+
16948
+ /* A clickable label is a <button>, and Nextcloud's core stylesheet gives
16949
+ every `button:not(.button-vue)` a min-height of the clickable area (34 to
16950
+ 44px) with the text centred in it. That pushed each reachable stage's label
16951
+ about 12px below the current one, which is a <span>. Zeroed here so all
16952
+ labels sit 8px under their bar, as the board draws them. The visually
16953
+ hidden "(current step)" is absolutely positioned and takes no space. */
16954
+ button.cn-stages-widget__bar-label[data-v-358fde0f] {
16955
+ min-height: 0;
16956
+ height: auto;
16957
+ line-height: inherit;
16958
+ cursor: pointer;
16959
+ }
16960
+ button.cn-stages-widget__bar-label[aria-disabled="true"][data-v-358fde0f] {
16961
+ cursor: not-allowed;
16962
+ }
16963
+ button.cn-stages-widget__bar-label[data-v-358fde0f]:focus-visible {
16964
+ outline: 2px solid var(--color-primary-element);
16965
+ outline-offset: 2px;
16966
+ border-radius: var(--border-radius-small, 4px);
16967
+ }
16968
+ .cn-stages-widget__bar-step--done .cn-stages-widget__bar-label[data-v-358fde0f] {
16969
+ color: var(--color-main-text);
16970
+ font-weight: 600;
16971
+ }
16972
+ .cn-stages-widget__bar-step--current .cn-stages-widget__bar-label[data-v-358fde0f] {
16973
+ color: var(--color-main-text);
16974
+ font-weight: 700;
16975
+ }
16976
+ .cn-stages-widget__bar-date[data-v-358fde0f] {
16977
+ font-size: 12px;
16978
+ color: var(--color-text-maxcontrast);
16979
+ }
16980
+
16760
16981
  /* Text for screen readers only. */
16761
16982
  .cn-stages-widget__sr-only[data-v-358fde0f] {
16762
16983
  position: absolute;
@@ -16934,7 +17155,7 @@ a.cn-xwiki-card__title[data-v-54e85fe3]:hover {
16934
17155
  padding: var(--cn-kpi-padding-flat, 8px);
16935
17156
  box-sizing: border-box;
16936
17157
  overflow: hidden;
16937
- text-align: left;
17158
+ text-align: start;
16938
17159
  text-decoration: none;
16939
17160
  color: inherit;
16940
17161
  background: transparent;
@@ -17049,6 +17270,29 @@ a.cn-xwiki-card__title[data-v-54e85fe3]:hover {
17049
17270
  white-space: nowrap;
17050
17271
  }
17051
17272
 
17273
+ /* A caption coloured by a rule (`captionVariant` / `overrides[].captionVariant`):
17274
+ "1 due today" in the error colour. Foreground tokens, which stay readable in
17275
+ dark mode. */
17276
+ .cn-kpi-card__label--primary {
17277
+ color: var(--color-primary-element);
17278
+ font-weight: 600;
17279
+ }
17280
+
17281
+ .cn-kpi-card__label--success {
17282
+ color: var(--color-text-success, var(--color-success-text));
17283
+ font-weight: 600;
17284
+ }
17285
+
17286
+ .cn-kpi-card__label--warning {
17287
+ color: var(--color-element-warning, var(--color-warning-text));
17288
+ font-weight: 600;
17289
+ }
17290
+
17291
+ .cn-kpi-card__label--error {
17292
+ color: var(--color-text-error, var(--color-error-text));
17293
+ font-weight: 600;
17294
+ }
17295
+
17052
17296
  /* Semantic variants. Each re-points the ONE accent token, so the icon tint
17053
17297
  and the number move together by construction — there is no second place to
17054
17298
  forget. The inline KPI below shares the same modifiers for the same reason:
@@ -17145,6 +17389,53 @@ a.cn-xwiki-card__title[data-v-54e85fe3]:hover {
17145
17389
  font-size: var(--cn-kpi-value-size-stacked, 2rem);
17146
17390
  }
17147
17391
 
17392
+ /* Stacked: the board's tile (`content.layout: 'stacked'`). A plain muted
17393
+ label, the number at 34px/700 in the text colour, and the caption on a line
17394
+ of its own; CnStatWidget draws no icon circle in this layout. The padding
17395
+ adds up with a dashboard card-fit cell's 8px 14px to the board's 18px 20px.
17396
+ Every value is a token so a theme can move it. */
17397
+ .cn-kpi-card--stacked {
17398
+ flex-direction: column;
17399
+ align-items: stretch;
17400
+ justify-content: center;
17401
+ gap: 0;
17402
+ padding: var(--cn-kpi-stacked-padding, 10px 6px);
17403
+ }
17404
+
17405
+ .cn-kpi-card--stacked .cn-kpi-card__body {
17406
+ gap: var(--cn-kpi-stacked-gap, 6px);
17407
+ }
17408
+
17409
+ .cn-kpi-card--stacked .cn-kpi-card__title {
17410
+ font-size: var(--cn-kpi-stacked-title-size, 14px);
17411
+ font-weight: var(--cn-kpi-stacked-title-weight, 400);
17412
+ color: var(--color-text-maxcontrast);
17413
+ }
17414
+
17415
+ .cn-kpi-card--stacked .cn-kpi-card__value {
17416
+ font-size: var(--cn-kpi-stacked-value-size, 34px);
17417
+ font-weight: var(--cn-kpi-value-weight, 700);
17418
+ line-height: 1;
17419
+ letter-spacing: -0.01em;
17420
+ color: var(--cn-kpi-stacked-value-color, var(--color-main-text));
17421
+ }
17422
+
17423
+ .cn-kpi-card--stacked .cn-kpi-card__caption-line {
17424
+ flex: 0 0 auto;
17425
+ max-width: 100%;
17426
+ font-size: var(--cn-kpi-label-size, 13px);
17427
+ font-weight: 500;
17428
+ }
17429
+
17430
+ /* A linked stacked tile reads as a tile, not as underlined link text. The
17431
+ NL Design theme underlines every `a` with `!important`, so the opt-out
17432
+ needs it too; it only applies to this opt-in layout. */
17433
+ a.cn-kpi-card--stacked,
17434
+ a.cn-kpi-card--stacked:hover,
17435
+ a.cn-kpi-card--stacked:focus-visible {
17436
+ text-decoration: none !important;
17437
+ }
17438
+
17148
17439
  /* Filled: the card draws its own grey box, for a KPI that is NOT already
17149
17440
  inside a wrapper that draws one. Opt-in via `content.flat: false`. */
17150
17441
  .cn-kpi-card--filled {
@@ -18003,6 +18294,68 @@ to { background-position: -200% 0;
18003
18294
  }
18004
18295
 
18005
18296
 
18297
+ .cn-segmented-control[data-v-7b344b4f] {
18298
+ display: inline-flex;
18299
+ gap: 4px;
18300
+ max-width: 100%;
18301
+ padding: 4px;
18302
+ border-radius: var(--border-radius-container, var(--border-radius-large, 10px));
18303
+ background-color: var(--color-background-dark);
18304
+ overflow-x: auto;
18305
+ }
18306
+ .cn-segmented-control--stretch[data-v-7b344b4f] {
18307
+ display: flex;
18308
+ }
18309
+ .cn-segmented-control--stretch .cn-segmented-control__option[data-v-7b344b4f] {
18310
+ flex: 1 1 0;
18311
+ }
18312
+
18313
+ /* The parent class outscores Nextcloud's server rule that gives every plain
18314
+ `button` a margin and a border. */
18315
+ .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f] {
18316
+ display: inline-flex;
18317
+ align-items: center;
18318
+ justify-content: center;
18319
+ gap: 8px;
18320
+ box-sizing: border-box;
18321
+ min-height: 36px;
18322
+ margin: 0;
18323
+ padding: 0 16px;
18324
+ border: 1px solid transparent;
18325
+ border-radius: var(--border-radius-element, var(--border-radius-large, 8px));
18326
+ background-color: transparent;
18327
+ /* Full-contrast label on every option: the choice is carried by the
18328
+ raised surface, not by dimming the others. */
18329
+ color: var(--color-main-text);
18330
+ font: inherit;
18331
+ font-weight: 600;
18332
+ white-space: nowrap;
18333
+ cursor: pointer;
18334
+ }
18335
+ .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f]:hover {
18336
+ background-color: var(--color-background-hover);
18337
+ }
18338
+ .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f]:focus-visible {
18339
+ outline: 2px solid var(--color-primary-element);
18340
+ outline-offset: 2px;
18341
+ }
18342
+
18343
+ /* The border survives forced-colours mode, which drops background and shadow. */
18344
+ .cn-segmented-control .cn-segmented-control__option--checked[data-v-7b344b4f],
18345
+ .cn-segmented-control .cn-segmented-control__option--checked[data-v-7b344b4f]:hover {
18346
+ border-color: var(--color-border-dark);
18347
+ background-color: var(--color-main-background);
18348
+ box-shadow: 0 1px 2px var(--color-box-shadow);
18349
+ }
18350
+ .cn-segmented-control .cn-segmented-control__option[disabled][data-v-7b344b4f] {
18351
+ cursor: default;
18352
+ opacity: 0.5;
18353
+ }
18354
+ .cn-segmented-control__count[data-v-7b344b4f] {
18355
+ font-weight: 400;
18356
+ }
18357
+
18358
+
18006
18359
  .cn-header-widget[data-v-1b97430f] {
18007
18360
  width: 100%;
18008
18361
  height: 100%;
@@ -18014,6 +18367,37 @@ to { background-position: -200% 0;
18014
18367
  min-height: 0;
18015
18368
  border-radius: 0;
18016
18369
  }
18370
+
18371
+ /* With a view switch the heading and the switch share one row, the switch
18372
+ at the right and bottom-aligned with the heading; on a narrow card the
18373
+ switch wraps under it. */
18374
+ .cn-header-widget--with-views[data-v-1b97430f] {
18375
+ display: flex;
18376
+ flex-wrap: wrap;
18377
+ align-items: flex-end;
18378
+ justify-content: space-between;
18379
+ gap: calc(2 * var(--default-grid-baseline)) calc(4 * var(--default-grid-baseline));
18380
+ }
18381
+ .cn-header-widget--with-views .cn-header-widget__content[data-v-1b97430f] {
18382
+ flex: 1 1 320px;
18383
+ width: auto;
18384
+ }
18385
+ .cn-header-widget__views[data-v-1b97430f] {
18386
+ position: relative;
18387
+ z-index: 1;
18388
+ flex: 0 0 auto;
18389
+ padding: 16px;
18390
+ }
18391
+
18392
+ /* On the page ground (`content.ground`): no card, so no inset around the
18393
+ view switch, and the heading at the board's 32px. */
18394
+ .cn-header-widget--ground .cn-header-widget__views[data-v-1b97430f] {
18395
+ padding: 0;
18396
+ }
18397
+ .cn-header-widget--ground .cn-header-widget__title[data-v-1b97430f] {
18398
+ font-size: var(--cn-header-ground-title-size, 32px);
18399
+ letter-spacing: -0.01em;
18400
+ }
18017
18401
  .cn-header-widget__date[data-v-1b97430f] {
18018
18402
  font-size: 14px;
18019
18403
  line-height: 1.4;
@@ -18075,7 +18459,7 @@ to { background-position: -200% 0;
18075
18459
  height: 1px;
18076
18460
  opacity: 0;
18077
18461
  pointer-events: none;
18078
- left: -9999px;
18462
+ inset-inline-start: -9999px;
18079
18463
  top: -9999px;
18080
18464
  }
18081
18465
  @media print {
@@ -32883,6 +33267,70 @@ a.cn-integration-card__title[data-v-f7e9bbfa]:hover {
32883
33267
  }
32884
33268
 
32885
33269
 
33270
+ /* The emblem beside the app name (`nav.brand.emblem`). A theme sets
33271
+ --nldesign-emblem-url for `emblem: true`, and --cn-nav-emblem-size for both. */
33272
+ .cn-app-nav__brand-emblem {
33273
+ flex: none;
33274
+ height: var(--cn-nav-emblem-size, 34px);
33275
+ width: auto;
33276
+ object-fit: contain;
33277
+ }
33278
+ .cn-app-nav__brand-emblem--theme {
33279
+ display: inline-block;
33280
+ width: var(--cn-nav-emblem-size, 34px);
33281
+ background: var(--nldesign-emblem-url) center / contain no-repeat;
33282
+ }
33283
+
33284
+ /* The solid primary action (`solid: true`, or an action that dispatches):
33285
+ one full-width primary button, as the board draws "New case". */
33286
+ .cn-app-nav__primary-action--solid .cn-action-buttons,
33287
+ .cn-app-nav__primary-action--solid .cn-action-buttons .button-vue,
33288
+ .cn-app-nav__primary-action--solid .button-vue {
33289
+ width: 100%;
33290
+ justify-content: center;
33291
+ }
33292
+
33293
+ /* The card above the footer entries (`nav.card`). Theme hooks:
33294
+ --cn-nav-card-background and --cn-nav-card-radius. */
33295
+ .cn-app-nav__card {
33296
+ display: flex;
33297
+ flex-direction: column;
33298
+ gap: calc(2 * var(--default-grid-baseline));
33299
+ margin: calc(2 * var(--default-grid-baseline));
33300
+ padding: calc(4 * var(--default-grid-baseline));
33301
+ border-radius: var(--cn-nav-card-radius, var(--border-radius-large));
33302
+ background: var(--cn-nav-card-background, var(--color-background-hover));
33303
+ }
33304
+ .cn-app-nav__card-title {
33305
+ color: var(--color-main-text);
33306
+ font-weight: 700;
33307
+ }
33308
+ .cn-app-nav__card-text {
33309
+ color: var(--color-text-maxcontrast);
33310
+ line-height: 1.4;
33311
+ }
33312
+ .cn-app-nav__card-link {
33313
+ align-self: flex-start;
33314
+ margin: 0;
33315
+ padding: 0;
33316
+ border: 0;
33317
+ background: none;
33318
+ color: var(--color-primary-element);
33319
+ font: inherit;
33320
+ font-weight: 600;
33321
+ text-decoration: none;
33322
+ cursor: pointer;
33323
+ }
33324
+ .cn-app-nav__card-link:hover,
33325
+ .cn-app-nav__card-link:focus-visible {
33326
+ text-decoration: underline;
33327
+ }
33328
+ .cn-app-nav__card-link:focus-visible {
33329
+ outline: 2px solid var(--color-primary-element);
33330
+ outline-offset: 2px;
33331
+ border-radius: var(--border-radius-small, 4px);
33332
+ }
33333
+
32886
33334
  /* The brand block at the top of the navigation. */
32887
33335
  .cn-app-nav__brand {
32888
33336
  align-items: center;
@@ -32935,6 +33383,21 @@ a.cn-integration-card__title[data-v-f7e9bbfa]:hover {
32935
33383
  padding: calc(var(--default-grid-baseline, 4px) * 2);
32936
33384
  }
32937
33385
 
33386
+ /*
33387
+ * The primary action never shrinks out of sight. NcAppNavigation renders it in
33388
+ * `.app-navigation__body`, a flex child with `overflow-y: scroll` (so its
33389
+ * minimum height is 0) beside a list of `height: 100%` and the footer. With a
33390
+ * card and footer entries below the list, the column overflows and the body
33391
+ * gives up its share of the shrink: "New case" showed as a 24px sliver of a
33392
+ * 42px button. All three forms carry `.app-navigation-new` (the solid and
33393
+ * link wrappers mirror NcAppNavigationNew's class), and the rule is scoped to
33394
+ * this component's navigation, so a navigation without a primary action lays
33395
+ * out exactly as before.
33396
+ */
33397
+ .app-navigation[data-testid="cn-nav"] .app-navigation__body:has(> .app-navigation-new) {
33398
+ flex-shrink: 0;
33399
+ }
33400
+
32938
33401
  /*
32939
33402
  * Footer-section items (section: "footer") render in NcAppNavigation's
32940
33403
  * #footer slot, outside the scroll container, so they stay visible above
@@ -32958,6 +33421,19 @@ a.cn-integration-card__title[data-v-f7e9bbfa]:hover {
32958
33421
  overflow: visible !important;
32959
33422
  }
32960
33423
 
33424
+ /*
33425
+ * A declared footer that names `settings` first (`nav.footer`) puts the
33426
+ * foldout above the footer list. The two are siblings in NcAppNavigation's
33427
+ * flex column, so `order` moves them without changing either's markup; the
33428
+ * card above keeps order 0 and stays first.
33429
+ */
33430
+ .cn-app-nav__settings--first {
33431
+ order: 1;
33432
+ }
33433
+ .cn-app-nav__footer-list--after-settings {
33434
+ order: 2;
33435
+ }
33436
+
32961
33437
  /*
32962
33438
  * Align the settings foldout's items with the main/footer list items,
32963
33439
  * whose icons sit at a 16px inset. The foldout's items live in a bare
@@ -34771,68 +35247,6 @@ a.cn-integration-card__title[data-v-f7e9bbfa]:hover {
34771
35247
  }
34772
35248
 
34773
35249
 
34774
- .cn-segmented-control[data-v-7b344b4f] {
34775
- display: inline-flex;
34776
- gap: 4px;
34777
- max-width: 100%;
34778
- padding: 4px;
34779
- border-radius: var(--border-radius-container, var(--border-radius-large, 10px));
34780
- background-color: var(--color-background-dark);
34781
- overflow-x: auto;
34782
- }
34783
- .cn-segmented-control--stretch[data-v-7b344b4f] {
34784
- display: flex;
34785
- }
34786
- .cn-segmented-control--stretch .cn-segmented-control__option[data-v-7b344b4f] {
34787
- flex: 1 1 0;
34788
- }
34789
-
34790
- /* The parent class outscores Nextcloud's server rule that gives every plain
34791
- `button` a margin and a border. */
34792
- .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f] {
34793
- display: inline-flex;
34794
- align-items: center;
34795
- justify-content: center;
34796
- gap: 8px;
34797
- box-sizing: border-box;
34798
- min-height: 36px;
34799
- margin: 0;
34800
- padding: 0 16px;
34801
- border: 1px solid transparent;
34802
- border-radius: var(--border-radius-element, var(--border-radius-large, 8px));
34803
- background-color: transparent;
34804
- /* Full-contrast label on every option: the choice is carried by the
34805
- raised surface, not by dimming the others. */
34806
- color: var(--color-main-text);
34807
- font: inherit;
34808
- font-weight: 600;
34809
- white-space: nowrap;
34810
- cursor: pointer;
34811
- }
34812
- .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f]:hover {
34813
- background-color: var(--color-background-hover);
34814
- }
34815
- .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f]:focus-visible {
34816
- outline: 2px solid var(--color-primary-element);
34817
- outline-offset: 2px;
34818
- }
34819
-
34820
- /* The border survives forced-colours mode, which drops background and shadow. */
34821
- .cn-segmented-control .cn-segmented-control__option--checked[data-v-7b344b4f],
34822
- .cn-segmented-control .cn-segmented-control__option--checked[data-v-7b344b4f]:hover {
34823
- border-color: var(--color-border-dark);
34824
- background-color: var(--color-main-background);
34825
- box-shadow: 0 1px 2px var(--color-box-shadow);
34826
- }
34827
- .cn-segmented-control .cn-segmented-control__option[disabled][data-v-7b344b4f] {
34828
- cursor: default;
34829
- opacity: 0.5;
34830
- }
34831
- .cn-segmented-control__count[data-v-7b344b4f] {
34832
- font-weight: 400;
34833
- }
34834
-
34835
-
34836
35250
  .cn-brand-stripe[data-v-6fdfa763] {
34837
35251
  --cn-brand-stripe-first: var(--cn-brand-stripe-ratio-1, 1);
34838
35252
  --cn-brand-stripe-second: var(--cn-brand-stripe-ratio-2, 1);