@conduction/nextcloud-vue 2.149.0 → 2.151.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 (78) hide show
  1. package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
  2. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +7 -2
  3. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
  4. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +40 -41
  5. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
  6. package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
  7. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +12 -0
  8. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
  9. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
  10. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
  11. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +6 -3
  12. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
  13. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +13 -1
  14. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
  15. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
  16. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +5 -1
  17. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
  18. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
  19. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  20. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +46 -0
  21. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  22. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +64 -64
  23. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  24. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
  25. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +15 -1
  26. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  27. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  28. package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue.js +1 -1
  29. package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue2.js.map +1 -1
  30. package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue3.js +16 -5
  31. package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue3.js.map +1 -1
  32. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  33. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +25 -2
  34. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  35. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +82 -68
  36. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  37. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +1 -1
  38. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -1
  39. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -1
  40. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +1 -1
  41. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -1
  42. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +1 -1
  43. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -1
  44. package/dist/esm/integrations/builtin/calendar/eventStatus.js +43 -2
  45. package/dist/esm/integrations/builtin/calendar/eventStatus.js.map +1 -1
  46. package/dist/esm/l10n/en.json.js +4 -1
  47. package/dist/esm/l10n/en.json.js.map +1 -1
  48. package/dist/esm/l10n/nl.json.js +5 -2
  49. package/dist/esm/l10n/nl.json.js.map +1 -1
  50. package/dist/esm/library-style.js +1 -1
  51. package/dist/esm/nextcloud-vue.css +707 -438
  52. package/dist/esm/utils/fillTemplate.js +19 -2
  53. package/dist/esm/utils/fillTemplate.js.map +1 -1
  54. package/dist/nextcloud-vue.cjs.js +926 -723
  55. package/dist/nextcloud-vue.cjs.js.map +2 -2
  56. package/dist/nextcloud-vue.css +707 -438
  57. package/l10n/en.json +4 -1
  58. package/l10n/nl.json +5 -2
  59. package/package.json +1 -1
  60. package/src/components/CnActionDialog/CnActionDialog.vue +17 -4
  61. package/src/components/CnChartWidget/CnChartWidget.md +1 -1
  62. package/src/components/CnChartWidget/CnChartWidget.vue +12 -0
  63. package/src/components/CnConversationThread/CnConversationThread.vue +16 -2
  64. package/src/components/CnConversationThread/CnConversationWidget.vue +5 -1
  65. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +47 -2
  66. package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -1
  67. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +15 -1
  68. package/src/components/CnPlanWidget/CnPlanWidgetRow.vue +17 -2
  69. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +45 -2
  70. package/src/components/CnRetentionWidget/CnRetentionWidget.vue +8 -1
  71. package/src/components/CnTimelineWidget/CnTimelineManage.vue +1 -1
  72. package/src/css/board.css +2 -0
  73. package/src/css/dialog.css +6 -0
  74. package/src/css/look-board-detail.css +137 -0
  75. package/src/css/look-board-index.css +5 -1
  76. package/src/css/look-board.css +78 -2
  77. package/src/integrations/builtin/calendar/eventStatus.js +42 -1
  78. package/src/utils/fillTemplate.js +19 -2
@@ -19,6 +19,13 @@
19
19
  --cn-board-notice-ink: var(--color-warning-text, #7a4f00);
20
20
  /* The done marker of the next-step card. */
21
21
  --cn-board-success-tint: var(--color-success-light, #e7f3ea);
22
+ /* The ink on that tint: a completed plan row's state. */
23
+ --cn-board-success-ink: var(--color-success-text, #1e6b2a);
24
+ /* The ink on the light primary fill: an active plan row's state. */
25
+ --cn-board-primary-light-ink: var(--color-primary-element-light-text, #234a78);
26
+ /* The teal badge of a public history entry. */
27
+ --cn-board-teal-tint: var(--nldesign-color-teal-light, #e3f1f3);
28
+ --cn-board-teal-ink: var(--nldesign-color-teal-dark, #1d5e66);
22
29
  /* Card h2 and side heading. */
23
30
  --cn-board-heading-size: 17px;
24
31
  --cn-board-side-heading-size: 15px;
@@ -582,6 +589,20 @@
582
589
  font-size: 13px;
583
590
  }
584
591
 
592
+ /* The initials beside a message: the resident's in the soft ink on the chip
593
+ ground, ours in the primary tint's ink on its light ground, as
594
+ DqZaakContact draws SV and PJ (r31: the initials read main ink).
595
+ @spec openspec/changes/board-conversation-avatar-tones/specs/board-conversation-avatar-tones/spec.md#requirement-a-messages-initials-take-their-sides-tone */
596
+ .cn-look-board .cn-conversation-thread .cn-conversation-thread__avatar:not(.cn-look-nextcloud *) {
597
+ background: var(--color-background-dark);
598
+ color: var(--cn-board-text-soft);
599
+ }
600
+
601
+ .cn-look-board .cn-conversation-thread .cn-conversation-thread__message--us .cn-conversation-thread__avatar:not(.cn-look-nextcloud *) {
602
+ background: var(--color-primary-element-light);
603
+ color: var(--color-primary-element-light-text);
604
+ }
605
+
585
606
  /* A message keeps 64px free on the side away from its avatar, so the two
586
607
  sides read as two columns; the line above it is 13px in the soft ink at the
587
608
  normal line height, and our bubble's text is in the main ink. Each names
@@ -849,6 +870,13 @@
849
870
  font-weight: 500;
850
871
  }
851
872
 
873
+ /* The mail card's header buttons (Mail koppelen, Mail opstellen) are the
874
+ board's 40px control (DqZaakEmail; probed on :8080: 34 live).
875
+ @spec openspec/changes/board-mail-header-buttons-40/specs/board-mail-header-buttons-40/spec.md#requirement-the-mail-cards-header-buttons-are-40px */
876
+ .cn-look-board .cn-mail-tab__header-actions .button-vue:where(:not(.cn-look-nextcloud *)) {
877
+ --button-size: var(--cn-board-control-height);
878
+ }
879
+
852
880
  /* The files table's checkbox column is the board's 42px (12px either side
853
881
  of the 18px box): DqZaakDocumenten and DqDocumentenBeheer both draw it so.
854
882
  The component's 36px pushed the file icon and name 6px left (r31: name 96
@@ -2428,3 +2456,112 @@
2428
2456
  .cn-look-board .cn-detail-page .cn-widget-wrapper:not(.cn-detail-page__side *):has(> .cn-widget-wrapper__header .cn-widget-wrapper__subtitle) > .cn-widget-wrapper__content:has(> .cn-object-data-widget__grid-wrap) {
2429
2457
  padding-top: 14px;
2430
2458
  }
2459
+
2460
+ /* Buttons in a side card stand as the boards draw them in a column: the full
2461
+ width of the card with their label at the start (DqSociaalDomein
2462
+ "Toestemming intrekken" and "Markeer voor aandacht"), a facts action at the
2463
+ 34px control height.
2464
+ @spec openspec/changes/board-r31-side-buttons-checklist-boxes/specs/board-r31-side-buttons-checklist-boxes/spec.md#requirement-a-side-cards-button-spans-the-card-with-its-label-at-the-start */
2465
+ .cn-look-board .cn-detail-page__side .cn-facts-widget__actions:not(.cn-look-nextcloud *) > .button-vue {
2466
+ --button-size: 34px;
2467
+ --default-clickable-area: 34px;
2468
+ flex: 1 1 100%;
2469
+ height: 34px;
2470
+ min-height: 34px;
2471
+ }
2472
+
2473
+ .cn-look-board .cn-detail-page__side .cn-facts-widget__actions:not(.cn-look-nextcloud *) > .button-vue .button-vue__wrapper,
2474
+ .cn-look-board .cn-attention-flag:not(.cn-look-nextcloud *) .button-vue .button-vue__wrapper {
2475
+ justify-content: flex-start;
2476
+ }
2477
+
2478
+ /* A checklist's boxes are the boards' 18px, an open one in the control
2479
+ border grey and a ticked one in the primary colour (DqTaak "Checklist").
2480
+ @spec openspec/changes/board-r31-side-buttons-checklist-boxes/specs/board-r31-side-buttons-checklist-boxes/spec.md#requirement-a-board-checklist-box-is-18px-and-grey-while-open */
2481
+ .cn-look-board .cn-checklist-widget__item .checkbox-radio-switch:not(.cn-look-nextcloud *) .checkbox-content__icon svg {
2482
+ width: 18px;
2483
+ height: 18px;
2484
+ }
2485
+
2486
+ .cn-look-board .cn-checklist-widget__item .checkbox-radio-switch:not(.checkbox-radio-switch--checked):not(.cn-look-nextcloud *) .checkbox-content__icon {
2487
+ color: var(--color-border-maxcontrast);
2488
+ }
2489
+
2490
+ /* In a side card the pill and its date stand 8px apart, as the boards draw
2491
+ them (DqOrganisatie "Lopende zaken", "Open tickets"); the row's own 16px
2492
+ is for a full-width list.
2493
+ @spec openspec/changes/record-list-pill-variant-when/specs/record-list/spec.md#requirement-a-side-rows-pill-and-date-stand-8px-apart */
2494
+ .cn-look-board .cn-detail-page__side .cn-record-list__aside:not(.cn-look-nextcloud *) {
2495
+ gap: 8px;
2496
+ }
2497
+
2498
+ /* A plan in the board look, as DqZaak draws "Zaakplan": ruled rows 10px
2499
+ high on each side, the name at 15px/500 over its muted line, the state a
2500
+ 13px/600 pill toned by state (r31: grey rows, 600 names, 400 pills).
2501
+ @spec openspec/changes/board-plan-rows/specs/plan-widget/spec.md */
2502
+ .cn-look-board .cn-plan .cn-plan-row:not(.cn-look-nextcloud *) {
2503
+ gap: 6px 16px;
2504
+ padding: 10px 0;
2505
+ border-top: 1px solid var(--color-border);
2506
+ background: transparent;
2507
+ }
2508
+
2509
+ .cn-look-board .cn-plan .cn-plan-row .cn-plan-row__name:not(.cn-look-nextcloud *) {
2510
+ font-size: 15px;
2511
+ font-weight: 500;
2512
+ line-height: normal;
2513
+ }
2514
+
2515
+ .cn-look-board .cn-plan .cn-plan-row .cn-plan-row__meta:not(.cn-look-nextcloud *) {
2516
+ line-height: normal;
2517
+ }
2518
+
2519
+ .cn-look-board .cn-plan .cn-plan-row .cn-plan-row__state:not(.cn-look-nextcloud *) {
2520
+ padding: 3px 10px;
2521
+ border-radius: 12px;
2522
+ background: var(--color-background-dark);
2523
+ color: var(--cn-board-text-soft);
2524
+ font-size: 13px;
2525
+ font-weight: 600;
2526
+ line-height: normal;
2527
+ white-space: nowrap;
2528
+ }
2529
+
2530
+ .cn-look-board .cn-plan .cn-plan-row .cn-plan-row__state[data-state='completed']:not(.cn-look-nextcloud *) {
2531
+ background: var(--cn-board-success-tint);
2532
+ color: var(--cn-board-success-ink);
2533
+ }
2534
+
2535
+ .cn-look-board .cn-plan .cn-plan-row .cn-plan-row__state[data-state='active']:not(.cn-look-nextcloud *) {
2536
+ background: var(--color-primary-element-light);
2537
+ color: var(--cn-board-primary-light-ink);
2538
+ }
2539
+
2540
+ /* The history card's note composer and entries as DqZaakHistorie draws them
2541
+ (r31 strict verdict): the note field three lines high on a 1.5 line with
2542
+ 10px 12px inside, the add button at the board's 40px, the title-row
2543
+ buttons 12px apart, and an entry the requester sees marked with a 12px
2544
+ teal pill.
2545
+ @spec openspec/changes/board-history-composer/specs/timeline/spec.md */
2546
+ .cn-look-board .cn-timeline-manage .cn-timeline-manage__draft:not(.cn-look-nextcloud *) {
2547
+ min-height: calc(3 * 1.5em + 22px);
2548
+ padding: 10px 12px;
2549
+ line-height: 1.5;
2550
+ }
2551
+
2552
+ .cn-look-board .cn-timeline-manage .cn-timeline-manage__composer-foot .button-vue:where(:not(.cn-look-nextcloud *)) {
2553
+ --button-size: var(--cn-board-control-height);
2554
+ }
2555
+
2556
+ .cn-look-board .cn-timeline-manage .cn-timeline-manage__header-actions:not(.cn-look-nextcloud *) {
2557
+ gap: 12px;
2558
+ }
2559
+
2560
+ .cn-look-board .cn-timeline-manage .cn-timeline-manage__badge--public:not(.cn-look-nextcloud *) {
2561
+ padding: 2px 8px;
2562
+ border-radius: 10px;
2563
+ background: var(--cn-board-teal-tint);
2564
+ color: var(--cn-board-teal-ink);
2565
+ font-size: 12px;
2566
+ font-weight: 600;
2567
+ }
@@ -1514,17 +1514,19 @@
1514
1514
  margin: 0;
1515
1515
  font-size: 17px;
1516
1516
  font-weight: 700;
1517
- line-height: 1.3;
1517
+ line-height: normal;
1518
1518
  text-decoration: none;
1519
1519
  white-space: normal;
1520
1520
  }
1521
1521
 
1522
1522
  .cn-look-board .cn-object-card--board .cn-object-card__record-meta {
1523
1523
  --nldesign-component-paragraph-font-size: 14px;
1524
+ --nldesign-component-paragraph-line-height: normal;
1524
1525
  --nldesign-component-paragraph-color: var(--color-text-maxcontrast);
1525
1526
  margin: 0;
1526
1527
  color: var(--color-text-maxcontrast);
1527
1528
  font-size: 14px;
1529
+ line-height: normal;
1528
1530
  }
1529
1531
 
1530
1532
  /* The meta line, note and description are paragraphs: each hands the theme,
@@ -1532,11 +1534,13 @@
1532
1534
  .cn-look-board .cn-object-card--board .cn-object-card__record-note {
1533
1535
  --nldesign-component-paragraph-font-size: 13px;
1534
1536
  --nldesign-component-paragraph-font-weight: 600;
1537
+ --nldesign-component-paragraph-line-height: normal;
1535
1538
  --nldesign-component-paragraph-color: var(--cn-board-text-soft);
1536
1539
  margin: 0;
1537
1540
  color: var(--cn-board-text-soft);
1538
1541
  font-size: 13px;
1539
1542
  font-weight: 600;
1543
+ line-height: normal;
1540
1544
  }
1541
1545
 
1542
1546
  .cn-look-board .cn-object-card--board .cn-object-card__record-note--purple {
@@ -317,6 +317,17 @@
317
317
  font-size: 14px;
318
318
  }
319
319
 
320
+ /* A link action is drawn as a button action: the board's 40px, no outer
321
+ margin (DqMijnWerk "Vandaag eerst": live links grew to the theme's 44px
322
+ link target and the button kept Nextcloud's 3px margin, 46px tall and
323
+ 13px apart where the board draws 40 to 42 and 10).
324
+ @spec openspec/changes/board-banner-actions-as-drawn/specs/board-banner-actions-as-drawn/spec.md#requirement-a-board-banners-actions-are-drawn-alike */
325
+ .cn-look-board .cn-banner-widget__action.cn-banner-widget__action:not(.cn-look-nextcloud *) {
326
+ height: var(--cn-board-control-height);
327
+ min-height: 0;
328
+ margin: 0;
329
+ }
330
+
320
331
  .cn-look-board .cn-banner-widget__action--primary:not(.cn-look-nextcloud *) {
321
332
  border: 0;
322
333
  }
@@ -346,7 +357,10 @@
346
357
  min-height: var(--cn-board-control-height);
347
358
  }
348
359
 
349
- .cn-look-board .cn-workspace-filter-widget__form:not(.cn-look-nextcloud *) .button-vue {
360
+ /* `.button-vue.button-vue`: NcButton sets its own padding on a button
361
+ without an icon (`.button-vue:has(.button-vue__icon:empty)`), as strong as
362
+ a single class here, and loads later. */
363
+ .cn-look-board .cn-workspace-filter-widget__form:not(.cn-look-nextcloud *) .button-vue.button-vue {
350
364
  --button-size: var(--cn-board-control-height);
351
365
  --button-padding: 16px;
352
366
  }
@@ -760,7 +774,7 @@
760
774
  /* "CSV exporteren" beside "Rapport laden" is the neutral secondary at the
761
775
  40px control height, 14px in (DqTermijnen).
762
776
  @spec openspec/changes/workspace-filter-export-table/specs/workspace-filter-export-table/spec.md#requirement-a-workspace-filter-input-can-export-the-table-it-loads */
763
- .cn-look-board .cn-workspace-filter-widget__form:not(.cn-look-nextcloud *) .button-vue.cn-workspace-filter-widget__export {
777
+ .cn-look-board .cn-workspace-filter-widget__form:not(.cn-look-nextcloud *) .button-vue.button-vue.cn-workspace-filter-widget__export {
764
778
  --button-size: var(--cn-board-control-height);
765
779
  --button-padding: 14px;
766
780
  }
@@ -813,6 +827,29 @@
813
827
  background: var(--color-background-hover);
814
828
  }
815
829
 
830
+ /* ---- A card table's head controls -------------------------------------- */
831
+ /* The head of a card's table (CnTasksWidget, CnRecordListWidget) draws its
832
+ sort control as the bare label, square, and the funnel after it 4px on as a
833
+ 22px button with a 4px radius, as CnDataTable's board head does
834
+ (DqZaakTaken). Nextcloud's `button` rule gave the label an 8px radius and a
835
+ 3px end margin (7px to the funnel) and NcActions its 8px trigger radius;
836
+ the extra class outranks both. */
837
+ .cn-look-board .cn-tasks-widget__head .cn-tasks-widget__head-sort:not(.cn-look-nextcloud *),
838
+ .cn-look-board .cn-record-list__head .cn-record-list__sort:not(.cn-look-nextcloud *) {
839
+ margin: 0;
840
+ border-radius: 0;
841
+ }
842
+
843
+ .cn-look-board .cn-tasks-widget__head .cn-tasks-widget__head-filter .button-vue:not(.cn-look-nextcloud *),
844
+ .cn-look-board .cn-record-list__head .cn-record-list__head-filter .button-vue:not(.cn-look-nextcloud *) {
845
+ --button-size: 22px;
846
+ width: 22px;
847
+ min-width: 22px;
848
+ height: 22px;
849
+ min-height: 22px;
850
+ border-radius: 4px;
851
+ }
852
+
816
853
  /* ---- The buildiq square ------------------------------------------------ */
817
854
  /* The board square's size. Its orange is set in patches.css, beside the
818
855
  brand orange it replaces, since this sheet names no colour literal. */
@@ -2593,6 +2630,7 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .v-popper__popper.action-
2593
2630
  color: var(--color-main-text);
2594
2631
  font-size: 15px;
2595
2632
  font-weight: 600;
2633
+ line-height: normal;
2596
2634
  }
2597
2635
 
2598
2636
  /* A row whose one action is outlined (`rowAction.variant: "outlined"`,
@@ -2621,9 +2659,13 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .v-popper__popper.action-
2621
2659
  background: var(--color-background-hover);
2622
2660
  }
2623
2661
 
2662
+ /* Title and meta lines at the font's normal line height: a two-line row is
2663
+ 60px, as every Dq dashboard board draws it (r31: 69 at Nextcloud's 1.5).
2664
+ @spec openspec/changes/board-dashboard-rows-normal-leading/specs/board-dashboard-rows-normal-leading/spec.md#requirement-a-board-dashboard-row-is-set-at-the-normal-line-height */
2624
2665
  .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-record-list__meta {
2625
2666
  color: var(--color-text-maxcontrast);
2626
2667
  font-size: 13px;
2668
+ line-height: normal;
2627
2669
  }
2628
2670
 
2629
2671
  .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-record-list__trailing {
@@ -2680,6 +2722,25 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .v-popper__popper.action-
2680
2722
  border-top: 1px solid var(--color-border);
2681
2723
  }
2682
2724
 
2725
+ /* Note rows (DqDagAfsluiten "Nog open van vandaag"): the kind pill 12px
2726
+ from the title, the record button and the closing buttons at the board's
2727
+ 40px, and the closing pair at the two ends of their line (Annuleren left,
2728
+ Dag afsluiten right).
2729
+ @spec openspec/changes/board-record-notes-controls/specs/board-record-notes-controls/spec.md#requirement-board-note-rows-draw-the-boards-controls */
2730
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-record-notes__head {
2731
+ gap: 8px 12px;
2732
+ }
2733
+
2734
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-record-notes__fields .button-vue,
2735
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-record-notes__all-actions .button-vue {
2736
+ --button-size: var(--cn-board-control-height);
2737
+ }
2738
+
2739
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-record-notes__all-actions {
2740
+ flex: 1 1 100%;
2741
+ justify-content: space-between;
2742
+ }
2743
+
2683
2744
  /* Hover: the whole row takes the hover ground, 8px beyond the text so the
2684
2745
  text does not move. */
2685
2746
  .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-record-list__row--link {
@@ -2766,6 +2827,21 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .v-popper__popper.action-
2766
2827
  padding: 0 var(--cn-board-dashboard-card-inset) 10px;
2767
2828
  }
2768
2829
 
2830
+ /* The stacked bar's legend in the board's type: the label 14px and the
2831
+ count 22px, both at the font's normal line height, 2px apart: a 46px item
2832
+ (DqMijnWerk "Mijn 14 zaken per stap"; live drew 14.25/22.5px at 1.5 and
2833
+ 1.2, a 50.4px item).
2834
+ @spec openspec/changes/board-stacked-bar-legend-type/specs/board-stacked-bar-legend-type/spec.md#requirement-a-board-stacked-bar-legend-is-set-in-the-boards-type */
2835
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-stacked-bar:not(.cn-stacked-bar--compact) .cn-stacked-bar__label {
2836
+ font-size: 14px;
2837
+ line-height: normal;
2838
+ }
2839
+
2840
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-stacked-bar:not(.cn-stacked-bar--compact) .cn-stacked-bar__count {
2841
+ font-size: 22px;
2842
+ line-height: normal;
2843
+ }
2844
+
2769
2845
  /* DqMijnWerk "Mijn archiefbeoordelingen": its rows and its empty line. */
2770
2846
  .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--borderless) .cn-decision-list {
2771
2847
  padding: 0 var(--cn-board-dashboard-card-inset) 20px;
@@ -25,9 +25,43 @@ export function eventStatusLabel(ev) {
25
25
  if (status === 'cancelled') {
26
26
  return t('nextcloud-vue', 'Cancelled')
27
27
  }
28
+ const answer = inviteeAnswer(ev)
29
+ if (answer === 'needs-action') {
30
+ return t('nextcloud-vue', 'Invited')
31
+ }
32
+ if (answer === 'accepted') {
33
+ return t('nextcloud-vue', 'Accepted')
34
+ }
35
+ if (answer === 'declined') {
36
+ return t('nextcloud-vue', 'Declined')
37
+ }
38
+ if (answer === 'tentative') {
39
+ return t('nextcloud-vue', 'Tentative')
40
+ }
28
41
  return ''
29
42
  }
30
43
 
44
+ /**
45
+ * Where the invitees stand when the event itself has no status: a decline
46
+ * first, then anyone still to answer, then a tentative answer, else accepted
47
+ * when all accepted; '' without invitees that answered or were asked.
48
+ *
49
+ * @param {object} ev The event.
50
+ * @return {string} `declined`, `needs-action`, `tentative`, `accepted` or ''.
51
+ * @spec openspec/changes/calendar-invitee-answer/specs/calendar-integration/spec.md#requirement-an-appointment-without-a-status-shows-where-its-invitees-stand
52
+ */
53
+ export function inviteeAnswer(ev) {
54
+ const answers = (Array.isArray(ev?.attendees) ? ev.attendees : [])
55
+ .map((att) => (att && typeof att === 'object' ? String(att.partstat || '').toLowerCase() : ''))
56
+ .filter(Boolean)
57
+ for (const answer of ['declined', 'needs-action', 'tentative']) {
58
+ if (answers.includes(answer)) {
59
+ return answer
60
+ }
61
+ }
62
+ return answers.length > 0 && answers.every((answer) => answer === 'accepted') ? 'accepted' : ''
63
+ }
64
+
31
65
  /**
32
66
  * The badge tone of the event's status.
33
67
  *
@@ -45,7 +79,14 @@ export function eventStatusVariant(ev) {
45
79
  if (status === 'cancelled') {
46
80
  return 'error'
47
81
  }
48
- return 'default'
82
+ const answer = inviteeAnswer(ev)
83
+ if (answer === 'accepted') {
84
+ return 'success'
85
+ }
86
+ if (answer === 'declined') {
87
+ return 'error'
88
+ }
89
+ return answer === '' ? 'default' : 'info'
49
90
  }
50
91
 
51
92
  /**
@@ -60,6 +60,22 @@ export function formatLongDate(value, now = new Date(), withYear = false) {
60
60
  }
61
61
  }
62
62
 
63
+ /**
64
+ * How many entries a list holds; with a key, the entries of that list in each
65
+ * of its entries summed (`{sections|count:items}`: the questions of every
66
+ * section of a checklist).
67
+ *
68
+ * @param {Array} list The list.
69
+ * @param {string} key The key of each entry's own list, or '' to count the entries.
70
+ * @return {number} The count.
71
+ */
72
+ function countEntries(list, key) {
73
+ if (key === '') {
74
+ return list.length
75
+ }
76
+ return list.reduce((sum, entry) => sum + (entry && Array.isArray(entry[key]) ? entry[key].length : 0), 0)
77
+ }
78
+
63
79
  /**
64
80
  * Format one token value.
65
81
  *
@@ -76,7 +92,7 @@ export function formatLongDate(value, now = new Date(), withYear = false) {
76
92
  function formatValue(value, format, now, arg = '', object = null, config = null, formatters = null) {
77
93
  // `{list|count}`: how many entries a list holds, nothing for an empty one.
78
94
  if (format === 'count') {
79
- const count = Array.isArray(value) ? value.length : Number(value)
95
+ const count = Array.isArray(value) ? countEntries(value, arg) : Number(value)
80
96
  return Number.isFinite(count) && count > 0 ? String(count) : ''
81
97
  }
82
98
  if (value === null || value === undefined || value === '' || typeof value === 'object') {
@@ -160,7 +176,8 @@ function formatValue(value, format, now, arg = '', object = null, config = null,
160
176
  * ("vandaag, 09.42"), `{path|ago}` says how long ago it was ("10 min
161
177
  * geleden", "vanochtend", "vrijdag"), and `{path|days}` is the
162
178
  * whole days since that date ("has waited {createdAt|days} days"),
163
- * `{path|count}` is how many entries a list holds (nothing for an empty one),
179
+ * `{path|count}` is how many entries a list holds (nothing for an empty one;
180
+ * `{path|count:key}` sums the `key` list of each entry),
164
181
  * `{path|lower}` writes the value in lower case ("Step 2: {statusLabel|lower}"
165
182
  * reads "Step 2: in progress" mid-sentence), and any other name is one of
166
183
  * the app's formatters, passed as `context.formatters` (`{id|caseAddress}`).