/*! * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-or-later */ @use 'variables'; @use 'sass:color'; @use 'functions'; /* Specifically override browser styles */ input, textarea, select, button, div[contenteditable=true], div[contenteditable=false] { font-family: var(--font-face); } .select2-container-multi .select2-choices .select2-search-field input, .select2-search input, .ui-widget { font-family: var(--font-face) !important; } .select2-container.select2-drop-above .select2-choice { background-image: unset !important; } $opacity-disabled: .7; /* Simple selector to allow easy overriding */ select, button:not( .button-vue, /* "vs__" class prefix is used in the vue-select lib */ [class^="vs__"] ), input, textarea, div[contenteditable=true], div[contenteditable=false] { width: 130px; min-height: var(--default-clickable-area); box-sizing: border-box; } /** * color-main-text normal state * color-main-text active state * color-text-maxcontrast disabled state */ button:not(.button-vue), input:not([type='range']), textarea { &:disabled { cursor: default; color: var(--color-text-maxcontrast); border-color: var(--color-border-dark); opacity: $opacity-disabled; } } input:not([type="range"]) { outline: none; } /* Default global values */ div.select2-drop .select2-search input, // TODO: REMOVE WHEN DROPPING SELECT2 input[type='submit'], input[type='button'], input[type='reset'], button:not( .button-vue, [class^="vs__"] ), .button, .pager li a { padding: 7px 14px; background-color: var(--color-main-background); color: var(--color-main-text); border: 1px solid var(--color-border-dark); font-size: var(--default-font-size); outline: none; border-radius: var(--border-radius); cursor: text; &:not(.app-navigation-entry-button) { margin: 3px; margin-inline-start: 0; } &:not( :disabled, .primary ) { &:not(.app-navigation-entry-button) { &:hover, &:focus, &.active { /* active class used for multiselect */ border-color: var(--color-main-text); outline: none; } &:active { outline: none; background-color: var(--color-main-background); color: var(--color-main-text); } } &:focus-visible { box-shadow: 0 0 0 4px var(--color-main-background) !important; outline: 2px solid var(--color-main-text) !important; } } &:disabled { background-color: var(--color-background-dark); color: var(--color-main-text); cursor: default; opacity: 0.5; } &:required { box-shadow: none; } &:user-invalid { box-shadow: 0 0 0 2px var(--color-error) !important; } /* Primary action button, use sparingly */ &.primary { background-color: var(--color-primary-element); border-color: var(--color-primary-element); color: var(--color-primary-element-text); cursor: pointer; /* Apply border to primary button if on log in page (and not in a dark container) or if in header */ #body-login :not(.body-login-container) &, #header & { border-color: var(--color-primary-element-text); } &:not(:disabled) { &:hover, &:focus, &:active { background-color: var(--color-primary-element-hover); border-color: var(--color-primary-element-hover); } &:focus, &:focus-visible { box-shadow: 0 0 0 2px var(--color-main-text); } &:active { color: var(--color-primary-element-text-dark); } } &:disabled { // opacity is already defined to .5 if disabled background-color: var(--color-primary-element); color: var(--color-primary-element-text-dark); cursor: default; } } } div[contenteditable=false] { margin: 3px; margin-inline-start: 0; padding: 7px 6px; font-size: 13px; border: 1px solid var(--color-background-darker); outline: none; border-radius: var(--border-radius); background-color: var(--color-background-dark); color: var(--color-text-maxcontrast); cursor: default; opacity: 0.5; } /* Specific override */ input { &:not([type='radio']):not([type='checkbox']):not([type='range']):not([type='submit']):not([type='button']):not([type='reset']):not([type='color']):not([type='file']):not([type='image']) { -webkit-appearance: textfield; -moz-appearance: textfield; appearance: textfield; // force height for inline elements like inputs (not textarea, contenteditable...) height: var(--default-clickable-area); } &[type='radio'], &[type='checkbox'], &[type='file'], &[type='image'] { height: auto; width: auto; } /* Color input doesn't respect the initial height so we need to set a custom one */ &[type='color'] { margin: 3px; padding: 0 2px; min-height: 30px; width: 40px; cursor: pointer; } &[type='hidden'] { height: 0; width: 0; } &[type='time'] { width: initial; } } /* 'Click' inputs */ select, button:not( .button-vue, [class^="vs__"] ), .button, input[type='button'], input[type='submit'], input[type='reset'] { padding: calc((var(--default-clickable-area) - 1lh) / 2) calc(3 * var(--default-grid-baseline)); font-size: var(--default-font-size); width: auto; min-height: var(--default-clickable-area); cursor: pointer; box-sizing: border-box; color: var(--color-primary-element-light-text); background-color: var(--color-primary-element-light); border: none; &:hover, &:focus { background-color: var(--color-primary-element-light-hover); } &:disabled { cursor: default; } } input:not( [type='range'], .input-field__input, [type='submit'], [type='button'], [type='reset'], .multiselect__input, .select2-input, .action-input__input, [class^="vs__"] ), select, div[contenteditable=true], textarea { margin: 3px; margin-inline-start: 0; padding: 0 12px; font-size: var(--default-font-size); background-color: var(--color-main-background); color: var(--color-main-text); border: 2px solid var(--color-border-maxcontrast); height: 36px; outline: none; border-radius: var(--border-radius-large); text-overflow: ellipsis; cursor: pointer; &:not(:disabled):hover, &:not(:disabled):focus, &:not(:disabled):active { border-color: 2px solid var(--color-main-text); box-shadow: 0 0 0 2px var(--color-main-background); } &:not(:disabled):focus { cursor: text; } } .multiselect__input, .select2-input { background-color: var(--color-main-background); color: var(--color-main-text); } textarea, div[contenteditable=true] { padding: 12px; height: auto; } /* Override the ugly select arrow */ select { background: var(--icon-triangle-s-dark) no-repeat; appearance: none; background-color: var(--color-main-background); padding-inline-end: 28px !important; } body[dir='ltr'] select { background-position: right 8px center; } body[dir='rtl'] select { background-position: left 8px center; } select, button:not( .button-vue, [class^="vs__"] ), .button { * { cursor: pointer; } &:disabled { * { cursor: default; } } } /* Buttons */ button:not( .button-vue, [class^="vs__"] ), .button, input[type='button'], input[type='submit'], input[type='reset'] { font-weight: bold; border-radius: var(--border-radius-element); /* Get rid of the inside dotted line in Firefox */ &::-moz-focus-inner { border: 0; } &.error { background-color: var(--color-error) !important; border-color: var(--color-error) !important; color: #fff !important; &:hover{ background-color: var(--color-error-hover) !important; border-color: var(--color-main-text) !important; } } } button:not( .button-vue, .action-button, [class^="vs__"] ), .button { > span { /* icon position inside buttons */ &[class^='icon-'], &[class*=' icon-'] { display: inline-block; vertical-align: text-bottom; opacity: 0.5; } } } /* Confirm inputs */ input[type='text'], input[type='password'], input[type='email'] { + .icon-confirm { margin-inline-start: -13px !important; border-inline-start-color: transparent !important; border-radius: 0 var(--border-radius-large) var(--border-radius-large) 0 !important; border-width: 2px; background-clip: padding-box; /* Avoid background under border */ background-color: var(--color-main-background) !important; opacity: 1; height: var(--default-clickable-area); width: var(--default-clickable-area); padding: 7px 6px; cursor: pointer; margin-inline-end: 0; &:disabled { cursor: default; @include functions.icon-color('confirm-fade', 'actions', variables.$color-black, 2, true); } } /* only show confirm borders if input is not focused */ &:not(:active):not(:hover):not(:focus){ &:invalid { + .icon-confirm { border-color: var(--color-error); } } + .icon-confirm { &:active, &:hover, &:focus { border-color: var(--color-primary-element) !important; border-radius: var(--border-radius) !important; &:disabled { border-color: var(--color-background-darker) !important; } } } } &:active, &:hover, &:focus { + .icon-confirm { border-color: var(--color-primary-element) !important; border-inline-start-color: transparent !important; /* above previous input */ z-index: 2; } } } /* Various Fixes */ button img, .button img { cursor: pointer; } select, .button.multiselect { font-weight: normal; } /* Radio & Checkboxes */ $checkbox-radio-size: 14px; $color-checkbox-radio-white: #fff; input[type='checkbox'], input[type='radio'] { &.radio, &.checkbox { position: absolute; inset-inline-start: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; + label { user-select: none; } &:disabled + label, &:disabled + label:before { cursor: default; } + label:before { content: ''; display: inline-block; height: $checkbox-radio-size; width: $checkbox-radio-size; vertical-align: middle; border-radius: 50%; margin: 0 3px; margin-inline: 3px 6px; border: 1px solid var(--color-text-maxcontrast); } &:not(:disabled):not(:checked) + label:hover:before, &:focus + label:before { border-color: var(--color-primary-element); } &:focus-visible + label { outline-style: solid; outline-color: var(--color-main-text); outline-width: 1px; outline-offset: 2px; } &:checked + label:before, &.checkbox:indeterminate + label:before { /* ^ :indeterminate have a strange behavior on radio, so we respecified the checkbox class again to be safe */ box-shadow: inset 0px 0px 0px 2px var(--color-main-background); background-color: var(--color-primary-element); border-color: var(--color-primary-element); } &:disabled + label:before { border: 1px solid var(--color-text-maxcontrast); background-color: var(--color-text-maxcontrast) !important; /* override other status */ } &:checked:disabled + label:before { background-color: var(--color-text-maxcontrast); } // Detail description below label of checkbox or radio button & + label ~ em { display: inline-block; margin-inline-start: 25px; } & + label ~ em:last-of-type { margin-bottom: $checkbox-radio-size; } } &.checkbox { + label:before { border-radius: 1px; height: $checkbox-radio-size; width: $checkbox-radio-size; box-shadow: none !important; background-position: center; } &:checked + label:before { background-image: url('../img/actions/checkbox-mark.svg'); } &:indeterminate + label:before { background-image: url('../img/actions/checkbox-mixed.svg'); } } /* We do not use the variables as we keep the colours as white for this variant */ &.radio--white, &.checkbox--white { + label:before, &:focus + label:before { border-color: color.adjust($color-checkbox-radio-white, $lightness: -27%, $space: hsl); } &:not(:disabled):not(:checked) + label:hover:before { border-color: $color-checkbox-radio-white; } &:checked + label:before { box-shadow: inset 0px 0px 0px 2px var(--color-main-background); background-color: color.adjust($color-checkbox-radio-white, $lightness: -14%, $space: hsl); border-color: color.adjust($color-checkbox-radio-white, $lightness: -14%, $space: hsl); } &:disabled + label:before { background-color: color.adjust($color-checkbox-radio-white, $lightness: -27%, $space: hsl) !important; /* override other status */ border-color: rgba($color-checkbox-radio-white, 0.4) !important; /* override other status */ } &:checked:disabled + label:before { box-shadow: inset 0px 0px 0px 2px var(--color-main-background); border-color: rgba($color-checkbox-radio-white, 0.4) !important; /* override other status */ background-color: color.adjust($color-checkbox-radio-white, $lightness: -27%, $space: hsl); } } &.checkbox--white { &:checked + label:before, &:indeterminate + label:before { background-color: transparent !important; /* Override default checked */ border-color: $color-checkbox-radio-white !important; /* Override default checked */ background-image: url('../img/actions/checkbox-mark-white.svg'); } &:indeterminate + label:before { background-image: url('../img/actions/checkbox-mixed-white.svg'); } &:disabled + label:before { opacity: 0.7; /* No other choice for white background image */ } } } /* Select2 overriding. Merged to core with vendor stylesheet */ div.select2-drop { margin-top: -2px; background-color: var(--color-main-background); &.select2-drop-active { border-color: var(--color-border-dark); } .avatar { display: inline-block; margin-inline-end: 8px; vertical-align: middle; img { cursor: pointer; } } .select2-search input { min-height: auto; background: var(--icon-search-dark) no-repeat !important; background-origin: content-box !important; } .select2-results { max-height: 250px; margin: 0; padding: 0; .select2-result-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; span { cursor: pointer; em { cursor: inherit; background: unset; } } } .select2-result, .select2-no-results, .select2-searching { position: relative; display: list-item; padding: 12px; background-color: transparent; cursor: pointer; color: var(--color-text-maxcontrast); } .select2-result { &.select2-selected { background-color: var(--color-background-dark); } } .select2-highlighted { background-color: var(--color-background-dark); color: var(--color-main-text); } } } body[dir='ltr'] div.select2-drop .select2-search input { background-position: right center !important; } body[dir='rtl'] div.select2-drop .select2-search input { background-position: left center !important; } .select2-chosen, #select2-drop { .avatar, .avatar img { cursor: pointer; } } div.select2-container-multi { .select2-choices, &.select2-container-active .select2-choices { box-shadow: none; white-space: nowrap; text-overflow: ellipsis; background: var(--color-main-background); color: var(--color-text-maxcontrast) !important; box-sizing: content-box; border-radius: var(--border-radius-large); border: 2px solid var(--color-border-dark); margin: 0; padding: 6px; min-height: 44px; &:focus-within { border-color: var(--color-primary-element) } .select2-search-choice { line-height: 20px; padding-inline-start: 5px; &.select2-search-choice-focus, &:hover, &:active, & { background-image: none; background-color: var(--color-main-background); color: var(--color-text-maxcontrast); border: 1px solid var(--color-border-dark); } .select2-search-choice-close { display: none; } } .select2-search-field input { line-height: 20px; min-height: 28px; max-height: 28px; color: var(--color-main-text); &.select2-active { background: none !important; } } } } div.select2-container { margin: 3px; margin-inline-start: 0; &.select2-container-multi .select2-choices { display: flex; flex-wrap: wrap; li { float: none; } } a.select2-choice { box-shadow: none; white-space: nowrap; text-overflow: ellipsis; background: var(--color-main-background); color: var(--color-text-maxcontrast) !important; box-sizing: content-box; border-radius: var(--border-radius-large); border: 2px solid var(--color-border-dark); margin: 0; padding: 6px 12px; min-height: 44px; &:focus-within { border-color: var(--color-primary-element) } .select2-search-choice { line-height: 20px; padding-inline-start: 5px; background-image: none; background-color: var(--color-background-dark); border-color: var(--color-background-dark); .select2-search-choice-close { display: none; } &.select2-search-choice-focus, &:hover { background-color: var(--color-border); border-color: var(--color-border); } } .select2-arrow { background: none; border-radius: 0; border: none; b { background: var(--icon-triangle-s-dark) no-repeat center !important; opacity: .5; } } &:hover .select2-arrow b, &:focus .select2-arrow b, &:active .select2-arrow b { opacity: .7; } .select2-search-field input { line-height: 20px; } } } /* Vue v-select */ .v-select { margin: 3px; margin-inline-start: 0; display: inline-block; .dropdown-toggle { display: flex !important; flex-wrap: wrap; .selected-tag { line-height: 20px; padding-inline-start: 5px; background-image: none; background-color: var(--color-main-background); color: var(--color-text-maxcontrast); border: 1px solid var(--color-border-dark); display: inline-flex; align-items: center; .close { margin-inline-start: 3px; } } } .dropdown-menu { padding: 0; li { padding: 5px; position: relative; display: list-item; background-color: transparent; cursor: pointer; color: var(--color-text-maxcontrast); a { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; height: 25px; padding-block: 3px 4px; padding-inline: 2px 7px; margin: 0; cursor: pointer; min-height: 1em; -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; display: inline-flex; align-items: center; background-color: transparent !important; color: inherit !important; &::before { content: ' '; background-image: var(--icon-checkmark-dark); background-repeat: no-repeat; background-position: center; min-width: 16px; min-height: 16px; display: block; opacity: 0.5; margin-inline-end: 5px; visibility: hidden; } } &.highlight { color: var(--color-main-text); } &.active > a { background-color: var(--color-background-dark); color: var(--color-main-text); &::before { visibility: visible; } } } } } /* Progressbar */ progress:not(.vue) { display: block; width: 100%; padding: 0; border: 0 none; background-color: var(--color-background-dark); border-radius: var(--border-radius); flex-basis: 100%; height: 5px; overflow: hidden; &.warn { &::-moz-progress-bar { background: var(--color-error); } &::-webkit-progress-value { background: var(--color-error); } } &::-webkit-progress-bar { background: transparent; } &::-moz-progress-bar { border-radius: var(--border-radius); background: var(--color-primary-element); transition: 250ms all ease-in-out; } &::-webkit-progress-value { border-radius: var(--border-radius); background: var(--color-primary-element); transition: 250ms all ease-in-out; } } /* Animation */ @keyframes shake { 10%, 90% { transform: translate(-1px); } 20%, 80% { transform: translate(2px); } 30%, 50%, 70% { transform: translate(-4px); } 40%, 60% { transform: translate(4px); } } .shake { animation-name: shake; animation-duration: .7s; animation-timing-function: ease-out; } // Keep the labels for screen readers but hide them since we use placeholders // Same as .hidden-visually label.infield { position: absolute; inset-inline-start: -10000px; top: -10000px; width: 1px; height: 1px; overflow: hidden; } // when rules are grouped using the comma operator and one selector is invalid / unknown then the whole group is invalidated. // https://www.w3.org/TR/selectors-3/#grouping // In this case `::-ms-input-placeholder` is unknown to Firefox and Chrome @mixin placeholder-style { color: var(--color-text-maxcontrast); font-size: var(--default-font-size); } ::placeholder { @include placeholder-style; } ::-ms-input-placeholder { @include placeholder-style; } ::-webkit-input-placeholder { @include placeholder-style; }