@conduction/nextcloud-vue 2.124.0 → 2.125.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 +120 -11
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +78 -32
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +8 -7
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue.js +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js +2 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js +2 -2
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnDialog/CnDialog.vue2.js +5 -0
- package/dist/esm/components/CnDialog/CnDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnDialog/CnDialog.vue3.js +1 -1
- package/dist/esm/components/CnDialog/CnDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +13 -0
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +7 -2
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +159 -10
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +151 -90
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js +12 -0
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js.map +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue.js +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js +39 -68
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js +70 -116
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +19 -3
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +8 -8
- package/dist/esm/l10n/nl.json.js +8 -8
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +316 -185
- package/dist/nextcloud-vue.cjs.js +1149 -808
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +316 -185
- package/l10n/en.json +8 -8
- package/l10n/nl.json +8 -8
- package/package.json +1 -1
- package/src/components/CnActionDialog/CnActionDialog.vue +173 -14
- package/src/components/CnAppRoot/CnAppRoot.vue +8 -7
- package/src/components/CnAssignDialog/CnAssignDialog.vue +4 -3
- package/src/components/CnDialog/CnDialog.vue +6 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +14 -0
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +7 -2
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +237 -23
- package/src/components/CnSavedViewsControl/CnSavedViewsControl.vue +13 -1
- package/src/components/CnUserSettingsDialog/CnUserSettingsDialog.vue +147 -145
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +19 -3
- package/src/css/dialog.css +23 -0
- package/src/css/look-board-index.css +5 -1
- package/src/css/look-board.css +19 -0
|
@@ -7,29 +7,26 @@
|
|
|
7
7
|
class="cn-user-settings-dialog"
|
|
8
8
|
:name="title"
|
|
9
9
|
look="board"
|
|
10
|
-
|
|
11
|
-
:eyebrow="eyebrow"
|
|
12
|
-
:subtitle="subtitle"
|
|
10
|
+
headless
|
|
13
11
|
:open="open"
|
|
14
|
-
:style="
|
|
12
|
+
:style="frameStyle"
|
|
15
13
|
data-testid="cn-user-settings-dialog"
|
|
16
14
|
@update:open="onUpdateOpen"
|
|
17
15
|
@closing="close">
|
|
18
16
|
<div class="cn-user-settings-dialog__body">
|
|
19
17
|
<nav
|
|
20
|
-
v-if="sections.length > 0"
|
|
21
18
|
class="cn-user-settings-dialog__nav"
|
|
22
19
|
:aria-label="navLabel"
|
|
23
20
|
data-testid="cn-user-settings-nav">
|
|
21
|
+
<h2 class="cn-user-settings-dialog__title" data-testid="cn-user-settings-title">
|
|
22
|
+
{{ title }}
|
|
23
|
+
</h2>
|
|
24
24
|
<!-- `nextcloudLinks`: Nextcloud's own personal settings first, as
|
|
25
25
|
links, then one entry for this app holding its sections. -->
|
|
26
26
|
<ul v-if="ncLinks.length > 0" class="cn-user-settings-dialog__nc-links" data-testid="cn-user-settings-nc-links">
|
|
27
27
|
<li v-for="link in ncLinks" :key="link.key">
|
|
28
28
|
<a :href="link.href" class="cn-user-settings-dialog__nav-link">
|
|
29
|
-
<span
|
|
30
|
-
<CnIcon :name="link.icon" :size="18" />
|
|
31
|
-
</span>
|
|
32
|
-
<span>{{ link.label }}</span>
|
|
29
|
+
<span class="cn-user-settings-dialog__nav-label">{{ link.label }}</span>
|
|
33
30
|
</a>
|
|
34
31
|
</li>
|
|
35
32
|
</ul>
|
|
@@ -47,10 +44,7 @@
|
|
|
47
44
|
:aria-current="section.id === selected ? 'true' : undefined"
|
|
48
45
|
:data-testid="`cn-user-settings-nav-${section.id}`"
|
|
49
46
|
@click.prevent="selectSection(section.id)">
|
|
50
|
-
<span
|
|
51
|
-
<CnVNodes :vnodes="section.icon" />
|
|
52
|
-
</span>
|
|
53
|
-
<span>{{ section.name }}</span>
|
|
47
|
+
<span class="cn-user-settings-dialog__nav-label">{{ section.name }}</span>
|
|
54
48
|
</a>
|
|
55
49
|
</li>
|
|
56
50
|
</ul>
|
|
@@ -58,24 +52,22 @@
|
|
|
58
52
|
<div class="cn-user-settings-dialog__sections">
|
|
59
53
|
<!-- @slot default NcAppSettingsSection children; each registers itself in the navigation. -->
|
|
60
54
|
<slot />
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<span class="cn-user-settings-dialog__heading-icon" aria-hidden="true" :data-testid="`cn-user-settings-heading-icon-${section.id}`">
|
|
65
|
-
<CnVNodes :vnodes="section.icon" />
|
|
66
|
-
</span>
|
|
67
|
-
</Teleport>
|
|
68
|
-
</template>
|
|
55
|
+
<p class="cn-user-settings-dialog__note" data-testid="cn-user-settings-note">
|
|
56
|
+
{{ footerNote }}
|
|
57
|
+
</p>
|
|
69
58
|
</div>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
59
|
+
<NcButton
|
|
60
|
+
class="cn-user-settings-dialog__close"
|
|
61
|
+
variant="tertiary"
|
|
62
|
+
:aria-label="closeLabel"
|
|
63
|
+
:title="closeLabel"
|
|
64
|
+
data-testid="cn-user-settings-close"
|
|
65
|
+
@click="close">
|
|
66
|
+
<template #icon>
|
|
67
|
+
<Close :size="20" />
|
|
68
|
+
</template>
|
|
77
69
|
</NcButton>
|
|
78
|
-
</
|
|
70
|
+
</div>
|
|
79
71
|
</CnDialog>
|
|
80
72
|
</template>
|
|
81
73
|
|
|
@@ -83,9 +75,9 @@
|
|
|
83
75
|
import { translate as t } from '@nextcloud/l10n'
|
|
84
76
|
import { generateUrl } from '@nextcloud/router'
|
|
85
77
|
import { NcButton } from '@nextcloud/vue'
|
|
86
|
-
import {
|
|
78
|
+
import { ref } from 'vue'
|
|
79
|
+
import Close from 'vue-material-design-icons/Close.vue'
|
|
87
80
|
import CnDialog from '../CnDialog/CnDialog.vue'
|
|
88
|
-
import CnIcon from '../CnIcon/CnIcon.vue'
|
|
89
81
|
|
|
90
82
|
/**
|
|
91
83
|
* The key NcAppSettingsSection injects to register itself with its dialog
|
|
@@ -96,37 +88,28 @@ const REGISTRATION_KEY = Symbol.for('NcAppSettingsDialog:registration')
|
|
|
96
88
|
/** The key NcAppSettingsSection injects for the legacy design flag. */
|
|
97
89
|
const LEGACY_DESIGN_KEY = Symbol.for('NcAppSettingsDialog:legacy')
|
|
98
90
|
|
|
99
|
-
/** Renders a section's icon vnodes as they were registered. */
|
|
100
|
-
const CnVNodes = {
|
|
101
|
-
name: 'CnVNodes',
|
|
102
|
-
props: { vnodes: { type: [Array, Object], default: null } },
|
|
103
|
-
render() {
|
|
104
|
-
// A section's icon is drawn twice (navigation and heading), so each draw gets its own copy.
|
|
105
|
-
const list = Array.isArray(this.vnodes) ? this.vnodes : [this.vnodes]
|
|
106
|
-
return list.map((vnode) => (vnode && typeof vnode === 'object' ? cloneVNode(vnode) : vnode))
|
|
107
|
-
},
|
|
108
|
-
}
|
|
109
|
-
|
|
110
91
|
/**
|
|
111
|
-
* CnUserSettingsDialog - the user settings dialog in the board look
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* a
|
|
92
|
+
* CnUserSettingsDialog - the user settings dialog in the board look, as the
|
|
93
|
+
* DqPersoonlijkeInstellingen board draws Nextcloud's own settings dialog:
|
|
94
|
+
* 900px wide, the title at the top of a tinted navigation column, every
|
|
95
|
+
* section stacked on a white pane that the navigation scrolls, a close icon
|
|
96
|
+
* in the corner, and no header or footer. Under the sections a line says
|
|
97
|
+
* that changes save straight away.
|
|
116
98
|
*
|
|
117
99
|
* The sections stay the app's: any `NcAppSettingsSection` in the default slot
|
|
118
100
|
* registers itself with this dialog exactly as it does with
|
|
119
|
-
* `NcAppSettingsDialog`, with its name
|
|
120
|
-
*
|
|
101
|
+
* `NcAppSettingsDialog`, with its name and order. CnAppRoot renders this
|
|
102
|
+
* dialog instead of `NcAppSettingsDialog` under the board look.
|
|
121
103
|
*
|
|
122
104
|
* @spec openspec/changes/user-settings-board-dialog/specs/user-settings-board-dialog/spec.md#requirement-the-user-settings-dialog-takes-the-board-look
|
|
105
|
+
* @spec openspec/changes/user-settings-dialog-dq-board/specs/user-settings-dialog-dq-board/spec.md#requirement-the-user-settings-dialog-follows-the-dq-board
|
|
123
106
|
*
|
|
124
107
|
* @event update:open Emitted with `false` when the dialog closes.
|
|
125
108
|
*/
|
|
126
109
|
export default {
|
|
127
110
|
name: 'CnUserSettingsDialog',
|
|
128
111
|
|
|
129
|
-
components: {
|
|
112
|
+
components: { Close, CnDialog, NcButton },
|
|
130
113
|
|
|
131
114
|
provide() {
|
|
132
115
|
return {
|
|
@@ -145,9 +128,19 @@ export default {
|
|
|
145
128
|
open: { type: Boolean, default: false },
|
|
146
129
|
/** Dialog title; also its accessible name. */
|
|
147
130
|
title: { type: String, required: true },
|
|
148
|
-
/**
|
|
131
|
+
/**
|
|
132
|
+
* Deprecated and ignored: the board draws no line above the title.
|
|
133
|
+
* Kept so a host that passes it stays valid.
|
|
134
|
+
*
|
|
135
|
+
* @deprecated
|
|
136
|
+
*/
|
|
149
137
|
eyebrow: { type: String, default: () => t('nextcloud-vue', 'Your account') },
|
|
150
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* Deprecated and ignored: the board draws no line under the title.
|
|
140
|
+
* Kept so a host that passes it stays valid.
|
|
141
|
+
*
|
|
142
|
+
* @deprecated
|
|
143
|
+
*/
|
|
151
144
|
subtitle: { type: String, default: () => t('nextcloud-vue', 'Only for you. Colleagues keep their own settings.') },
|
|
152
145
|
/** The app's name, after the footer note and as the navigation entry holding its sections. */
|
|
153
146
|
appName: { type: String, default: '' },
|
|
@@ -166,8 +159,6 @@ export default {
|
|
|
166
159
|
return {
|
|
167
160
|
sections: [],
|
|
168
161
|
selected: '',
|
|
169
|
-
/** Ids of the sections whose heading is in the page, for the heading icons. */
|
|
170
|
-
headingTargets: [],
|
|
171
162
|
picked: false,
|
|
172
163
|
}
|
|
173
164
|
},
|
|
@@ -190,9 +181,9 @@ export default {
|
|
|
190
181
|
}))
|
|
191
182
|
},
|
|
192
183
|
|
|
193
|
-
/** @return {object} The board's
|
|
194
|
-
|
|
195
|
-
return { '--cn-dialog-
|
|
184
|
+
/** @return {object} The board's 900px width, over CnDialog's width roles. */
|
|
185
|
+
frameStyle() {
|
|
186
|
+
return { '--cn-dialog-width': '900px' }
|
|
196
187
|
},
|
|
197
188
|
|
|
198
189
|
/** @return {string} The navigation's accessible name. */
|
|
@@ -212,21 +203,6 @@ export default {
|
|
|
212
203
|
},
|
|
213
204
|
},
|
|
214
205
|
|
|
215
|
-
watch: {
|
|
216
|
-
sections() {
|
|
217
|
-
this.$nextTick(() => {
|
|
218
|
-
this.headingTargets = typeof document === 'undefined'
|
|
219
|
-
? []
|
|
220
|
-
: this.sections.filter((section) => section.icon && document.getElementById(`settings-section_${section.id}--label`)).map((section) => section.id)
|
|
221
|
-
this.showSelected()
|
|
222
|
-
})
|
|
223
|
-
},
|
|
224
|
-
|
|
225
|
-
selected() {
|
|
226
|
-
this.$nextTick(() => this.showSelected())
|
|
227
|
-
},
|
|
228
|
-
},
|
|
229
|
-
|
|
230
206
|
methods: {
|
|
231
207
|
/**
|
|
232
208
|
* Add a section to the navigation, kept in `order`; a section
|
|
@@ -235,13 +211,14 @@ export default {
|
|
|
235
211
|
*
|
|
236
212
|
* @param {string} id The section id.
|
|
237
213
|
* @param {string} name The section name.
|
|
238
|
-
* @param {number} [order] The section's place.
|
|
239
|
-
*
|
|
214
|
+
* @param {number} [order] The section's place. A section's icon, the
|
|
215
|
+
* fourth argument NcAppSettingsSection passes, is not drawn: the
|
|
216
|
+
* board lists the sections by name alone.
|
|
240
217
|
*/
|
|
241
|
-
registerSection(id, name, order
|
|
218
|
+
registerSection(id, name, order) {
|
|
242
219
|
const rest = this.sections.filter((section) => section.id !== id)
|
|
243
220
|
const place = typeof order === 'number' ? order : Math.max(0, ...rest.map((section) => section.order)) + 1
|
|
244
|
-
this.sections = [...rest, { id, name, order: place
|
|
221
|
+
this.sections = [...rest, { id, name, order: place }].sort((a, b) => a.order - b.order)
|
|
245
222
|
if (!this.picked) {
|
|
246
223
|
this.selected = this.sections[0].id
|
|
247
224
|
}
|
|
@@ -260,7 +237,8 @@ export default {
|
|
|
260
237
|
},
|
|
261
238
|
|
|
262
239
|
/**
|
|
263
|
-
* Mark a section current
|
|
240
|
+
* Mark a section current, scroll it to the top of the pane and focus
|
|
241
|
+
* its heading. Every section stays in the pane.
|
|
264
242
|
*
|
|
265
243
|
* @param {string} id The section id.
|
|
266
244
|
*/
|
|
@@ -268,33 +246,18 @@ export default {
|
|
|
268
246
|
this.picked = true
|
|
269
247
|
this.selected = id
|
|
270
248
|
this.$nextTick(() => {
|
|
271
|
-
|
|
249
|
+
const el = typeof document !== 'undefined' ? document.getElementById(`settings-section_${id}`) : null
|
|
250
|
+
if (el && typeof el.scrollIntoView === 'function') {
|
|
251
|
+
el.scrollIntoView({ block: 'start', behavior: 'smooth' })
|
|
252
|
+
}
|
|
272
253
|
const heading = typeof document !== 'undefined' ? document.getElementById(`settings-section_${id}--label`) : null
|
|
273
254
|
if (heading) {
|
|
274
255
|
heading.setAttribute('tabindex', '-1')
|
|
275
|
-
heading.focus()
|
|
256
|
+
heading.focus({ preventScroll: true })
|
|
276
257
|
}
|
|
277
258
|
})
|
|
278
259
|
},
|
|
279
260
|
|
|
280
|
-
/**
|
|
281
|
-
* Show the current section and hide the others. They stay mounted,
|
|
282
|
-
* so what a reader typed in one survives a switch.
|
|
283
|
-
*
|
|
284
|
-
* @spec openspec/changes/user-settings-one-section/specs/user-settings-board-dialog/spec.md#requirement-the-board-user-settings-dialog-shows-one-section-at-a-time
|
|
285
|
-
*/
|
|
286
|
-
showSelected() {
|
|
287
|
-
if (typeof document === 'undefined') {
|
|
288
|
-
return
|
|
289
|
-
}
|
|
290
|
-
for (const section of this.sections) {
|
|
291
|
-
const el = document.getElementById(`settings-section_${section.id}`)
|
|
292
|
-
if (el) {
|
|
293
|
-
el.hidden = section.id !== this.selected
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
},
|
|
297
|
-
|
|
298
261
|
/**
|
|
299
262
|
* Follow NcDialog's own open state.
|
|
300
263
|
*
|
|
@@ -318,16 +281,35 @@ export default {
|
|
|
318
281
|
</script>
|
|
319
282
|
|
|
320
283
|
<style scoped>
|
|
284
|
+
/* The DqPersoonlijkeInstellingen board: a tinted navigation column with the
|
|
285
|
+
title on top, the sections on a white pane beside it, and the close icon
|
|
286
|
+
in the corner. The dialog's frame (900px, its tint, no padding) is in
|
|
287
|
+
dialog.css, on the teleported container. */
|
|
321
288
|
.cn-user-settings-dialog__body {
|
|
289
|
+
position: relative;
|
|
322
290
|
display: flex;
|
|
323
|
-
|
|
324
|
-
|
|
291
|
+
min-height: 440px;
|
|
292
|
+
max-height: min(760px, calc(100vh - 112px));
|
|
325
293
|
}
|
|
326
294
|
|
|
327
295
|
.cn-user-settings-dialog__nav {
|
|
296
|
+
display: flex;
|
|
328
297
|
flex: 0 0 200px;
|
|
298
|
+
flex-direction: column;
|
|
299
|
+
gap: 2px;
|
|
300
|
+
box-sizing: border-box;
|
|
329
301
|
width: 200px;
|
|
330
|
-
padding
|
|
302
|
+
padding: 0 4px 12px;
|
|
303
|
+
overflow-y: auto;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.cn-user-settings-dialog__title {
|
|
307
|
+
margin: 0;
|
|
308
|
+
padding: 14px 10px 12px;
|
|
309
|
+
font-size: 20px;
|
|
310
|
+
font-weight: 700;
|
|
311
|
+
line-height: 1.25;
|
|
312
|
+
color: var(--color-main-text);
|
|
331
313
|
}
|
|
332
314
|
|
|
333
315
|
.cn-user-settings-dialog__nav ul {
|
|
@@ -344,19 +326,25 @@ export default {
|
|
|
344
326
|
it (thematiq), and a bare `a` with `!important` beats any class. */
|
|
345
327
|
.cn-user-settings-dialog__nav-link,
|
|
346
328
|
.cn-user-settings-dialog__nav-link:visited {
|
|
329
|
+
position: relative;
|
|
347
330
|
display: flex;
|
|
348
331
|
align-items: center;
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
padding: 0 12px;
|
|
332
|
+
min-height: 36px;
|
|
333
|
+
padding: 0 10px;
|
|
352
334
|
border-radius: var(--border-radius-element, 8px);
|
|
353
335
|
font-size: 15px;
|
|
336
|
+
font-weight: 500;
|
|
354
337
|
color: var(--color-main-text);
|
|
355
338
|
text-decoration: none !important;
|
|
356
339
|
}
|
|
357
340
|
|
|
341
|
+
.cn-user-settings-dialog__nav-label {
|
|
342
|
+
overflow: hidden;
|
|
343
|
+
text-overflow: ellipsis;
|
|
344
|
+
}
|
|
345
|
+
|
|
358
346
|
.cn-user-settings-dialog__nav-link:hover {
|
|
359
|
-
background: var(--color-
|
|
347
|
+
background: color-mix(in srgb, var(--color-primary-element) 8%, transparent);
|
|
360
348
|
text-decoration: none !important;
|
|
361
349
|
}
|
|
362
350
|
|
|
@@ -365,75 +353,89 @@ export default {
|
|
|
365
353
|
outline-offset: 2px;
|
|
366
354
|
}
|
|
367
355
|
|
|
356
|
+
/* The open section: a stronger tint and a 3px bar at the left edge. */
|
|
368
357
|
.cn-user-settings-dialog__nav-link--active,
|
|
369
358
|
.cn-user-settings-dialog__nav-link--active:hover {
|
|
370
|
-
background: var(--color-primary-element-light);
|
|
371
|
-
|
|
359
|
+
background: color-mix(in srgb, var(--color-primary-element) 16%, var(--color-primary-element-light));
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.cn-user-settings-dialog__nav-link--active::before {
|
|
363
|
+
content: '';
|
|
364
|
+
position: absolute;
|
|
365
|
+
top: 6px;
|
|
366
|
+
bottom: 6px;
|
|
367
|
+
inset-inline-start: 0;
|
|
368
|
+
width: 3px;
|
|
369
|
+
border-radius: 2px;
|
|
370
|
+
background: var(--color-primary-element);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.cn-user-settings-dialog__group {
|
|
374
|
+
margin: 10px 0 2px;
|
|
375
|
+
padding: 0 10px;
|
|
376
|
+
font-size: 15px;
|
|
372
377
|
font-weight: 600;
|
|
378
|
+
color: var(--color-main-text);
|
|
373
379
|
}
|
|
374
380
|
|
|
375
|
-
.cn-user-settings-
|
|
376
|
-
|
|
377
|
-
flex: none;
|
|
378
|
-
width: 18px;
|
|
379
|
-
height: 18px;
|
|
380
|
-
align-items: center;
|
|
381
|
-
justify-content: center;
|
|
381
|
+
.cn-user-settings-dialog__group-sections {
|
|
382
|
+
padding-inline-start: 10px;
|
|
382
383
|
}
|
|
383
384
|
|
|
384
385
|
.cn-user-settings-dialog__sections {
|
|
385
386
|
display: flex;
|
|
386
|
-
flex: 1 1
|
|
387
|
+
flex: 1 1 auto;
|
|
387
388
|
flex-direction: column;
|
|
389
|
+
gap: 32px;
|
|
390
|
+
box-sizing: border-box;
|
|
388
391
|
min-width: 0;
|
|
392
|
+
padding: 20px 64px 20px 24px;
|
|
393
|
+
overflow-y: auto;
|
|
394
|
+
border-inline-start: 1px solid var(--color-border);
|
|
395
|
+
border-radius: 8px 0 0 8px;
|
|
396
|
+
background: var(--color-main-background);
|
|
389
397
|
}
|
|
390
398
|
|
|
391
399
|
.cn-user-settings-dialog__sections :deep(.app-settings-section) {
|
|
392
400
|
margin: 0;
|
|
393
|
-
padding:
|
|
394
|
-
border
|
|
401
|
+
padding: 0;
|
|
402
|
+
border: 0;
|
|
395
403
|
}
|
|
396
404
|
|
|
397
405
|
.cn-user-settings-dialog__sections :deep(.app-settings-section__name) {
|
|
398
|
-
margin: 0 0
|
|
399
|
-
font-size:
|
|
406
|
+
margin: 0 0 6px;
|
|
407
|
+
font-size: 20px;
|
|
400
408
|
font-weight: 700;
|
|
401
|
-
|
|
402
|
-
align-items: center;
|
|
403
|
-
gap: 10px;
|
|
409
|
+
line-height: 1.3;
|
|
404
410
|
}
|
|
405
411
|
|
|
406
412
|
.cn-user-settings-dialog__note {
|
|
407
|
-
flex: 1 1 auto;
|
|
408
413
|
margin: 0;
|
|
409
414
|
font-size: 14px;
|
|
410
415
|
color: var(--color-text-maxcontrast);
|
|
411
416
|
}
|
|
412
417
|
|
|
413
|
-
.cn-user-settings-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
.cn-user-settings-dialog__group {
|
|
418
|
-
margin: 10px 0 2px;
|
|
419
|
-
padding: 0 12px;
|
|
420
|
-
font-size: 15px;
|
|
421
|
-
font-weight: 600;
|
|
422
|
-
color: var(--color-main-text);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
.cn-user-settings-dialog__group-sections {
|
|
426
|
-
padding-inline-start: 12px;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
.cn-user-settings-dialog__heading-icon {
|
|
430
|
-
display: inline-flex;
|
|
431
|
-
order: -1;
|
|
432
|
-
color: var(--color-text-maxcontrast);
|
|
418
|
+
.cn-user-settings-dialog__close {
|
|
419
|
+
position: absolute;
|
|
420
|
+
top: 8px;
|
|
421
|
+
inset-inline-end: 8px;
|
|
433
422
|
}
|
|
434
423
|
|
|
435
|
-
|
|
436
|
-
.cn-user-settings-
|
|
437
|
-
|
|
424
|
+
@media (max-width: 600px) {
|
|
425
|
+
.cn-user-settings-dialog__body {
|
|
426
|
+
flex-direction: column;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.cn-user-settings-dialog__nav {
|
|
430
|
+
flex-basis: auto;
|
|
431
|
+
width: auto;
|
|
432
|
+
max-height: 40vh;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.cn-user-settings-dialog__sections {
|
|
436
|
+
padding: 20px 16px;
|
|
437
|
+
border-inline-start: 0;
|
|
438
|
+
border-radius: 8px 8px 0 0;
|
|
439
|
+
}
|
|
438
440
|
}
|
|
439
441
|
</style>
|
|
@@ -115,6 +115,7 @@ import { useObjectStore } from '../../store/useObjectStore.js'
|
|
|
115
115
|
import { dispatchAction, resolveObjectOpType } from '../../utils/actionsDispatcher.js'
|
|
116
116
|
import { resolveObjectTokenContext } from '../../utils/detailObjectContext.js'
|
|
117
117
|
import { pageFilter, pageSort } from '../../utils/pageControls.js'
|
|
118
|
+
import { readPath } from '../../utils/readPath.js'
|
|
118
119
|
import { dropOptionalUnresolved, hasUnresolvedTokens, resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
|
|
119
120
|
import { compileRowClass } from '../../utils/rowClassRules.js'
|
|
120
121
|
import { fieldsFromSchema } from '../../utils/schema.js'
|
|
@@ -406,6 +407,19 @@ export default {
|
|
|
406
407
|
default: '',
|
|
407
408
|
},
|
|
408
409
|
|
|
410
|
+
/**
|
|
411
|
+
* The row field (a dot-path) holding the id `rowRoute` opens, for a row
|
|
412
|
+
* that links to another record (a payment row opening its case:
|
|
413
|
+
* `rowIdField: "case"`). Empty (the default) uses the row's own id; a
|
|
414
|
+
* row whose field is empty does not link.
|
|
415
|
+
*
|
|
416
|
+
* @spec openspec/changes/object-table-row-id-field/specs/object-table/spec.md#requirement-a-row-can-link-to-the-record-a-field-names
|
|
417
|
+
*/
|
|
418
|
+
rowIdField: {
|
|
419
|
+
type: String,
|
|
420
|
+
default: '',
|
|
421
|
+
},
|
|
422
|
+
|
|
409
423
|
/**
|
|
410
424
|
* Client-side row cap, forwarded to CnDataTable (`0` = all rows).
|
|
411
425
|
* This is what makes `viewAllRoute` reachable for `endpointSource`
|
|
@@ -791,7 +805,7 @@ export default {
|
|
|
791
805
|
* @return {object}
|
|
792
806
|
*/
|
|
793
807
|
innerProps() {
|
|
794
|
-
const { title, documentationUrl, widgetId, hideWrapper, source, endpointSource, actions, rowRoute, rowClass, schema, exportCsv, exportFileName, ...rest } = this.$props
|
|
808
|
+
const { title, documentationUrl, widgetId, hideWrapper, source, endpointSource, actions, rowRoute, rowIdField, rowClass, schema, exportCsv, exportFileName, ...rest } = this.$props
|
|
795
809
|
const inner = {}
|
|
796
810
|
for (const [k, v] of Object.entries(rest)) {
|
|
797
811
|
if (v !== undefined) {
|
|
@@ -854,8 +868,10 @@ export default {
|
|
|
854
868
|
*/
|
|
855
869
|
rowRouteFn() {
|
|
856
870
|
return (row) => {
|
|
857
|
-
const id =
|
|
858
|
-
|
|
871
|
+
const id = this.rowIdField
|
|
872
|
+
? readPath(row, this.rowIdField)
|
|
873
|
+
: row && (row.id || (row['@self'] && row['@self'].id))
|
|
874
|
+
return id !== null && id !== undefined && id !== '' && typeof id !== 'object' ? { name: this.rowRoute, params: { id: String(id) } } : null
|
|
859
875
|
}
|
|
860
876
|
},
|
|
861
877
|
|
package/src/css/dialog.css
CHANGED
|
@@ -30,6 +30,14 @@
|
|
|
30
30
|
background-color: color-mix(in srgb, var(--color-main-text) 45%, transparent);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/* Any modal of a board-look app (an app's own NcDialog or NcModal, not
|
|
34
|
+
opened through CnDialog) dims the page the same way. A page that takes the
|
|
35
|
+
Nextcloud look keeps Nextcloud's backdrop.
|
|
36
|
+
@spec openspec/changes/board-modal-backdrop/specs/board-modal-backdrop/spec.md#requirement-every-modal-in-a-board-app-dims-the-page-as-the-boards-do */
|
|
37
|
+
body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .modal-mask {
|
|
38
|
+
background-color: color-mix(in srgb, var(--color-main-text) 45%, transparent);
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
/* Width by role, capped at the viewport minus a 16px gutter each side. The
|
|
34
42
|
shadow carries `!important`: the nldesign theme removes every
|
|
35
43
|
`.modal-container`'s shadow with `!important` and offers no token for it. */
|
|
@@ -70,6 +78,21 @@
|
|
|
70
78
|
border: 0;
|
|
71
79
|
}
|
|
72
80
|
|
|
81
|
+
/* The user settings dialog (CnUserSettingsDialog, DqPersoonlijkeInstellingen
|
|
82
|
+
board): the frame takes the navigation's tint and the body fills it edge
|
|
83
|
+
to edge; the white pane and the navigation are drawn by the component.
|
|
84
|
+
@spec openspec/changes/user-settings-dialog-dq-board/specs/user-settings-dialog-dq-board/spec.md#requirement-the-user-settings-dialog-follows-the-dq-board */
|
|
85
|
+
.modal-mask.cn-dialog-board.cn-user-settings-dialog .modal-wrapper .modal-container {
|
|
86
|
+
overflow: hidden;
|
|
87
|
+
background: var(--color-primary-element-light);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.modal-mask.cn-dialog-board.cn-user-settings-dialog .dialog__content {
|
|
91
|
+
gap: 0;
|
|
92
|
+
padding: 0;
|
|
93
|
+
overflow: hidden;
|
|
94
|
+
}
|
|
95
|
+
|
|
73
96
|
/* Header: padding 22px 24px 0. */
|
|
74
97
|
.cn-dialog-header {
|
|
75
98
|
display: flex;
|
|
@@ -972,9 +972,13 @@
|
|
|
972
972
|
outline-offset: 2px;
|
|
973
973
|
}
|
|
974
974
|
|
|
975
|
-
/* Under the card grid the footer is a row of its own, not a card's edge
|
|
975
|
+
/* Under the card grid the footer is a row of its own, not a card's edge: no
|
|
976
|
+
hairline, 4px 0 (DqAanMijToegewezen, BqAgents, BqStore).
|
|
977
|
+
@spec openspec/changes/board-pagination-under-card-grid/specs/board-pagination-under-card-grid/spec.md#requirement-the-page-footer-under-a-card-grid-is-a-plain-row */
|
|
976
978
|
.cn-look-board .cn-index-page__main:not(.cn-index-page__main--table) > .cn-pagination--board {
|
|
977
979
|
margin-top: 8px;
|
|
980
|
+
padding: 4px 0;
|
|
981
|
+
border-top: 0;
|
|
978
982
|
}
|
|
979
983
|
|
|
980
984
|
/* ------------------------------------------------------------------- cards */
|
package/src/css/look-board.css
CHANGED
|
@@ -1602,6 +1602,25 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .v-popper__popper.action-
|
|
|
1602
1602
|
font-weight: 600;
|
|
1603
1603
|
}
|
|
1604
1604
|
|
|
1605
|
+
/* A compact list (`density: "compact"`) draws its rows 10px above and below,
|
|
1606
|
+
at least 56px tall, 6px between lines, the title at 500 (DqProcesanalyse
|
|
1607
|
+
"Waar zaken blijven hangen").
|
|
1608
|
+
@spec openspec/changes/record-list-density/specs/record-list/spec.md#requirement-a-record-list-can-draw-compact-rows */
|
|
1609
|
+
.cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-record-list--compact .cn-record-list__row {
|
|
1610
|
+
box-sizing: border-box;
|
|
1611
|
+
min-height: 56px;
|
|
1612
|
+
padding: 10px 0;
|
|
1613
|
+
gap: 6px 16px;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
.cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-record-list--compact .cn-record-list__title {
|
|
1617
|
+
font-weight: 500;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
.cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-record-list--compact .cn-record-list__main {
|
|
1621
|
+
gap: 2px;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1605
1624
|
/* Hover: the whole row takes the hover ground, 8px beyond the text so the
|
|
1606
1625
|
text does not move. */
|
|
1607
1626
|
.cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-record-list__row--link {
|