aboutsummaryrefslogtreecommitdiffstats
path: root/core/css/inputs.scss
diff options
context:
space:
mode:
Diffstat (limited to 'core/css/inputs.scss')
-rw-r--r--core/css/inputs.scss896
1 files changed, 896 insertions, 0 deletions
diff --git a/core/css/inputs.scss b/core/css/inputs.scss
new file mode 100644
index 00000000000..27136b69ad4
--- /dev/null
+++ b/core/css/inputs.scss
@@ -0,0 +1,896 @@
+/*!
+ * 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;
+}