From d4e8e39c0d2a0aa885242801c37ee8064ee5b8a6 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Sat, 13 Sep 2025 17:41:33 +0200 Subject: [PATCH 1/6] docs: add current dark theme styles for proper reviewing Needed so that the styleguide preview is correct. Signed-off-by: Ferdinand Thiessen --- styleguide/assets/dark.css | 193 ++++++++++++++++++++----------------- 1 file changed, 104 insertions(+), 89 deletions(-) diff --git a/styleguide/assets/dark.css b/styleguide/assets/dark.css index d71151fdf4..c625f9d8e4 100644 --- a/styleguide/assets/dark.css +++ b/styleguide/assets/dark.css @@ -3,93 +3,108 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ [data-theme-dark] { - --color-main-background:#171717; - --color-main-background-rgb:23,23,23; - --color-main-background-translucent:rgba(var(--color-main-background-rgb), .97); - --color-main-background-blur:rgba(var(--color-main-background-rgb), .85); - --filter-background-blur:blur(25px); - --gradient-main-background:var(--color-main-background) 0%, var(--color-main-background-translucent) 85%, transparent 100%; - --color-background-hover:#212121; - --color-background-dark:#292929; - --color-background-darker:#3b3b3b; - --color-placeholder-light:#313131; - --color-placeholder-dark:#4a4a4a; - --color-main-text:#EBEBEB; - --color-text-maxcontrast:#999999; - --color-text-maxcontrast-default:#999999; - --color-text-maxcontrast-background-blur:#a8a8a8; - --color-text-light:var(--color-main-text); - --color-text-lighter:var(--color-text-maxcontrast); - --color-scrollbar:#3d3d3d; - --color-error:#FF3333; - --color-error-rgb:255,51,51; - --color-error-hover:#ff6666; - --color-error-text:#ff8080; - --color-warning:#FFCC00; - --color-warning-rgb:255,204,0; - --color-warning-hover:#ffd633; - --color-warning-text:#FFCC00; - --color-success:#3B973B; - --color-success-rgb:59,151,59; - --color-success-hover:#4cb94c; - --color-success-text:#5ec05e; - --color-info:#00AEFF; - --color-info-rgb:0,174,255; - --color-info-hover:#33beff; - --color-info-text:#00AEFF; - --color-favorite:#ffde00; - --color-loading-light:#777; - --color-loading-dark:#CCC; - --color-box-shadow-rgb:0,0,0; - --color-box-shadow:#000000; - --color-border:#292929; - --color-border-dark:#3b3b3b; - --color-border-maxcontrast:#7d7d7d; - --font-face:system-ui, -apple-system, "Segoe UI", Roboto, Oxygen-Sans, Cantarell, Ubuntu, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - --default-font-size:15px; - --default-line-height:24px; - --animation-quick:100ms; - --animation-slow:300ms; - --border-width-input:1px; - --border-width-input-focused:2px; - --border-radius:3px; - --border-radius-large:10px; - --border-radius-rounded:28px; - --border-radius-element:8px; - --border-radius-pill:100px; - --default-clickable-area:34px; - --clickable-area-large:48px; - --clickable-area-small:24px; - --default-grid-baseline:4px; - --header-height:50px; - --header-menu-item-height:44px; - --navigation-width:300px; - --sidebar-min-width:300px; - --sidebar-max-width:500px; - --body-container-radius:calc(var(--default-grid-baseline) * 3); - --body-container-margin:calc(var(--default-grid-baseline) * 2); - --body-height:calc(100% - env(safe-area-inset-bottom) - var(--header-height) - var(--body-container-margin)); - --breakpoint-mobile:1024px; - --background-invert-if-dark:invert(100%); - --background-invert-if-bright:no; - --background-image-invert-if-bright:no; - --primary-invert-if-bright:invert(100%); - --primary-invert-if-dark:no; - --color-primary:#00679e; - --color-primary-text:#ffffff; - --color-primary-hover:#045783; - --color-primary-light:#14232c; - --color-primary-light-text:#99c2d8; - --color-primary-light-hover:#1e2d35; - --color-primary-element:#0091f2; - --color-primary-element-hover:#079cff; - --color-primary-element-text:#000000; - --color-primary-element-text-dark:#0a0a0a; - --color-primary-element-light:#14232c; - --color-primary-element-light-hover:#1e2d35; - --color-primary-element-light-text:#99d3f9; - --gradient-primary-background:linear-gradient(40deg, var(--color-primary) 0%, var(--color-primary-hover) 100%); - --color-background-plain:#00679e; - --color-background-plain-text:#ffffff; - --image-background:url('./img/background/jo-myoung-hee-fluid-dark.webp'); + --color-main-background: #171717; + --color-main-background-rgb: 23, 23, 23; + --color-main-background-translucent: rgba(var(--color-main-background-rgb), .97); + --color-main-background-blur: rgba(var(--color-main-background-rgb), .85); + --filter-background-blur: blur(25px); + --gradient-main-background: var(--color-main-background) 0%, var(--color-main-background-translucent) 85%, transparent 100%; + --color-background-hover: #212121; + --color-background-dark: #292929; + --color-background-darker: #3b3b3b; + --color-placeholder-light: #313131; + --color-placeholder-dark: #4a4a4a; + --color-main-text: #EBEBEB; + --color-text-maxcontrast: #999999; + --color-text-maxcontrast-default: #999999; + --color-text-maxcontrast-background-blur: #a8a8a8; + --color-text-error: #ff6f6f; + --color-text-success: #49bb37; + --color-border: #292929; + --color-border-dark: #3b3b3b; + --color-border-maxcontrast: #7d7d7d; + --color-border-error: var(--color-element-error); + --color-border-success: var(--color-element-success); + --color-element-error: #FF5050; + --color-element-info: #0099E0; + --color-element-success: #40A330; + --color-element-warning: #FFCC00; + --color-error: #552121; + --color-error-hover: #7a2f2f; + --color-error-text: #FFCCCC; + --color-warning: #3D3010; + --color-warning-hover: #65501b; + --color-warning-text: #FFEEC5; + --color-success: #11321A; + --color-success-hover: #1e582e; + --color-success-text: #D5F2DC; + --color-info: #003553; + --color-info-hover: #005686; + --color-info-text: #00AEFF; + --color-favorite: #ffde00; + --color-error-rgb: 85, 33, 33; + --color-warning-rgb: 61, 48, 16; + --color-success-rgb: 17, 50, 26; + --color-info-rgb: 0, 53, 83; + --color-loading-light: #777; + --color-loading-dark: #CCC; + --color-scrollbar: var(--color-border-maxcontrast) transparent; + --color-box-shadow-rgb: 0, 0, 0; + --color-box-shadow: #000000; + --color-background-assistant: #221D2B; + --color-border-assistant: linear-gradient(125deg, #0C3A65 50%, #6204A5 125%); + --color-element-assistant: linear-gradient(238deg, #A569D3 12%, #00679E 39%, #422083 86%); + --color-element-assistant-icon: linear-gradient(285deg, #CDACE7 15.28%, #008FDB 39.98%, #A180E0 82.05%); + --font-face: system-ui, -apple-system, 'Segoe UI', Roboto, Oxygen-Sans, Cantarell, Ubuntu, 'Helvetica Neue', 'Noto Sans', 'Liberation Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --default-font-size: 15px; + --font-size-small: 13px; + --default-line-height: 1.5; + --animation-quick: 100ms; + --animation-slow: 300ms; + --border-width-input: 1px; + --border-width-input-focused: 2px; + --border-radius-small: 4px; + --border-radius-element: 8px; + --border-radius-container: 12px; + --border-radius-container-large: 16px; + --border-radius: var(--border-radius-small); + --border-radius-large: var(--border-radius-element); + --border-radius-rounded: 28px; + --border-radius-pill: 100px; + --default-clickable-area: 34px; + --clickable-area-large: 48px; + --clickable-area-small: 24px; + --default-grid-baseline: 4px; + --header-height: 50px; + --header-menu-item-height: 44px; + --header-menu-icon-mask: linear-gradient(var(--color-background-plain-text) 25%, color-mix(in srgb, var(--color-background-plain-text), 55% transparent) 90%) alpha; + --navigation-width: 300px; + --sidebar-min-width: 300px; + --sidebar-max-width: 500px; + --body-container-radius: var(--border-radius-container-large); + --body-container-margin: calc(var(--default-grid-baseline) * 2); + --body-height: calc(100% - env(safe-area-inset-bottom) - var(--header-height) - var(--body-container-margin)); + --breakpoint-mobile: 1024px; + --background-invert-if-dark: invert(100%); + --background-invert-if-bright: no; + --background-image-invert-if-bright: no; + --primary-invert-if-bright: invert(100%); + --primary-invert-if-dark: no; + --color-primary: #00679e; + --color-primary-text: #ffffff; + --color-primary-hover: #045783; + --color-primary-element: #0091f2; + --color-primary-element-hover: #17a2ff; + --color-primary-element-text: #000000; + --color-primary-element-text-dark: #121212; + --color-primary-light: #14232c; + --color-primary-light-hover: #1f2e36; + --color-primary-light-text: #99c2d8; + --color-primary-element-light: var(--color-primary-light); + --color-primary-element-light-text: var(--color-primary-light-text); + --color-primary-element-light-hover: var(--color-primary-light-hover); + --gradient-primary-background: linear-gradient(40deg, var(--color-primary) 0%, var(--color-primary-hover) 100%); + --color-background-plain: #00679e; + --color-background-plain-text: #ffffff; + --image-background: url('./img/background/jo-myoung-hee-fluid-dark.webp'); } From 7cc7855ca12154d710b8884f22bd4c73f253b8aa Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Sat, 13 Sep 2025 17:39:04 +0200 Subject: [PATCH 2/6] feat: create sharedscss mixin for input border styles This provides proper styles for input like elements with respect for dark theme and legacy Nextcloud version. Signed-off-by: Ferdinand Thiessen --- src/assets/input-border.scss | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/assets/input-border.scss diff --git a/src/assets/input-border.scss b/src/assets/input-border.scss new file mode 100644 index 0000000000..bce394dabb --- /dev/null +++ b/src/assets/input-border.scss @@ -0,0 +1,53 @@ +/*! + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + + @mixin boxShadow($borderColor) { + box-shadow: 0 -1px $borderColor, + 0 0 0 1px color-mix(in srgb, $borderColor, 65% transparent); +} + +@mixin boxShadowDark($borderColor) { + box-shadow: 0 1px $borderColor, + 0 0 0 1px color-mix(in srgb, $borderColor, 65% transparent); +} + +/** + * Similar as inputBorder but without active styles. + */ +@mixin inputLikeBorder($darkThemeSelector, $legacySelector, $borderColor: var(--color-border-maxcontrast)) { + border: none; + border-radius: var(--border-radius-element); + @include boxShadow($borderColor); + + &:hover:not([disabled]) { + box-shadow: 0 0 0 1px $borderColor; + } + + @at-root #{$darkThemeSelector} #{&} { + @include boxShadowDark($borderColor); + } + + @at-root #{$legacySelector} #{&} { + box-shadow: 0 0 0 1px $borderColor; + + &:hover:not([disabled]) { + box-shadow: 0 0 0 2px $borderColor; + } + } +} + +/** + * Create a consistent border for an input element. + * With Nextcloud 32+ there is no real border anymore but we use a box-shadow. + */ +@mixin inputBorder($darkThemeSelector, $legacySelector, $borderColor: var(--color-border-maxcontrast)) { + @include inputLikeBorder($darkThemeSelector, $legacySelector, $borderColor); + + &:focus-within:not([disabled]), + &:active:not([disabled]) { + box-shadow: 0 0 0 2px $borderColor, + 0 0 0 4px var(--color-main-background) !important; + } +} From 6f21bf7eab4fb0884f93e183df18a8a6d525331d Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Sat, 13 Sep 2025 17:39:58 +0200 Subject: [PATCH 3/6] refactor(NcInputField): use new shares scss mixin for input border Signed-off-by: Ferdinand Thiessen --- src/components/NcInputField/NcInputField.vue | 52 +++++--------------- 1 file changed, 11 insertions(+), 41 deletions(-) diff --git a/src/components/NcInputField/NcInputField.vue b/src/components/NcInputField/NcInputField.vue index 096f552e89..4485d275dd 100644 --- a/src/components/NcInputField/NcInputField.vue +++ b/src/components/NcInputField/NcInputField.vue @@ -20,6 +20,7 @@ For a list of all available props and attributes, please check the [HTMLInputEle
+@use '../../assets/input-border.scss' as border; .input-field { --input-border-color: var(--color-border-maxcontrast); --input-border-radius: var(--border-radius-element); - // Used e.g. if border width differs between focused and unfocused we need to compensate to prevent jumping - --input-border-width-offset: calc(var(--border-width-input-focused, 2px) - var(--border-width-input, 2px)); // The padding before the input can start (leading button or border) --input-padding-start: var(--border-radius-large); // The padding where the input has to end (trailing button or border) @@ -408,23 +412,15 @@ export default { &__main-wrapper { height: var(--default-clickable-area); - padding: var(--border-width-input, 2px); + padding: var(--border-width-input-focused, 2px); position: relative; - - &:not(:has([disabled])):has(input:focus), - &:not(:has([disabled])):has(input:active) { - padding: 0; - } } &__input { + @include border.inputBorder('.input-field--dark', '.input-field--legacy', var(--input-border-color)); background-color: var(--color-main-background); color: var(--color-main-text); - border: none; border-radius: var(--input-border-radius); - box-shadow: - 0 -1px var(--input-border-color), - 0 0 0 1px color-mix(in srgb, var(--input-border-color), 65% transparent); cursor: pointer; -webkit-appearance: textfield !important; @@ -434,11 +430,11 @@ export default { font-size: var(--default-font-size); text-overflow: ellipsis; + padding-block: 0; + padding-inline: var(--input-padding-start) var(--input-padding-end); height: 100% !important; min-height: unset; width: 100%; - padding-block: var(--input-border-width-offset); - padding-inline: calc(var(--input-padding-start) + var(--input-border-width-offset)) calc(var(--input-padding-end) + var(--input-border-width-offset)); &::placeholder { color: var(--color-text-maxcontrast); @@ -458,17 +454,9 @@ export default { display: none; } - &:hover:not([disabled]) { - box-shadow: 0 0 0 1px var(--input-border-color);; - } - &:active:not([disabled]), &:focus:not([disabled]) { --input-border-color: var(--color-main-text); - // Reset padding offset when focused - --input-border-width-offset: 0px; - border: var(--border-width-input-focused, 2px) solid var(--input-border-color); - box-shadow: 0 0 0 2px var(--color-main-background) !important; } &:focus + .input-field__label, @@ -611,23 +599,5 @@ export default { } } } - - &--legacy { - .input-field__input { - box-shadow: 0 0 0 1px var(--input-border-color) inset; - } - - .input-field__main-wrapper:hover:not(:has([disabled])) { - padding: 0; - - .input-field__input { - --input-border-color: var(--color-main-text); - // Reset padding offset when focused - --input-border-width-offset: 0px; - border: var(--border-width-input-focused, 2px) solid var(--input-border-color); - box-shadow: 0 0 0 2px var(--color-main-background) !important; - } - } - } } From ccf3cd6e0f5997bb7e711b73c4422cb4d350c943 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Sat, 13 Sep 2025 17:40:42 +0200 Subject: [PATCH 4/6] refactor(NcTextArea): use shared scss mixin for input border Signed-off-by: Ferdinand Thiessen --- src/components/NcTextArea/NcTextArea.vue | 51 ++++++------------------ 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/src/components/NcTextArea/NcTextArea.vue b/src/components/NcTextArea/NcTextArea.vue index 4e5ad5b881..297e8e1ed5 100644 --- a/src/components/NcTextArea/NcTextArea.vue +++ b/src/components/NcTextArea/NcTextArea.vue @@ -91,6 +91,7 @@ It extends and styles an HTMLTextAreaElement.
@@ -141,6 +142,7 @@ It extends and styles an HTMLTextAreaElement. From a2aeca4c514c52bb923f692a7f579db84f6bbdee Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Sat, 13 Sep 2025 17:41:10 +0200 Subject: [PATCH 5/6] fix(NcSelect): use shared scss mixin to apply new input design changes Signed-off-by: Ferdinand Thiessen --- src/components/NcSelect/NcSelect.vue | 42 ++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/components/NcSelect/NcSelect.vue b/src/components/NcSelect/NcSelect.vue index b30b7f5233..bc29e59c10 100644 --- a/src/components/NcSelect/NcSelect.vue +++ b/src/components/NcSelect/NcSelect.vue @@ -325,6 +325,8 @@ export default {