Skip to content

Commit 6d21a5c

Browse files
committed
feat(settings-dialog): Align title with navigation column
The settings dialog title now sits over a tinted navigation column on the inline-start edge of the dialog, replacing the centered header. Navigation links use the default button weight with a rounded inline-start stripe on the active item, mirroring the navigation-item redesign. Closes #7641 Signed-off-by: nfebe <fenn25.fn@gmail.com>
1 parent ea71fe9 commit 6d21a5c

2 files changed

Lines changed: 173 additions & 43 deletions

File tree

src/components/NcAppSettingsDialog/NcAppSettingsDialog.vue

Lines changed: 169 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import NcVNodes from '../NcVNodes/NcVNodes.vue'
1313
import NcAppSettingsDialogVersion from './NcAppSettingsDialogVersion.vue'
1414
import { useIsMobile } from '../../composables/useIsMobile/index.ts'
1515
import { t } from '../../l10n.ts'
16+
import { isLegacy34 } from '../../utils/legacy.ts'
1617
import { APP_SETTINGS_LEGACY_DESIGN_KEY, APP_SETTINGS_REGISTRATION_KEY } from './useAppSettingsDialog.ts'
1718
1819
export interface IAppSettingsSection {
@@ -215,6 +216,7 @@ function unregisterSection(id: string) {
215216
<NcDialog
216217
v-if="open"
217218
class="app-settings"
219+
:class="{ 'app-settings--legacy': isLegacy34 }"
218220
contentClasses="app-settings__content"
219221
navigationClasses="app-settings__navigation"
220222
:additionalTrapElements
@@ -225,6 +227,9 @@ function unregisterSection(id: string) {
225227
:name
226228
@update:open="handleCloseModal">
227229
<template v-if="hasNavigation" #navigation="{ isCollapsed }">
230+
<h2 v-if="!isLegacy34" class="app-settings__title">
231+
{{ name }}
232+
</h2>
228233
<ul
229234
v-if="!isCollapsed"
230235
class="navigation-list">
@@ -258,68 +263,191 @@ function unregisterSection(id: string) {
258263
</template>
259264

260265
<style lang="scss" scoped>
261-
.app-settings {
266+
$navigation-width: 200px;
267+
// Opaque tint for the dialog surface so the modal stays a solid panel
268+
// (translucent over `transparent` would let background content bleed through).
269+
$nav-tint-solid: color-mix(in srgb, var(--color-primary-element) 8%, var(--color-main-background));
270+
$nav-tint-strong: color-mix(in srgb, var(--color-primary-element) 16%, transparent);
271+
$content-inset: calc(3 * var(--default-grid-baseline));
272+
273+
// New design (NC34+): tint the whole dialog, content sits as a rounded
274+
// white card on top, sidebar shows the tint through.
275+
.app-settings:not(.app-settings--legacy) {
276+
:deep(.modal-wrapper .modal-container) {
277+
padding-inline-start: 0 !important;
278+
padding-block-start: 0 !important;
279+
background-color: $nav-tint-solid;
280+
overflow: hidden;
281+
}
282+
283+
// Title is rendered inside the navigation slot; hide the native h2 but
284+
// keep it in the a11y tree so the modal still has its accessible name.
285+
:deep(.dialog__name) {
286+
position: absolute;
287+
width: 1px;
288+
height: 1px;
289+
margin: -1px;
290+
padding: 0;
291+
overflow: hidden;
292+
clip: rect(0 0 0 0);
293+
white-space: nowrap;
294+
border: 0;
295+
}
296+
262297
:deep(.app-settings__navigation) {
263-
min-width: 200px;
264-
margin-inline-end: calc(4 * var(--default-grid-baseline));
298+
min-width: $navigation-width;
299+
max-width: $navigation-width;
300+
flex: 0 0 $navigation-width;
301+
// Beat NcDialog's default 20px end-margin so the tint meets the content.
302+
margin-inline-end: 0 !important;
265303
overflow-x: hidden;
266304
overflow-y: auto;
267305
position: relative;
268306
}
269307
270308
:deep(.app-settings__content) {
271-
padding-inline: calc(4 * var(--default-grid-baseline));
309+
padding-inline: $content-inset;
310+
background-color: var(--color-main-background);
311+
border-inline-start: 1px solid var(--color-border-dark);
312+
border-start-start-radius: var(--border-radius-element);
313+
border-end-start-radius: var(--border-radius-element);
272314
}
273-
}
274315
275-
.navigation-list {
276-
height: 100%;
277-
overflow-y: auto;
278-
padding: calc(3 * var(--default-grid-baseline));
279-
280-
&__link {
281-
display: flex;
282-
align-content: center;
283-
font-size: 16px;
284-
height: var(--default-clickable-area);
285-
margin: 4px 0;
286-
line-height: var(--default-clickable-area);
287-
border-radius: var(--border-radius-element);
316+
.app-settings__title {
317+
box-sizing: border-box;
318+
padding: $content-inset;
319+
margin: 0;
320+
font-size: var(--default-font-size);
288321
font-weight: bold;
289-
padding: 0 calc(4 * var(--default-grid-baseline));
290-
cursor: pointer;
291-
white-space: nowrap;
292-
text-overflow: ellipsis;
293-
overflow: hidden;
294-
background-color: transparent;
295-
border: none;
322+
}
296323
297-
&:hover,
298-
&:focus {
299-
background-color: var(--color-background-hover);
300-
}
324+
.navigation-list {
325+
height: 100%;
326+
overflow-y: auto;
327+
padding: var(--default-grid-baseline);
328+
329+
&__link {
330+
position: relative;
331+
display: flex;
332+
align-items: center;
333+
font-size: var(--default-font-size);
334+
font-weight: normal;
335+
height: var(--default-clickable-area);
336+
margin: 2px 0;
337+
line-height: var(--default-clickable-area);
338+
border-radius: var(--border-radius-element);
339+
padding-inline: calc(2 * var(--default-grid-baseline));
340+
cursor: pointer;
341+
white-space: nowrap;
342+
text-overflow: ellipsis;
343+
overflow: hidden;
344+
background-color: transparent;
345+
border: none;
346+
color: var(--color-main-text);
347+
348+
&:hover,
349+
&:focus {
350+
background-color: $nav-tint-strong;
351+
}
301352
302-
&--active {
303-
background-color: var(--color-primary-element-light) !important;
353+
&--active {
354+
background-color: $nav-tint-strong;
355+
font-weight: 500;
356+
357+
&::before {
358+
content: '';
359+
position: absolute;
360+
inset-block: var(--default-grid-baseline);
361+
inset-inline-start: 0;
362+
width: 3px;
363+
background-color: var(--color-primary-element);
364+
border-radius: 999px;
365+
}
366+
}
367+
368+
&--icon {
369+
gap: var(--default-grid-baseline);
370+
}
371+
372+
&-icon {
373+
display: flex;
374+
justify-content: center;
375+
align-content: center;
376+
width: calc(var(--default-clickable-area) - 2 * var(--default-grid-baseline));
377+
max-width: calc(var(--default-clickable-area) - 2 * var(--default-grid-baseline));
378+
}
304379
}
380+
}
305381
306-
&--icon {
307-
padding-inline-start: calc(2 * var(--default-grid-baseline));
308-
gap: var(--default-grid-baseline);
382+
@media only screen and (max-width: $breakpoint-small-mobile) {
383+
:deep(.app-settings__content) {
384+
border: none;
385+
border-radius: 0;
309386
}
387+
}
388+
}
389+
390+
// Legacy design (NC < 34): keep the original centered-title layout.
391+
.app-settings.app-settings--legacy {
392+
:deep(.app-settings__navigation) {
393+
min-width: 200px;
394+
margin-inline-end: calc(4 * var(--default-grid-baseline));
395+
overflow-x: hidden;
396+
overflow-y: auto;
397+
position: relative;
398+
}
399+
400+
:deep(.app-settings__content) {
401+
padding-inline: calc(4 * var(--default-grid-baseline));
402+
}
403+
404+
.navigation-list {
405+
height: 100%;
406+
overflow-y: auto;
407+
padding: calc(3 * var(--default-grid-baseline));
310408
311-
&-icon {
409+
&__link {
312410
display: flex;
313-
justify-content: center;
314411
align-content: center;
315-
width: calc(var(--default-clickable-area) - 2 * var(--default-grid-baseline));
316-
max-width: calc(var(--default-clickable-area) - 2 * var(--default-grid-baseline));
412+
font-size: 16px;
413+
height: var(--default-clickable-area);
414+
margin: 4px 0;
415+
line-height: var(--default-clickable-area);
416+
border-radius: var(--border-radius-element);
417+
font-weight: bold;
418+
padding: 0 calc(4 * var(--default-grid-baseline));
419+
cursor: pointer;
420+
white-space: nowrap;
421+
text-overflow: ellipsis;
422+
overflow: hidden;
423+
background-color: transparent;
424+
border: none;
425+
426+
&:hover,
427+
&:focus {
428+
background-color: var(--color-background-hover);
429+
}
430+
431+
&--active {
432+
background-color: var(--color-primary-element-light) !important;
433+
}
434+
435+
&--icon {
436+
padding-inline-start: calc(2 * var(--default-grid-baseline));
437+
gap: var(--default-grid-baseline);
438+
}
439+
440+
&-icon {
441+
display: flex;
442+
justify-content: center;
443+
align-content: center;
444+
width: calc(var(--default-clickable-area) - 2 * var(--default-grid-baseline));
445+
max-width: calc(var(--default-clickable-area) - 2 * var(--default-grid-baseline));
446+
}
317447
}
318448
}
319-
}
320449
321-
@media only screen and (max-width: $breakpoint-small-mobile) {
322-
.app-settings {
450+
@media only screen and (max-width: $breakpoint-small-mobile) {
323451
:deep(.dialog__name) {
324452
padding-inline-start: 16px;
325453
}

src/utils/legacy.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55

6-
const [majorVersion] = window.OC?.config?.version?.split('.') ?? []
7-
export const isLegacy = Number.parseInt(majorVersion ?? '32') < 32
6+
const version = window.OC?.config?.version?.split('.')[0] || '32'
7+
const major = Number.parseInt(version)
8+
export const isLegacy32 = major < 32
9+
export const isLegacy34 = major < 34

0 commit comments

Comments
 (0)