@conduction/nextcloud-vue 2.150.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.
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +7 -2
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +40 -41
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +6 -3
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +13 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +5 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +46 -0
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +64 -64
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +15 -1
- 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/CnPlanWidget/CnPlanWidgetRow.vue.js +1 -1
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue2.js.map +1 -1
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue3.js +16 -5
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +25 -2
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +82 -68
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/eventStatus.js +43 -2
- package/dist/esm/integrations/builtin/calendar/eventStatus.js.map +1 -1
- package/dist/esm/l10n/en.json.js +4 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +5 -2
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +623 -362
- package/dist/nextcloud-vue.cjs.js +894 -720
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +623 -362
- package/l10n/en.json +4 -1
- package/l10n/nl.json +5 -2
- package/package.json +1 -1
- package/src/components/CnActionDialog/CnActionDialog.vue +17 -4
- package/src/components/CnConversationThread/CnConversationThread.vue +16 -2
- package/src/components/CnConversationThread/CnConversationWidget.vue +5 -1
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +47 -2
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -1
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +15 -1
- package/src/components/CnPlanWidget/CnPlanWidgetRow.vue +17 -2
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +45 -2
- package/src/components/CnRetentionWidget/CnRetentionWidget.vue +8 -1
- package/src/components/CnTimelineWidget/CnTimelineManage.vue +1 -1
- package/src/css/dialog.css +6 -0
- package/src/css/look-board-detail.css +137 -0
- package/src/css/look-board.css +78 -2
- package/src/integrations/builtin/calendar/eventStatus.js +42 -1
package/l10n/en.json
CHANGED
|
@@ -2399,7 +2399,10 @@
|
|
|
2399
2399
|
"More actions for {name}": "More actions for {name}",
|
|
2400
2400
|
"Unlink contact": "Unlink contact",
|
|
2401
2401
|
"{term}, extendable by {extension}": "{term}, extendable by {extension}",
|
|
2402
|
-
"Move {item}, use the arrow keys": "Move {item}, use the arrow keys"
|
|
2402
|
+
"Move {item}, use the arrow keys": "Move {item}, use the arrow keys",
|
|
2403
|
+
"Invited": "Invited",
|
|
2404
|
+
"Accepted": "Accepted",
|
|
2405
|
+
"Declined": "Declined"
|
|
2403
2406
|
},
|
|
2404
2407
|
"plurals": {
|
|
2405
2408
|
"{count} member": [
|
package/l10n/nl.json
CHANGED
|
@@ -2008,7 +2008,7 @@
|
|
|
2008
2008
|
"Mail is not available": "E-mail is niet beschikbaar",
|
|
2009
2009
|
"Install Nextcloud Mail to draft and link mail here.": "Installeer Nextcloud Mail om hier e-mail op te stellen en te koppelen.",
|
|
2010
2010
|
"Email template": "E-mailsjabloon",
|
|
2011
|
-
"Open draft from template": "Concept openen
|
|
2011
|
+
"Open draft from template": "Concept openen uit sjabloon",
|
|
2012
2012
|
"Empty draft": "Leeg concept",
|
|
2013
2013
|
"Could not open draft": "Kon concept niet openen",
|
|
2014
2014
|
"Some template fields could not be filled. Fill these in the draft yourself:": "Sommige sjabloonvelden konden niet worden ingevuld. Vul deze zelf in het concept in:",
|
|
@@ -2654,7 +2654,10 @@
|
|
|
2654
2654
|
"More actions for {name}": "Meer acties voor {name}",
|
|
2655
2655
|
"Unlink contact": "Contact ontkoppelen",
|
|
2656
2656
|
"{term}, extendable by {extension}": "{term}, te verdagen met {extension}",
|
|
2657
|
-
"Move {item}, use the arrow keys": "{item} verplaatsen, gebruik de pijltjestoetsen"
|
|
2657
|
+
"Move {item}, use the arrow keys": "{item} verplaatsen, gebruik de pijltjestoetsen",
|
|
2658
|
+
"Invited": "Uitgenodigd",
|
|
2659
|
+
"Accepted": "Geaccepteerd",
|
|
2660
|
+
"Declined": "Afgewezen"
|
|
2658
2661
|
},
|
|
2659
2662
|
"plurals": {
|
|
2660
2663
|
"{count} member": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conduction/nextcloud-vue",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.151.0",
|
|
4
4
|
"description": "Shared Vue component library for Conduction Nextcloud apps — complements @nextcloud/vue with higher-level components, OpenRegister integration, and NL Design System support",
|
|
5
5
|
"homepage": "https://github.com/ConductionNL/nextcloud-vue#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -21,7 +21,10 @@
|
|
|
21
21
|
<strong>{{ summary.title }}</strong>
|
|
22
22
|
<span v-if="summary.meta" class="cn-action-dialog__muted">{{ summary.meta }}</span>
|
|
23
23
|
</span>
|
|
24
|
-
<span
|
|
24
|
+
<span
|
|
25
|
+
v-if="summary.badge"
|
|
26
|
+
class="cn-action-dialog__badge"
|
|
27
|
+
:class="summary.badgeVariant ? 'cn-status-badge--' + summary.badgeVariant : ''">{{ summary.badge }}</span>
|
|
25
28
|
</div>
|
|
26
29
|
|
|
27
30
|
<!-- Facts about the record, in titled groups ("Retention under the case type"). -->
|
|
@@ -218,7 +221,7 @@ let reasonSeq = 0
|
|
|
218
221
|
* `config`:
|
|
219
222
|
* - `title`, `subtitle`, `doneText`: texts, through the host translate;
|
|
220
223
|
* `eyebrow` a template filled from the record ("Close off · {identifier}").
|
|
221
|
-
* - `summary`: `{ source?, title, meta?, badge?, icon? }`: templates filled from
|
|
224
|
+
* - `summary`: `{ source?, title, meta?, badge?, badgeVariant?, badgeColorMap?, icon? }`: templates filled from
|
|
222
225
|
* the record (`source` an endpointSource to read it from, else `object`).
|
|
223
226
|
* - `facts`: `[{ title?, items: [{ label, value }] }]`, `value` a template; a
|
|
224
227
|
* `{path|<formatter>}` token reads through the built-in and app formatters.
|
|
@@ -355,7 +358,12 @@ export default {
|
|
|
355
358
|
return null
|
|
356
359
|
}
|
|
357
360
|
const title = this.fill(def.title)
|
|
358
|
-
|
|
361
|
+
const badge = this.fill(def.badge)
|
|
362
|
+
const variants = ['default', 'success', 'warning', 'error', 'info', 'purple', 'teal']
|
|
363
|
+
const mapped = def.badgeColorMap && typeof def.badgeColorMap === 'object' ? def.badgeColorMap[badge] : undefined
|
|
364
|
+
const wanted = mapped || def.badgeVariant
|
|
365
|
+
const badgeVariant = variants.includes(wanted) ? wanted : ''
|
|
366
|
+
return title ? { title, meta: this.fill(def.meta), badge, badgeVariant } : null
|
|
359
367
|
},
|
|
360
368
|
|
|
361
369
|
/** @return {Array<{title: string, facts: Array<{label: string, value: string}>}>} The fact groups. */
|
|
@@ -858,12 +866,17 @@ export default {
|
|
|
858
866
|
.cn-action-dialog__badge {
|
|
859
867
|
padding: 3px 10px;
|
|
860
868
|
border-radius: 12px;
|
|
861
|
-
background: var(--color-background-dark);
|
|
862
869
|
font-size: 13px;
|
|
863
870
|
font-weight: 600;
|
|
871
|
+
line-height: normal;
|
|
864
872
|
white-space: nowrap;
|
|
865
873
|
}
|
|
866
874
|
|
|
875
|
+
/* Without a tone (`badgeVariant`, `badgeColorMap`) the badge is neutral. */
|
|
876
|
+
.cn-action-dialog__badge:not([class*='cn-status-badge--']) {
|
|
877
|
+
background: var(--color-background-dark);
|
|
878
|
+
}
|
|
879
|
+
|
|
867
880
|
.cn-action-dialog__title {
|
|
868
881
|
margin: 0 0 8px;
|
|
869
882
|
font-size: 14px;
|
|
@@ -64,7 +64,11 @@
|
|
|
64
64
|
<span class="cn-conversation-thread__meta">
|
|
65
65
|
<span class="hidden-visually">{{ row.directionLabel }}</span>
|
|
66
66
|
<span class="cn-conversation-thread__author">{{ row.author }}</span>
|
|
67
|
-
<span v-if="row.channel" class="cn-conversation-thread__channel" data-testid="cn-conversation-channel"
|
|
67
|
+
<span v-if="row.channel" class="cn-conversation-thread__channel" data-testid="cn-conversation-channel"><CnIcon v-if="row.channelIcon"
|
|
68
|
+
class="cn-conversation-thread__channel-icon"
|
|
69
|
+
:name="row.channelIcon"
|
|
70
|
+
:size="13"
|
|
71
|
+
aria-hidden="true" />{{ row.channel }}</span>
|
|
68
72
|
<span v-if="row.status" class="cn-conversation-thread__status" data-testid="cn-conversation-status">{{ row.status }}</span>
|
|
69
73
|
<span v-if="showDirection"
|
|
70
74
|
class="cn-conversation-thread__direction"
|
|
@@ -151,6 +155,7 @@ import axios from '@nextcloud/axios'
|
|
|
151
155
|
import { translate as t } from '@nextcloud/l10n'
|
|
152
156
|
import { NcButton } from '@nextcloud/vue'
|
|
153
157
|
import Send from 'vue-material-design-icons/Send.vue'
|
|
158
|
+
import CnIcon from '../CnIcon/CnIcon.vue'
|
|
154
159
|
import CnQuickFilterBar from '../CnQuickFilterBar/CnQuickFilterBar.vue'
|
|
155
160
|
import { prefixUrl } from '../../utils/headers.js'
|
|
156
161
|
import { userLocale } from '../../utils/userLocale.js'
|
|
@@ -185,6 +190,7 @@ export default {
|
|
|
185
190
|
name: 'CnConversationThread',
|
|
186
191
|
|
|
187
192
|
components: {
|
|
193
|
+
CnIcon,
|
|
188
194
|
CnQuickFilterBar,
|
|
189
195
|
NcButton,
|
|
190
196
|
Send,
|
|
@@ -197,7 +203,7 @@ export default {
|
|
|
197
203
|
|
|
198
204
|
props: {
|
|
199
205
|
/**
|
|
200
|
-
* The messages, oldest first: `{ id?, author?, time?, text, side?, channel?, status?, actions?, note? }`.
|
|
206
|
+
* The messages, oldest first: `{ id?, author?, time?, text, side?, channel?, channelIcon?, status?, actions?, note? }`.
|
|
201
207
|
* `status` is shown after the channel ("Failed"); `actions` are
|
|
202
208
|
* `{ id, label, disabled? }` buttons under the text, each emitting
|
|
203
209
|
* `message-action`.
|
|
@@ -381,6 +387,7 @@ export default {
|
|
|
381
387
|
timeLabel: time.label,
|
|
382
388
|
datetime: time.datetime,
|
|
383
389
|
channel: typeof message.channel === 'string' ? message.channel : '',
|
|
390
|
+
channelIcon: typeof message.channelIcon === 'string' ? message.channelIcon : '',
|
|
384
391
|
status: typeof message.status === 'string' ? message.status : '',
|
|
385
392
|
actions: Array.isArray(message.actions) ? message.actions.filter((action) => action && action.id && action.label) : [],
|
|
386
393
|
directionLabel: side === 'us' ? t('nextcloud-vue', 'Sent message') : t('nextcloud-vue', 'Received message'),
|
|
@@ -787,4 +794,11 @@ export default {
|
|
|
787
794
|
.cn-conversation-thread__channel {
|
|
788
795
|
color: var(--color-text-maxcontrast);
|
|
789
796
|
}
|
|
797
|
+
|
|
798
|
+
/* The channel's icon (`channelIcon`) stands before its name, 5px apart. */
|
|
799
|
+
.cn-conversation-thread__channel:has(.cn-conversation-thread__channel-icon) {
|
|
800
|
+
display: inline-flex;
|
|
801
|
+
align-items: center;
|
|
802
|
+
gap: 5px;
|
|
803
|
+
}
|
|
790
804
|
</style>
|
|
@@ -109,7 +109,8 @@ import { userDisplayName } from '../../utils/userDisplayName.js'
|
|
|
109
109
|
* `bodyField`), `timeField` (alias `timestampField`), `authorField` (alias
|
|
110
110
|
* `senderField`), `sideField` (alias `directionField`) with `usValue` (alias
|
|
111
111
|
* `outValue`) for the messages the organisation sent, and `channelField` with
|
|
112
|
-
* an optional `channelMap` from stored value to label ("email" to "E-mail")
|
|
112
|
+
* an optional `channelMap` from stored value to label ("email" to "E-mail")
|
|
113
|
+
* and `channelIcons` from stored value to an icon name, drawn before the label.
|
|
113
114
|
*
|
|
114
115
|
* The reply box posts to `endpoint` (`@objectId` filled in), or runs
|
|
115
116
|
* `replyAction`, an action descriptor the app decides the meaning of: it is
|
|
@@ -294,6 +295,7 @@ export default {
|
|
|
294
295
|
const c = this.content || {}
|
|
295
296
|
const usValue = String(c.outValue ?? c.usValue ?? 'us')
|
|
296
297
|
const channelMap = c.channelMap && typeof c.channelMap === 'object' ? c.channelMap : {}
|
|
298
|
+
const channelIcons = c.channelIcons && typeof c.channelIcons === 'object' ? c.channelIcons : {}
|
|
297
299
|
const statusMap = c.statusMap && typeof c.statusMap === 'object' ? c.statusMap : {}
|
|
298
300
|
const stored = this.rawMessages()
|
|
299
301
|
.map(({ message, side, key }, index) => {
|
|
@@ -310,6 +312,8 @@ export default {
|
|
|
310
312
|
text: readPath(message, c.bodyField || c.textField || 'text'),
|
|
311
313
|
side: sideOf,
|
|
312
314
|
channel: channelKey === '' ? '' : this.tr(Object.hasOwn(channelMap, channelKey) ? channelMap[channelKey] : channelKey),
|
|
315
|
+
// @spec openspec/changes/conversation-channel-icons/specs/conversation-channel-icons/spec.md#requirement-a-messages-channel-can-carry-its-icon
|
|
316
|
+
channelIcon: Object.hasOwn(channelIcons, channelKey) && typeof channelIcons[channelKey] === 'string' ? channelIcons[channelKey] : '',
|
|
313
317
|
status: statusKey === '' ? '' : this.tr(Object.hasOwn(statusMap, statusKey) ? statusMap[statusKey] : statusKey),
|
|
314
318
|
actions: this.messageActions
|
|
315
319
|
.filter((action) => this.actionApplies(action, message))
|
|
@@ -327,7 +327,7 @@
|
|
|
327
327
|
{{ columnLabel(column) }}
|
|
328
328
|
</template>
|
|
329
329
|
</th>
|
|
330
|
-
<th class="cn-files-browser__col-actions" scope="col">
|
|
330
|
+
<th class="cn-files-browser__col-actions" scope="col" :style="actionsColumnStyle">
|
|
331
331
|
<span class="hidden-visually">{{ t('nextcloud-vue', 'Actions') }}</span>
|
|
332
332
|
</th>
|
|
333
333
|
</tr>
|
|
@@ -1343,6 +1343,8 @@ export default {
|
|
|
1343
1343
|
|
|
1344
1344
|
data() {
|
|
1345
1345
|
return {
|
|
1346
|
+
/** The actions column's measured width while a row button stands in it, else null. */
|
|
1347
|
+
actionsColumnWidth: null,
|
|
1346
1348
|
currentPath: this.rootPath,
|
|
1347
1349
|
/** The open folder as a node, or null before the first listing. */
|
|
1348
1350
|
folder: null,
|
|
@@ -1402,6 +1404,18 @@ export default {
|
|
|
1402
1404
|
},
|
|
1403
1405
|
|
|
1404
1406
|
computed: {
|
|
1407
|
+
/**
|
|
1408
|
+
* The actions column's width. The table lays out fixed, so its columns
|
|
1409
|
+
* take their widths from the head; a row button (Beoordelen) beside the
|
|
1410
|
+
* row menu needs more than the menu's 48px, measured from the first row.
|
|
1411
|
+
*
|
|
1412
|
+
* @return {object} The head cell's style.
|
|
1413
|
+
* @spec openspec/changes/files-actions-column-fits-row-button/specs/files-actions-column-fits-row-button/spec.md#requirement-the-actions-column-fits-a-row-button
|
|
1414
|
+
*/
|
|
1415
|
+
actionsColumnStyle() {
|
|
1416
|
+
return this.actionsColumnWidth ? { width: this.actionsColumnWidth + 'px' } : {}
|
|
1417
|
+
},
|
|
1418
|
+
|
|
1405
1419
|
/**
|
|
1406
1420
|
* The `dropDetail` text: the string, or the text of the first variant
|
|
1407
1421
|
* `{ when, text }` whose `when` is `true` or that has none.
|
|
@@ -1856,6 +1870,10 @@ export default {
|
|
|
1856
1870
|
}
|
|
1857
1871
|
},
|
|
1858
1872
|
|
|
1873
|
+
updated() {
|
|
1874
|
+
this.measureActionsColumn()
|
|
1875
|
+
},
|
|
1876
|
+
|
|
1859
1877
|
beforeUnmount() {
|
|
1860
1878
|
this.cnDetailSideColumn?.claim?.(this.$.uid, false)
|
|
1861
1879
|
for (const channel of FOLDER_CHANGED_CHANNELS) {
|
|
@@ -1865,6 +1883,34 @@ export default {
|
|
|
1865
1883
|
},
|
|
1866
1884
|
|
|
1867
1885
|
methods: {
|
|
1886
|
+
/**
|
|
1887
|
+
* Measure the first row's actions cell (padding, the row button, the
|
|
1888
|
+
* gap and the menu) and keep it as the column's width, so a fixed
|
|
1889
|
+
* table does not push the button past its card. Without a row button
|
|
1890
|
+
* the column keeps its own width.
|
|
1891
|
+
*
|
|
1892
|
+
* @spec openspec/changes/files-actions-column-fits-row-button/specs/files-actions-column-fits-row-button/spec.md#requirement-the-actions-column-fits-a-row-button
|
|
1893
|
+
*/
|
|
1894
|
+
measureActionsColumn() {
|
|
1895
|
+
const cell = this.$el && this.$el.querySelector ? this.$el.querySelector('tbody .cn-files-browser__col-actions') : null
|
|
1896
|
+
const button = cell ? cell.querySelector('.cn-files-browser__row-button') : null
|
|
1897
|
+
if (!cell || !button) {
|
|
1898
|
+
if (this.actionsColumnWidth !== null) {
|
|
1899
|
+
this.actionsColumnWidth = null
|
|
1900
|
+
}
|
|
1901
|
+
return
|
|
1902
|
+
}
|
|
1903
|
+
const style = window.getComputedStyle(cell)
|
|
1904
|
+
const content = [...cell.children].reduce((sum, child) => {
|
|
1905
|
+
const childStyle = window.getComputedStyle(child)
|
|
1906
|
+
return sum + child.offsetWidth + (parseFloat(childStyle.marginInlineStart) || 0) + (parseFloat(childStyle.marginInlineEnd) || 0)
|
|
1907
|
+
}, 0)
|
|
1908
|
+
const width = Math.ceil(content + (parseFloat(style.paddingInlineStart) || 0) + (parseFloat(style.paddingInlineEnd) || 0))
|
|
1909
|
+
if (width > 0 && width !== this.actionsColumnWidth) {
|
|
1910
|
+
this.actionsColumnWidth = width
|
|
1911
|
+
}
|
|
1912
|
+
},
|
|
1913
|
+
|
|
1868
1914
|
t,
|
|
1869
1915
|
|
|
1870
1916
|
preventMiddleClickAutoscroll,
|
|
@@ -3588,7 +3634,6 @@ export default {
|
|
|
3588
3634
|
|
|
3589
3635
|
.cn-files-browser__row-button {
|
|
3590
3636
|
display: inline-flex;
|
|
3591
|
-
margin-inline-end: 8px;
|
|
3592
3637
|
vertical-align: middle;
|
|
3593
3638
|
}
|
|
3594
3639
|
|
|
@@ -121,7 +121,7 @@ export default {
|
|
|
121
121
|
| `icon` | Object\|Function | `null` | MDI icon component shown in the card header |
|
|
122
122
|
| `objectType` | String | `''` | Registered object type slug used by `objectStore.saveObject()` |
|
|
123
123
|
| `store` | Object | `null` | Explicit Pinia objectStore instance; auto-detected via Pinia when omitted |
|
|
124
|
-
| `overrides` | Object | `{}` | Per-property config: `{ key: { order, gridColumn, gridRow, hidden, editable, label, widget, visibleWhen } }`. `visibleWhen` shows the field only when the shared visibility predicate holds for this object, in its local mode: `{ field, op, value }` (ops `eq`, `neq`, `in`, `empty`, ...), or `all` / `any` of those. It reads unsaved changes too. A rule that needs a request (`endpoint`, `source`) is ignored. Read grid only: the Edit form still offers the field. `format: 'duration'` reads an ISO period in words (`P28D` "4 weken"), and `extendBy` names the object's extension period, read as "4 weken, te verdagen met 2". |
|
|
124
|
+
| `overrides` | Object | `{}` | Per-property config: `{ key: { order, gridColumn, gridRow, hidden, editable, label, widget, visibleWhen } }`. `visibleWhen` shows the field only when the shared visibility predicate holds for this object, in its local mode: `{ field, op, value }` (ops `eq`, `neq`, `in`, `empty`, ...), or `all` / `any` of those. It reads unsaved changes too. A rule that needs a request (`endpoint`, `source`) is ignored. Read grid only: the Edit form still offers the field. `format: 'date'` / `'date-long'` reads a date the board way ("3 okt", "3 okt 2026"). `format: 'duration'` reads an ISO period in words (`P28D` "4 weken"), and `extendBy` names the object's extension period, read as "4 weken, te verdagen met 2". |
|
|
125
125
|
| `columns` | Number | `3` | Number of CSS grid columns in the widget |
|
|
126
126
|
| `collapsedFields` (`collapsed-fields`) | Number | `null` | Number of fields shown while collapsed, with a "Show all N fields" button for the rest. `null` fits the cell: the whole rows that fit stay, and the button only appears when the cell overflows |
|
|
127
127
|
| `hideEmpty` | Boolean | `false` | Hide fields with no value instead of rendering an em dash. For discriminated supertypes (one `ticket` schema holding request/complaint/contactmoment), so the grid is type-aware without the schema enumerating which fields belong to which variant. Read grid only — the field being edited, a field with unsaved changes, and the Edit form stay visible; `false`/`0` are values and are never hidden. |
|
|
@@ -438,7 +438,9 @@ import CnGroupNameCell from '../CnCellRenderer/CnGroupNameCell.vue'
|
|
|
438
438
|
import CnFormDialog from '../CnFormDialog/CnFormDialog.vue'
|
|
439
439
|
import { normalizeLook } from '../../composables/useLook.js'
|
|
440
440
|
import { useObjectStore } from '../../store/index.js'
|
|
441
|
+
import { formatBoardDate } from '../../utils/boardDate.js'
|
|
441
442
|
import { formatTermDuration } from '../../utils/builtInFormatters.js'
|
|
443
|
+
import { parseDateValue } from '../../utils/dateVariant.js'
|
|
442
444
|
import { foldDottedFields, isDottedKey, spreadDottedFields } from '../../utils/dottedFields.js'
|
|
443
445
|
import { groupDisplayName, loadGroupDisplayName, searchNextcloudGroups } from '../../utils/groupAutocomplete.js'
|
|
444
446
|
import { humaniseKey } from '../../utils/humaniseKey.js'
|
|
@@ -1105,7 +1107,19 @@ export default {
|
|
|
1105
1107
|
// label, beside a list that already read "Ingediend".
|
|
1106
1108
|
const enumLabel = this.enumDisplayLabel(field, raw)
|
|
1107
1109
|
const empty = this.emptyValueFor(field, raw)
|
|
1108
|
-
|
|
1110
|
+
// Only a format the page's override asks for: a schema `format` keeps its own rendering.
|
|
1111
|
+
const shown = this.resolvedOverrides[field.key]?.format
|
|
1112
|
+
if (empty === null && (shown === 'date' || shown === 'date-long') && raw !== null && raw !== undefined && raw !== '') {
|
|
1113
|
+
// The board's short date ("3 okt"), or with the year always ("3 okt 2026").
|
|
1114
|
+
const date = parseDateValue(raw)
|
|
1115
|
+
if (date !== null) {
|
|
1116
|
+
values[field.key] = shown === 'date-long'
|
|
1117
|
+
? formatBoardDate(date, new Date(date.getFullYear() + 1, 0, 1))
|
|
1118
|
+
: formatBoardDate(date)
|
|
1119
|
+
continue
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
if (empty === null && shown === 'duration' && raw !== null && raw !== undefined && raw !== '') {
|
|
1109
1123
|
// A term in words, with the extension at `extendBy` when the object holds one.
|
|
1110
1124
|
const extension = typeof field.extendBy === 'string' ? readPath(this.objectData || {}, field.extendBy) : null
|
|
1111
1125
|
values[field.key] = formatTermDuration(raw, extension)
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
-->
|
|
5
5
|
<template>
|
|
6
6
|
<div class="cn-plan-row" :data-testid="`cn-plan-row-${item.key || item.uuid}`">
|
|
7
|
-
<span class="cn-plan-
|
|
7
|
+
<span class="cn-plan-row__text">
|
|
8
|
+
<span class="cn-plan-row__name">{{ item.name }}</span>
|
|
9
|
+
<span v-if="item.description" class="cn-plan-row__meta" data-testid="cn-plan-row-meta">{{ item.description }}</span>
|
|
10
|
+
</span>
|
|
8
11
|
<span class="cn-plan-row__state" :data-state="item.state">{{ stateLabel(item.state) }}</span>
|
|
9
12
|
<NcButton v-if="item.state === 'enabled' && item.discretionary"
|
|
10
13
|
:disabled="busy"
|
|
@@ -95,11 +98,23 @@ export default {
|
|
|
95
98
|
padding-block: 6px;
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
.cn-plan-
|
|
101
|
+
.cn-plan-row__text {
|
|
102
|
+
display: flex;
|
|
99
103
|
flex: 1 1 auto;
|
|
104
|
+
flex-direction: column;
|
|
105
|
+
gap: 2px;
|
|
106
|
+
min-width: 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.cn-plan-row__name {
|
|
100
110
|
font-weight: 600;
|
|
101
111
|
}
|
|
102
112
|
|
|
113
|
+
.cn-plan-row__meta {
|
|
114
|
+
color: var(--color-text-maxcontrast);
|
|
115
|
+
font-size: 13px;
|
|
116
|
+
}
|
|
117
|
+
|
|
103
118
|
.cn-plan-row__state {
|
|
104
119
|
padding: 2px 10px;
|
|
105
120
|
border-radius: 12px;
|
|
@@ -309,6 +309,12 @@
|
|
|
309
309
|
:style="{ background: item.dot }"
|
|
310
310
|
aria-hidden="true"
|
|
311
311
|
data-testid="cn-record-list-dot" />
|
|
312
|
+
<span v-if="iconTiles"
|
|
313
|
+
class="cn-record-list__icon-tile"
|
|
314
|
+
aria-hidden="true"
|
|
315
|
+
data-testid="cn-record-list-icon-tile">
|
|
316
|
+
<CnIcon :name="item.icon" :size="18" />
|
|
317
|
+
</span>
|
|
312
318
|
<span class="cn-record-list__main">
|
|
313
319
|
<span v-if="item.title" class="cn-record-list__title">{{ item.title }}</span>
|
|
314
320
|
<span v-if="item.meta" class="cn-record-list__meta">{{ item.meta }}</span>
|
|
@@ -592,6 +598,7 @@ import { resolveDue } from '../../utils/dueText.js'
|
|
|
592
598
|
import { fillCountLabel } from '../../utils/fillCountLabel.js'
|
|
593
599
|
import { fillTemplate, firstFilled } from '../../utils/fillTemplate.js'
|
|
594
600
|
import { unwrapAppConfig } from '../../utils/formatMetric.js'
|
|
601
|
+
import { variantForColor } from '../../utils/headerFieldChips.js'
|
|
595
602
|
import { initialsOf } from '../../utils/initials.js'
|
|
596
603
|
import { lensUnavailableText, readLensReports } from '../../utils/lensAvailability.js'
|
|
597
604
|
import { isObjectRowsSpec, objectRowsOf } from '../../utils/objectRows.js'
|
|
@@ -1000,6 +1007,17 @@ export default {
|
|
|
1000
1007
|
return PRESENTATIONS.includes(value) ? value : 'rows'
|
|
1001
1008
|
},
|
|
1002
1009
|
|
|
1010
|
+
/**
|
|
1011
|
+
* Whether a `rows` row leads with its icon in a round tile
|
|
1012
|
+
* (`iconTile: true` beside `icon`), as DqZaakTaken draws "Wat hierna komt".
|
|
1013
|
+
*
|
|
1014
|
+
* @return {boolean}
|
|
1015
|
+
* @spec openspec/changes/record-list-row-icon-tile/specs/record-list/spec.md#requirement-a-record-list-row-can-lead-with-an-icon-tile
|
|
1016
|
+
*/
|
|
1017
|
+
iconTiles() {
|
|
1018
|
+
return this.content?.iconTile === true && this.cardIcons
|
|
1019
|
+
},
|
|
1020
|
+
|
|
1003
1021
|
/**
|
|
1004
1022
|
* Whether a `cards` card leads its title with an icon: only when the
|
|
1005
1023
|
* list declares `icon`, so a card without one has no placeholder.
|
|
@@ -2627,7 +2645,11 @@ export default {
|
|
|
2627
2645
|
},
|
|
2628
2646
|
|
|
2629
2647
|
/**
|
|
2630
|
-
* The row's pill: `{ field, labels?, colorMap?, variant?, hideValues? }`.
|
|
2648
|
+
* The row's pill: `{ field, labels?, colorMap?, colorField?, variant?, variantWhen?, hideValues? }`.
|
|
2649
|
+
* `variantWhen` (`[{ when, variant }]`, the first whose condition holds for the row) wins over `colorMap`.
|
|
2650
|
+
* `colorField` reads the tone from the row (a colour name such as a
|
|
2651
|
+
* status type's `colour`: purple, teal, blue ...) where `colorMap`
|
|
2652
|
+
* names none (DqMijnWerk "In behandeling" in the status's purple).
|
|
2631
2653
|
*
|
|
2632
2654
|
* @param {object} row The row.
|
|
2633
2655
|
* @param {object} [config] A pill config; the widget's `pill` by default.
|
|
@@ -2652,7 +2674,14 @@ export default {
|
|
|
2652
2674
|
const labels = pill.labels && typeof pill.labels === 'object' ? pill.labels : {}
|
|
2653
2675
|
const map = pill.colorMap && typeof pill.colorMap === 'object' ? pill.colorMap : {}
|
|
2654
2676
|
const found = Object.keys(map).find((k) => k.toLowerCase() === key.toLowerCase())
|
|
2655
|
-
|
|
2677
|
+
// `variantWhen` colours the pill by the row rather than the value: a
|
|
2678
|
+
// finished case is green whatever its case type calls the final status.
|
|
2679
|
+
const rule = Array.isArray(pill.variantWhen)
|
|
2680
|
+
? pill.variantWhen.find((entry) => entry && entry.when && evaluateVisibleWhenLocal(entry.when, row || {}))
|
|
2681
|
+
: null
|
|
2682
|
+
const colour = pill.colorField ? readPath(row, pill.colorField) : null
|
|
2683
|
+
const fromRow = typeof colour === 'string' && colour !== '' ? variantForColor(colour) : null
|
|
2684
|
+
const variant = rule ? rule.variant : (found ? map[found] : (fromRow || pill.variant))
|
|
2656
2685
|
return {
|
|
2657
2686
|
label: labels[key] ? this.translate(labels[key]) : key,
|
|
2658
2687
|
variant: isBadgeVariant(variant) ? variant : 'default',
|
|
@@ -3585,6 +3614,20 @@ a.cn-record-list__inline-title {
|
|
|
3585
3614
|
color: var(--color-primary-element);
|
|
3586
3615
|
text-decoration: underline;
|
|
3587
3616
|
}
|
|
3617
|
+
|
|
3618
|
+
/* A row's icon in a 36px round tile on the sunken ground, before the text
|
|
3619
|
+
(`iconTile`, DqZaakTaken "Wat hierna komt"). */
|
|
3620
|
+
.cn-record-list__icon-tile {
|
|
3621
|
+
display: flex;
|
|
3622
|
+
flex: none;
|
|
3623
|
+
align-items: center;
|
|
3624
|
+
justify-content: center;
|
|
3625
|
+
width: 36px;
|
|
3626
|
+
height: 36px;
|
|
3627
|
+
border-radius: 18px;
|
|
3628
|
+
background: var(--color-background-dark);
|
|
3629
|
+
color: var(--color-main-text);
|
|
3630
|
+
}
|
|
3588
3631
|
</style>
|
|
3589
3632
|
|
|
3590
3633
|
<style>
|
|
@@ -658,6 +658,12 @@ export default {
|
|
|
658
658
|
flex-direction: column;
|
|
659
659
|
gap: 2px;
|
|
660
660
|
min-width: 0;
|
|
661
|
+
line-height: normal;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/* A row's second line is 13px, as the boards draw it (DqZaakArchivering). */
|
|
665
|
+
.cn-retention__row-text .cn-retention__muted {
|
|
666
|
+
font-size: 13px;
|
|
661
667
|
}
|
|
662
668
|
|
|
663
669
|
/* A round mark before a hold or transfer row: LH (legal hold) on the error
|
|
@@ -671,7 +677,7 @@ export default {
|
|
|
671
677
|
height: 32px;
|
|
672
678
|
border-radius: 16px;
|
|
673
679
|
background: var(--color-background-dark);
|
|
674
|
-
color: var(--color-text-maxcontrast);
|
|
680
|
+
color: var(--cn-board-text-soft, var(--color-text-maxcontrast));
|
|
675
681
|
font-size: 12px;
|
|
676
682
|
font-weight: 700;
|
|
677
683
|
}
|
|
@@ -682,6 +688,7 @@ export default {
|
|
|
682
688
|
}
|
|
683
689
|
|
|
684
690
|
.cn-retention__row-title {
|
|
691
|
+
font-size: 15px;
|
|
685
692
|
font-weight: 600;
|
|
686
693
|
}
|
|
687
694
|
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
<span class="cn-timeline-manage__author">{{ entry.author }}</span>
|
|
103
103
|
<span class="cn-timeline-manage__moment">{{ moment(entry.created) }}</span>
|
|
104
104
|
<span v-if="entry.visibility === 'public'"
|
|
105
|
-
class="cn-timeline-manage__badge"
|
|
105
|
+
class="cn-timeline-manage__badge cn-timeline-manage__badge--public"
|
|
106
106
|
data-testid="cn-timeline-public">
|
|
107
107
|
{{ publicLabel }}
|
|
108
108
|
</span>
|
package/src/css/dialog.css
CHANGED
|
@@ -463,6 +463,12 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .modal-mask {
|
|
|
463
463
|
font-size: var(--cn-field-text-size, 15px);
|
|
464
464
|
}
|
|
465
465
|
|
|
466
|
+
/* A board textarea's lines sit on the normal line height, as the boards'
|
|
467
|
+
`font` shorthand sets it: two rows are 58px, not 68 (DqArchiveren Reden). */
|
|
468
|
+
.cn-dialog-board .dialog__content .textarea__input {
|
|
469
|
+
line-height: normal;
|
|
470
|
+
}
|
|
471
|
+
|
|
466
472
|
/* A plain input an app puts in a board dialog (a date, a number) is the same
|
|
467
473
|
40px control; Nextcloud's core stylesheet makes it 34px. */
|
|
468
474
|
.cn-dialog-board .dialog__content input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=file]):not([type=range]):not([type=color]):not([type=submit]):not([type=button]):not([type=reset]):not([type=image]):not(.input-field__input) {
|
|
@@ -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
|
+
}
|