@conduction/nextcloud-vue 2.56.0-beta.6 → 2.56.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js +14 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +39 -0
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +46 -4
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +224 -9
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +79 -25
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue2.js +42 -3
- package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue2.js.map +1 -1
- package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue3.js +39 -6
- package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +46 -0
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +11 -4
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue.js +10 -0
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue.js.map +1 -0
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js +39 -0
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js.map +1 -0
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue3.js +16 -0
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue3.js.map +1 -0
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +117 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +147 -89
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +10 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +259 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +131 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +10 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +116 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +24 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +503 -28
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +300 -142
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue.js +10 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue.js.map +1 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue2.js +237 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue2.js.map +1 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue3.js +120 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue3.js.map +1 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue.js +10 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue.js.map +1 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js +77 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js +27 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +169 -12
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +15 -7
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue2.js +37 -3
- package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue3.js +44 -16
- package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +132 -3
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +6 -3
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue.js +10 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue.js.map +1 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js +150 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js.map +1 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js +106 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js.map +1 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue.js +9 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue.js.map +1 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js +47 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue3.js +17 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +49 -0
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue2.js +6 -0
- package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue2.js +46 -0
- package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue3.js +15 -3
- package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue3.js.map +1 -1
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js +37 -1
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js.map +1 -1
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js +29 -13
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js +50 -3
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js.map +1 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue.js +10 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue.js.map +1 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js +186 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js +46 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js +11 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js +298 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js +77 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue.js +10 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue2.js +169 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue2.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue3.js +48 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue3.js.map +1 -0
- package/dist/esm/components/CnTabs/CnTab.vue2.js +35 -0
- package/dist/esm/components/CnTabs/CnTab.vue2.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTab.vue3.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue2.js +120 -7
- package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue3.js +57 -5
- package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +59 -4
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +6 -2
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js +10 -0
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js.map +1 -0
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +484 -0
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js +115 -0
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue.js +10 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue.js.map +1 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue2.js +189 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue2.js.map +1 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue3.js +74 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue3.js.map +1 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +82 -8
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +54 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +54 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +931 -4
- package/dist/esm/utils/dateVariant.js +124 -0
- package/dist/esm/utils/dateVariant.js.map +1 -0
- package/dist/esm/utils/detailActionModel.js +260 -0
- package/dist/esm/utils/detailActionModel.js.map +1 -0
- package/dist/esm/utils/dueRule.js +84 -0
- package/dist/esm/utils/dueRule.js.map +1 -0
- package/dist/esm/utils/fetchAggregate.js +37 -1
- package/dist/esm/utils/fetchAggregate.js.map +1 -1
- package/dist/esm/utils/fetchFilterCounts.js +186 -0
- package/dist/esm/utils/fetchFilterCounts.js.map +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js +5 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/readPath.js +30 -0
- package/dist/esm/utils/readPath.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +14970 -8991
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +931 -4
- package/l10n/en.json +54 -1
- package/l10n/nl.json +54 -1
- package/package.json +1 -1
- package/scripts/.jsdoc-baselines.json +3 -0
- package/src/components/CnActionsMenu/CnActionsMenu.vue +14 -1
- package/src/components/CnAppNav/CnAppNav.md +26 -0
- package/src/components/CnAppNav/CnAppNav.vue +104 -1
- package/src/components/CnBannerWidget/CnBannerWidget.vue +365 -10
- package/src/components/CnBannerWidgetForm/CnBannerWidgetForm.vue +65 -3
- package/src/components/CnBoardView/CnBoardView.vue +77 -0
- package/src/components/CnBrandStripe/CnBrandStripe.md +22 -0
- package/src/components/CnBrandStripe/CnBrandStripe.vue +100 -0
- package/src/components/CnBrandStripe/index.js +4 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +207 -1
- package/src/components/CnConversationThread/CnConversationThread.md +51 -0
- package/src/components/CnConversationThread/CnConversationThread.vue +457 -0
- package/src/components/CnConversationThread/CnConversationWidget.vue +144 -0
- package/src/components/CnConversationThread/index.js +4 -0
- package/src/components/CnDetailPage/CnDetailPage.md +16 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +683 -48
- package/src/components/CnDocumentReviewList/CnDocumentReviewList.md +55 -0
- package/src/components/CnDocumentReviewList/CnDocumentReviewList.vue +384 -0
- package/src/components/CnDocumentReviewList/CnDocumentReviewWidget.vue +108 -0
- package/src/components/CnDocumentReviewList/index.js +4 -0
- package/src/components/CnHeaderWidget/CnHeaderWidget.vue +189 -14
- package/src/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue +53 -3
- package/src/components/CnIndexPage/CnIndexPage.vue +135 -3
- package/src/components/CnNextStepCard/CnNextStepCard.md +40 -0
- package/src/components/CnNextStepCard/CnNextStepCard.vue +319 -0
- package/src/components/CnNextStepCard/CnNextStepWidget.vue +59 -0
- package/src/components/CnNextStepCard/index.js +4 -0
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +49 -0
- package/src/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue +6 -0
- package/src/components/CnObjectKanban/CnObjectKanban.vue +86 -2
- package/src/components/CnQuickFilterBar/CnQuickFilterBar.md +3 -0
- package/src/components/CnQuickFilterBar/CnQuickFilterBar.vue +60 -1
- package/src/components/CnSavedViewsControl/CnSavedViewsControl.vue +50 -3
- package/src/components/CnSegmentedControl/CnSegmentedControl.md +46 -0
- package/src/components/CnSegmentedControl/CnSegmentedControl.vue +291 -0
- package/src/components/CnSegmentedControl/index.js +4 -0
- package/src/components/CnStackedBarWidget/CnStackedBarWidget.md +15 -0
- package/src/components/CnStackedBarWidget/CnStackedBarWidget.vue +414 -0
- package/src/components/CnStackedBarWidget/index.js +14 -0
- package/src/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue +224 -0
- package/src/components/CnStackedBarWidgetForm/index.js +4 -0
- package/src/components/CnTabs/CnTab.vue +35 -0
- package/src/components/CnTabs/CnTabs.vue +244 -10
- package/src/components/CnTabsWidget/CnTabsWidget.vue +63 -4
- package/src/components/CnWeekStripWidget/CnWeekStripWidget.md +31 -0
- package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +668 -0
- package/src/components/CnWeekStripWidget/index.js +14 -0
- package/src/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue +265 -0
- package/src/components/CnWeekStripWidgetForm/index.js +4 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +74 -0
- package/src/components/index.js +11 -0
- package/src/css/detail-page.css +47 -0
- package/src/index.js +9 -0
- package/src/schemas/app-manifest-v2.schema.json +389 -1
- package/src/schemas/app-manifest.schema.json +2 -1
- package/src/utils/dateVariant.js +120 -0
- package/src/utils/detailActionModel.js +256 -0
- package/src/utils/dueRule.js +94 -0
- package/src/utils/fetchAggregate.js +36 -0
- package/src/utils/fetchFilterCounts.js +182 -0
- package/src/utils/index.js +1 -0
- package/src/utils/libraryWidgetKeys.js +5 -0
- package/src/utils/readPath.js +27 -0
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The brand stripe of the organisation. A theme sets its colours, shares and height through the `--cn-brand-stripe-*` custom properties. Without a theme it is one band in the primary colour.
|
|
2
|
+
|
|
3
|
+
```vue
|
|
4
|
+
<CnBrandStripe />
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
With the properties a theme would set:
|
|
8
|
+
|
|
9
|
+
```vue
|
|
10
|
+
<div style="--cn-brand-stripe-color-1: #cc0000; --cn-brand-stripe-color-2: #3669a5; --cn-brand-stripe-color-3: #cc0000; --cn-brand-stripe-ratio-1: 6; --cn-brand-stripe-ratio-2: 3; --cn-brand-stripe-ratio-3: 1; --cn-brand-stripe-height: 5px">
|
|
11
|
+
<CnBrandStripe />
|
|
12
|
+
</div>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Down the side of a panel, with `orientation="vertical"`:
|
|
16
|
+
|
|
17
|
+
```vue
|
|
18
|
+
<div style="display: flex; height: 80px; gap: 12px;">
|
|
19
|
+
<CnBrandStripe orientation="vertical" />
|
|
20
|
+
<span>Content beside the stripe</span>
|
|
21
|
+
</div>
|
|
22
|
+
```
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
-->
|
|
5
|
+
<template>
|
|
6
|
+
<div
|
|
7
|
+
class="cn-brand-stripe"
|
|
8
|
+
:class="{ 'cn-brand-stripe--vertical': orientation === 'vertical' }"
|
|
9
|
+
aria-hidden="true"
|
|
10
|
+
data-testid="cn-brand-stripe">
|
|
11
|
+
<span class="cn-brand-stripe__band cn-brand-stripe__band--1" />
|
|
12
|
+
<span class="cn-brand-stripe__band cn-brand-stripe__band--2" />
|
|
13
|
+
<span class="cn-brand-stripe__band cn-brand-stripe__band--3" />
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
/**
|
|
19
|
+
* CnBrandStripe draws the organisation's brand stripe: up to three coloured
|
|
20
|
+
* bands next to each other, for the top of a page, a card or a sidebar.
|
|
21
|
+
*
|
|
22
|
+
* The theme decides what it looks like, through the library's own custom
|
|
23
|
+
* properties: `--cn-brand-stripe-color-1/2/3` (the colours, start to end),
|
|
24
|
+
* `--cn-brand-stripe-ratio-1/2/3` (unitless shares, such as 6, 3 and 1)
|
|
25
|
+
* and `--cn-brand-stripe-height` (such as 5px). A theming app maps its own
|
|
26
|
+
* tokens onto these; the library never reads a theme's tokens. Without them the
|
|
27
|
+
* stripe is one band in the Nextcloud primary colour, 4px high.
|
|
28
|
+
*
|
|
29
|
+
* The stripe is decoration: it carries no meaning and is hidden from
|
|
30
|
+
* assistive technology.
|
|
31
|
+
*
|
|
32
|
+
* ```vue
|
|
33
|
+
* <CnBrandStripe />
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export default {
|
|
37
|
+
name: 'CnBrandStripe',
|
|
38
|
+
|
|
39
|
+
props: {
|
|
40
|
+
/**
|
|
41
|
+
* The direction the stripe runs in: `horizontal` (the default, a bar
|
|
42
|
+
* across the top) or `vertical` (a bar down the side; the height
|
|
43
|
+
* token then sets its width).
|
|
44
|
+
*
|
|
45
|
+
* @type {'horizontal'|'vertical'}
|
|
46
|
+
*/
|
|
47
|
+
orientation: {
|
|
48
|
+
type: String,
|
|
49
|
+
default: 'horizontal',
|
|
50
|
+
validator: (v) => ['horizontal', 'vertical'].includes(v),
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<!--
|
|
57
|
+
The stripe reads the library's own `--cn-brand-stripe-*` properties, each
|
|
58
|
+
with a Nextcloud fallback. A theming app sets them from its own tokens.
|
|
59
|
+
-->
|
|
60
|
+
<style scoped>
|
|
61
|
+
.cn-brand-stripe {
|
|
62
|
+
display: flex;
|
|
63
|
+
flex: none;
|
|
64
|
+
width: 100%;
|
|
65
|
+
height: var(--cn-brand-stripe-height, 4px);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.cn-brand-stripe--vertical {
|
|
69
|
+
flex-direction: column;
|
|
70
|
+
width: var(--cn-brand-stripe-height, 4px);
|
|
71
|
+
height: 100%;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.cn-brand-stripe__band {
|
|
75
|
+
flex-basis: 0;
|
|
76
|
+
flex-shrink: 1;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.cn-brand-stripe__band--1 {
|
|
80
|
+
flex-grow: var(--cn-brand-stripe-ratio-1, 1);
|
|
81
|
+
background-color: var(--cn-brand-stripe-color-1, var(--color-primary-element));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.cn-brand-stripe__band--2 {
|
|
85
|
+
flex-grow: var(--cn-brand-stripe-ratio-2, 1);
|
|
86
|
+
background-color: var(--cn-brand-stripe-color-2, var(--color-primary-element));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.cn-brand-stripe__band--3 {
|
|
90
|
+
flex-grow: var(--cn-brand-stripe-ratio-3, 1);
|
|
91
|
+
background-color: var(--cn-brand-stripe-color-3, var(--color-primary-element));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@media print {
|
|
95
|
+
.cn-brand-stripe {
|
|
96
|
+
print-color-adjust: exact;
|
|
97
|
+
-webkit-print-color-adjust: exact;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
</style>
|
|
@@ -55,6 +55,43 @@
|
|
|
55
55
|
<span v-else :title="rawTitle">{{ formattedValue }}</span>
|
|
56
56
|
</template>
|
|
57
57
|
|
|
58
|
+
<!-- Built-in "avatar" widget: a person as an avatar with the name beside
|
|
59
|
+
it. A user id (widgetProps.userField, or widgetProps.user for a cell
|
|
60
|
+
that holds the id itself) gets the Nextcloud avatar; a free name
|
|
61
|
+
gets its initials. The picture is decoration: the name is the text. -->
|
|
62
|
+
<template v-else-if="widget === 'avatar'">
|
|
63
|
+
<span v-if="avatarName || avatarUserId" class="cn-cell-renderer__avatar">
|
|
64
|
+
<span v-if="avatarUserId" class="cn-cell-renderer__avatar-picture" aria-hidden="true">
|
|
65
|
+
<NcAvatar
|
|
66
|
+
:user="avatarUserId"
|
|
67
|
+
:displayName="avatarName || avatarUserId"
|
|
68
|
+
:size="avatarSize"
|
|
69
|
+
:disableMenu="true"
|
|
70
|
+
:disableTooltip="true" />
|
|
71
|
+
</span>
|
|
72
|
+
<span
|
|
73
|
+
v-else
|
|
74
|
+
class="cn-cell-renderer__avatar-initials"
|
|
75
|
+
:style="{ width: avatarSize + 'px', height: avatarSize + 'px' }"
|
|
76
|
+
aria-hidden="true">{{ avatarInitials }}</span>
|
|
77
|
+
<span class="cn-cell-renderer__avatar-name" :title="avatarName || avatarUserId">{{ avatarName || avatarUserId }}</span>
|
|
78
|
+
</span>
|
|
79
|
+
<span v-else class="cn-cell-renderer__dash">—</span>
|
|
80
|
+
</template>
|
|
81
|
+
|
|
82
|
+
<!-- Built-in "date" widget: a date whose colour follows
|
|
83
|
+
widgetProps.variantWhen, rules on the number of days until it
|
|
84
|
+
(0 = today, negative = overdue). -->
|
|
85
|
+
<template v-else-if="widget === 'date'">
|
|
86
|
+
<time
|
|
87
|
+
v-if="dateTimestamp"
|
|
88
|
+
class="cn-cell-renderer__date"
|
|
89
|
+
:class="dateVariant ? 'cn-cell-renderer__date--' + dateVariant : null"
|
|
90
|
+
:datetime="dateTimestamp.toISOString()"
|
|
91
|
+
:title="rawTitle">{{ dateLabel }}</time>
|
|
92
|
+
<span v-else class="cn-cell-renderer__dash">—</span>
|
|
93
|
+
</template>
|
|
94
|
+
|
|
58
95
|
<!-- Explicit column formatter — overrides the type-aware paths below -->
|
|
59
96
|
<template v-else-if="hasFormatter">
|
|
60
97
|
<span :title="rawTitle">{{ formattedValue }}</span>
|
|
@@ -129,10 +166,13 @@
|
|
|
129
166
|
</template>
|
|
130
167
|
|
|
131
168
|
<script>
|
|
132
|
-
import {
|
|
169
|
+
import { getCanonicalLocale } from '@nextcloud/l10n'
|
|
170
|
+
import { NcAvatar, NcDateTime } from '@nextcloud/vue'
|
|
133
171
|
import CheckBold from 'vue-material-design-icons/CheckBold.vue'
|
|
134
172
|
import CnFkResolveCell from '../CnFkResolveCell/CnFkResolveCell.vue'
|
|
173
|
+
import { parseDateValue, resolveDateVariant } from '../../utils/dateVariant.js'
|
|
135
174
|
import { safeCurrencyCode } from '../../utils/formatMetric.js'
|
|
175
|
+
import { objectFieldValue } from '../../utils/objectName.js'
|
|
136
176
|
import { safeHref } from '../../utils/safeHref.js'
|
|
137
177
|
import { formatValue } from '../../utils/schema.js'
|
|
138
178
|
import { CnStatusBadge } from '../CnStatusBadge/index.js'
|
|
@@ -162,6 +202,7 @@ export default {
|
|
|
162
202
|
CnStatusBadge,
|
|
163
203
|
CnFkResolveCell,
|
|
164
204
|
CheckBold,
|
|
205
|
+
NcAvatar,
|
|
165
206
|
NcDateTime,
|
|
166
207
|
},
|
|
167
208
|
|
|
@@ -232,6 +273,12 @@ export default {
|
|
|
232
273
|
* the built-in id `"badge"` renders `CnStatusBadge` and the built-in
|
|
233
274
|
* id `"fkResolve"` renders `CnFkResolveCell` (uuid → related object
|
|
234
275
|
* label, config via `widgetProps { register, schema, labelField }`).
|
|
276
|
+
* The built-in id `"avatar"` renders a person as an avatar with the
|
|
277
|
+
* name beside it (`widgetProps { userField?, user?, nameField?, size? }`;
|
|
278
|
+
* a free name gets its initials), and the built-in id `"date"` renders
|
|
279
|
+
* a date whose colour follows `widgetProps.variantWhen`, rules on the
|
|
280
|
+
* number of days until the date (`[{ op: "lt", value: 0, variant:
|
|
281
|
+
* "error" }, { op: "lte", value: 5, variant: "warning" }]`).
|
|
235
282
|
* Takes precedence over `formatter`/the type-aware rendering, but the
|
|
236
283
|
* value handed to the widget is the formatter-shaped `formatted` when
|
|
237
284
|
* `formatter` is also set.
|
|
@@ -350,6 +397,112 @@ export default {
|
|
|
350
397
|
return Number.isNaN(date.getTime()) ? null : date
|
|
351
398
|
},
|
|
352
399
|
|
|
400
|
+
/**
|
|
401
|
+
* `avatar` widget: the Nextcloud user id whose avatar to show, or ''
|
|
402
|
+
* for a free name. Read from the row field `widgetProps.userField`,
|
|
403
|
+
* or from the cell value itself when `widgetProps.user` is true.
|
|
404
|
+
*
|
|
405
|
+
* @return {string}
|
|
406
|
+
* @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-avatar-and-date-cells
|
|
407
|
+
*/
|
|
408
|
+
avatarUserId() {
|
|
409
|
+
const props = this.widgetProps || {}
|
|
410
|
+
let id = ''
|
|
411
|
+
if (typeof props.userField === 'string' && props.userField !== '') {
|
|
412
|
+
id = objectFieldValue(this.row, props.userField)
|
|
413
|
+
} else if (props.user === true) {
|
|
414
|
+
id = this.value
|
|
415
|
+
}
|
|
416
|
+
return (typeof id === 'string' || typeof id === 'number') ? String(id) : ''
|
|
417
|
+
},
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* `avatar` widget: the name shown beside the picture. Read from the
|
|
421
|
+
* row field `widgetProps.nameField` when set, else the cell value.
|
|
422
|
+
*
|
|
423
|
+
* @return {string}
|
|
424
|
+
* @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-avatar-and-date-cells
|
|
425
|
+
*/
|
|
426
|
+
avatarName() {
|
|
427
|
+
const props = this.widgetProps || {}
|
|
428
|
+
if (typeof props.nameField === 'string' && props.nameField !== '') {
|
|
429
|
+
const name = objectFieldValue(this.row, props.nameField)
|
|
430
|
+
if (typeof name === 'string' && name !== '') {
|
|
431
|
+
return name
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (!this.hasValue || typeof this.value === 'object') {
|
|
435
|
+
return ''
|
|
436
|
+
}
|
|
437
|
+
return String(this.hasFormatter ? this.formattedValue : this.value)
|
|
438
|
+
},
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* `avatar` widget: the initials of a free name, at most two letters
|
|
442
|
+
* (first and last word).
|
|
443
|
+
*
|
|
444
|
+
* @return {string}
|
|
445
|
+
* @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-avatar-and-date-cells
|
|
446
|
+
*/
|
|
447
|
+
avatarInitials() {
|
|
448
|
+
const words = this.avatarName.trim().split(/\s+/).filter((word) => word !== '')
|
|
449
|
+
if (words.length === 0) {
|
|
450
|
+
return ''
|
|
451
|
+
}
|
|
452
|
+
const first = Array.from(words[0])[0] || ''
|
|
453
|
+
const last = words.length > 1 ? (Array.from(words[words.length - 1])[0] || '') : ''
|
|
454
|
+
return (first + last).toLocaleUpperCase()
|
|
455
|
+
},
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* `avatar` widget: the picture size in pixels (`widgetProps.size`, default 24).
|
|
459
|
+
*
|
|
460
|
+
* @return {number}
|
|
461
|
+
* @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-avatar-and-date-cells
|
|
462
|
+
*/
|
|
463
|
+
avatarSize() {
|
|
464
|
+
const size = Number(this.widgetProps && this.widgetProps.size)
|
|
465
|
+
return Number.isFinite(size) && size > 0 ? size : 24
|
|
466
|
+
},
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* `date` widget: the variant of the first `widgetProps.variantWhen`
|
|
470
|
+
* rule the date matches, or '' for none.
|
|
471
|
+
*
|
|
472
|
+
* @return {string}
|
|
473
|
+
* @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-avatar-and-date-cells
|
|
474
|
+
*/
|
|
475
|
+
dateVariant() {
|
|
476
|
+
const rules = this.widgetProps && this.widgetProps.variantWhen
|
|
477
|
+
const variant = resolveDateVariant(this.value, rules)
|
|
478
|
+
return variant === 'default' ? '' : variant
|
|
479
|
+
},
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* `date` widget: the date written out in the user's locale.
|
|
483
|
+
*
|
|
484
|
+
* @return {string}
|
|
485
|
+
* @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-avatar-and-date-cells
|
|
486
|
+
*/
|
|
487
|
+
dateLabel() {
|
|
488
|
+
const date = parseDateValue(this.value)
|
|
489
|
+
if (date === null) {
|
|
490
|
+
return ''
|
|
491
|
+
}
|
|
492
|
+
const options = { day: 'numeric', month: 'short', year: 'numeric' }
|
|
493
|
+
let locale
|
|
494
|
+
try {
|
|
495
|
+
locale = getCanonicalLocale()
|
|
496
|
+
} catch {
|
|
497
|
+
locale = undefined
|
|
498
|
+
}
|
|
499
|
+
try {
|
|
500
|
+
return new Intl.DateTimeFormat(locale || undefined, options).format(date)
|
|
501
|
+
} catch {
|
|
502
|
+
return new Intl.DateTimeFormat(undefined, options).format(date)
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
|
|
353
506
|
/** True when the property is a URI / URL (rendered as an external link). */
|
|
354
507
|
isUri() {
|
|
355
508
|
return this.property?.format === 'uri' || this.property?.format === 'url'
|
|
@@ -750,6 +903,59 @@ export default {
|
|
|
750
903
|
color: var(--color-text-maxcontrast);
|
|
751
904
|
}
|
|
752
905
|
|
|
906
|
+
.cn-cell-renderer__avatar {
|
|
907
|
+
display: inline-flex;
|
|
908
|
+
align-items: center;
|
|
909
|
+
gap: 8px;
|
|
910
|
+
max-width: 100%;
|
|
911
|
+
vertical-align: middle;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
.cn-cell-renderer__avatar-picture {
|
|
915
|
+
display: inline-flex;
|
|
916
|
+
flex: none;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.cn-cell-renderer__avatar-initials {
|
|
920
|
+
display: inline-flex;
|
|
921
|
+
flex: none;
|
|
922
|
+
align-items: center;
|
|
923
|
+
justify-content: center;
|
|
924
|
+
border-radius: 50%;
|
|
925
|
+
background-color: var(--color-primary-element-light);
|
|
926
|
+
color: var(--color-primary-element-light-text);
|
|
927
|
+
font-size: 0.75em;
|
|
928
|
+
font-weight: 700;
|
|
929
|
+
line-height: 1;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
.cn-cell-renderer__avatar-name {
|
|
933
|
+
min-width: 0;
|
|
934
|
+
overflow: hidden;
|
|
935
|
+
text-overflow: ellipsis;
|
|
936
|
+
white-space: nowrap;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/* A date that matched a rule is also set in a heavier weight, so the signal
|
|
940
|
+
does not rest on colour alone. */
|
|
941
|
+
.cn-cell-renderer__date--success,
|
|
942
|
+
.cn-cell-renderer__date--warning,
|
|
943
|
+
.cn-cell-renderer__date--error {
|
|
944
|
+
font-weight: 600;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
.cn-cell-renderer__date--success {
|
|
948
|
+
color: var(--color-text-success, var(--color-success-text));
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
.cn-cell-renderer__date--warning {
|
|
952
|
+
color: var(--color-text-warning, var(--color-warning-text));
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
.cn-cell-renderer__date--error {
|
|
956
|
+
color: var(--color-text-error, var(--color-error-text));
|
|
957
|
+
}
|
|
958
|
+
|
|
753
959
|
.cn-cell-renderer__icon--success {
|
|
754
960
|
color: var(--color-success);
|
|
755
961
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
A thread with a reply box:
|
|
2
|
+
|
|
3
|
+
```vue
|
|
4
|
+
<CnConversationThread
|
|
5
|
+
title="Contact with the resident"
|
|
6
|
+
reply-label="Answer to the resident"
|
|
7
|
+
:messages="[
|
|
8
|
+
{ id: 1, author: 'Sanne de Vries', time: '2026-10-04T10:52:00', side: 'them',
|
|
9
|
+
text: 'Thank you. I would like to see all documents about the lighting.' },
|
|
10
|
+
{ id: 2, time: '2026-10-04T10:24:00', side: 'us',
|
|
11
|
+
text: 'Construction starts in March. There will be lighting along the whole cycle path.' },
|
|
12
|
+
]" />
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Read-only, for a closed record:
|
|
16
|
+
|
|
17
|
+
```vue
|
|
18
|
+
<CnConversationThread
|
|
19
|
+
title="Contact"
|
|
20
|
+
:allow-reply="false"
|
|
21
|
+
:messages="[
|
|
22
|
+
{ id: 1, author: 'Sanne de Vries', time: '4 Oct, 10:52', side: 'them', text: 'Thank you.' },
|
|
23
|
+
]" />
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
No messages yet:
|
|
27
|
+
|
|
28
|
+
```vue
|
|
29
|
+
<CnConversationThread title="Contact" :messages="[]" />
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Posting to an endpoint. The reply goes out as `{ message, ...payload }`. `title-tag`, `placeholder`, `send-label`, `us-label` and `empty-text` adjust the wording, and the `reply-actions` slot adds buttons before Send:
|
|
33
|
+
|
|
34
|
+
```vue
|
|
35
|
+
<CnConversationThread
|
|
36
|
+
title="Contact"
|
|
37
|
+
title-tag="h2"
|
|
38
|
+
placeholder="Write your answer"
|
|
39
|
+
send-label="Send to resident"
|
|
40
|
+
us-label="Municipality"
|
|
41
|
+
empty-text="Nobody has written yet."
|
|
42
|
+
endpoint="/apps/example/api/cases/42/messages"
|
|
43
|
+
:payload="{ channel: 'portal' }"
|
|
44
|
+
:messages="[
|
|
45
|
+
{ id: 1, time: '2026-10-04T11:00:00', side: 'us', text: 'We received your request.' },
|
|
46
|
+
]">
|
|
47
|
+
<template #reply-actions="{ draft }">
|
|
48
|
+
<NcButton :disabled="!draft">Save draft</NcButton>
|
|
49
|
+
</template>
|
|
50
|
+
</CnConversationThread>
|
|
51
|
+
```
|