/** * @copyright Copyright (c) 2016, John Molakvoæ * @copyright Copyright (c) 2016, Morris Jobke * @copyright Copyright (c) 2016, Joas Schilling * @copyright Copyright (c) 2016, Julius Haertl * @copyright Copyright (c) 2016, jowi * @copyright Copyright (c) 2015, Joas Schilling * @copyright Copyright (c) 2015, Hendrik Leppelsack * @copyright Copyright (c) 2014-2017, Jan-Christoph Borchardt * * @license GNU AGPL version 3 or any later version * */ @use 'variables'; @import '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; } $default-height: 34px; /* Simple selector to allow easy overriding */ select, button:not(.button-vue), input, textarea, div[contenteditable=true], div[contenteditable=false] { width: 130px; min-height: $default-height; box-sizing: border-box; } /** * color-text-lighter normal state * color-text-lighter active state * color-text-maxcontrast disabled state */ /* Default global values */ div.select2-drop .select2-search input, // TODO: REMOVE WHEN DROPPING SELECT2 select, button:not(.button-vue), .button, input:not([type='range']), textarea, div[contenteditable=true], .pager li a { margin: 3px 3px 3px 0; padding: 7px 6px; font-size: 13px; background-color: var(--color-main-background); color: var(--color-main-text); border: 1px solid var(--color-border-dark); outline: none; border-radius: var(--border-radius); cursor: text; &:not(:disabled):not(.primary) { &:hover, &:focus, &.active { /* active class used for multiselect */ border-color: var(--color-primary-element); outline: none; } &:active { outline: none; background-color: var(--color-main-background); color: var(--color-text-light); } } &:disabled { background-color: var(--color-background-dark); color: var(--color-text-maxcontrast); cursor: default; opacity: 0.5; } &:required { box-shadow: none; } &:invalid { box-shadow: none !important; border-color: var(--color-error); } /* Primary action button, use sparingly */ &.primary { background-color: var(--color-primary-element); border-color: var(--color-primary-element); color: var(--color-primary-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-text); } &:not(:disabled) { &:hover, &:focus, &:active { background-color: var(--color-primary-element-light); border-color: var(--color-primary-element-light); } &:active { color: var(--color-primary-text-dark); } } &:disabled { // opacity is already defined to .5 if disabled background-color: var(--color-primary-element); color: var(--color-primary-text-dark); cursor: default; } } } div[contenteditable=false] { margin: 3px 3px 3px 0; padding: 7px 6px; font-size: 13px; background-color: var(--color-main-background); color: var(--color-text-lighter); border: 1px solid var(--color-background-darker); outline: none; border-radius: var(--border-radius); background-color: var(--color-background-dark); color: var(--color-text-lighter); 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; // force height for inline elements like inputs (not textarea, contenteditable...) height: $default-height; } &[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), .button, input[type='button'], input[type='submit'], input[type='reset'] { padding: 6px 16px; width: auto; min-height: $default-height; cursor: pointer; box-sizing: border-box; background-color: var(--color-background-dark); &:disabled { cursor: default; } } select, button:not(.button-vue), .button { * { cursor: pointer; } &:disabled { * { cursor: default; } } } /* Buttons */ button:not(.button-vue), .button, input[type='button'], input[type='submit'], input[type='reset'] { font-weight: bold; border-radius: var(--border-radius-pill); /* 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; } } button:not(.button-vue):not(.action-button), .button { > span { /* icon position inside buttons */ &[class^='icon-'], &[class*=' icon-'] { display: inline-block; vertical-align: text-bottom; opacity: 0.5; } } } textarea, div[contenteditable=true] { color: var(--color-main-text); cursor: text; font-family: inherit; height: auto; &:not(:disabled) { &:active, &:hover, &:focus { border-color: var(--color-background-darker) !important; background-color: var(--color-main-background) !important; } } } div[contenteditable=false] { color: var(--color-text-lighter); font-family: inherit; height: auto; } /* Override the ugly select arrow */ select { -webkit-appearance: none; -moz-appearance: none; appearance: none; background: var(--icon-triangle-s-dark) no-repeat right 4px center; background-color: inherit; outline: 0; padding-right: 24px !important; // force height for inline elements like inputs (not textarea, contenteditable...) height: $default-height; } /* Confirm inputs */ input { &[type='text'], &[type='password'], &[type='email'] { + .icon-confirm { margin-left: -8px !important; border-left-color: transparent !important; border-radius: 0 var(--border-radius) var(--border-radius) 0 !important; background-clip: padding-box; /* Avoid background under border */ background-color: var(--color-main-background) !important; opacity: 1; height: $default-height; width: $default-height; padding: 7px 6px; cursor: pointer; margin-right: 0; &:disabled { cursor: default; @include 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-left-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'], &[type='radio'] { &.radio, &.checkbox { position: absolute; left: -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 6px 3px 3px; border: 1px solid var(--color-text-lighter); } &: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-lighter); 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-left: 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: darken($color-checkbox-radio-white, 27%); } &: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: darken($color-checkbox-radio-white, 14%); border-color: darken($color-checkbox-radio-white, 14%); } &:disabled + label:before { background-color: darken($color-checkbox-radio-white, 27%) !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: darken($color-checkbox-radio-white, 27%); } } &.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-right: 8px; vertical-align: middle; img { cursor: pointer; } } .select2-search input { min-height: auto; background: var(--icon-search-dark) no-repeat right center !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-lighter); } .select2-result { &.select2-selected { background-color: var(--color-background-dark); } } .select2-highlighted { background-color: var(--color-background-dark); color: var(--color-main-text); } } } .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-lighter) !important; box-sizing: content-box; border-radius: var(--border-radius); border: 1px solid var(--color-border-dark); margin: 0; padding: 2px 0; min-height: auto; .select2-search-choice { line-height: 20px; padding-left: 5px; &.select2-search-choice-focus, &:hover, &:active, & { background-image: none; background-color: var(--color-main-background); color: var(--color-text-lighter); border: 1px solid var(--color-border-dark); } .select2-search-choice-close { display: none; } } .select2-search-field input { line-height: 20px; &.select2-active { background: none !important; } } } } div.select2-container { margin: 3px 3px 3px 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-lighter) !important; box-sizing: content-box; border-radius: var(--border-radius); border: 1px solid var(--color-border-dark); margin: 0; padding: 2px 0; padding-left: 6px; min-height: auto; .select2-search-choice { line-height: 20px; padding-left: 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 3px 3px 0; display: inline-block; .dropdown-toggle { display: flex !important; flex-wrap: wrap; .selected-tag { line-height: 20px; padding-left: 5px; background-image: none; background-color: var(--color-main-background); color: var(--color-text-lighter); border: 1px solid var(--color-border-dark); display: inline-flex; align-items: center; .close { margin-left: 3px; } } } .dropdown-menu { padding: 0; li { padding: 5px; position: relative; display: list-item; background-color: transparent; cursor: pointer; color: var(--color-text-lighter); a { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; height: 25px; padding: 3px 7px 4px 2px; 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-right: 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; } } } } } /* Vue multiselect */ .multiselect.multiselect-vue { margin: 1px 2px; padding: 0 !important; display: inline-block; width: 160px; position: relative; background-color: var(--color-main-background); &.multiselect--active { /* Opened: force display the input */ input.multiselect__input { opacity: 1 !important; cursor: text !important; } } &.multiselect--disabled, &.multiselect--disabled .multiselect__single { background-color: var(--color-background-dark) !important; } .multiselect__tags { /* space between tags and limit tag */ $space-between: 5px; display: flex; flex-wrap: nowrap; overflow: hidden; border: 1px solid var(--color-border-dark); cursor: pointer; position: relative; border-radius: var(--border-radius); height: $default-height; /* tag wrapper */ .multiselect__tags-wrap { align-items: center; display: inline-flex; overflow: hidden; max-width: 100%; position: relative; padding: 3px $space-between; flex-grow: 1; /* no tags or simple select? Show input directly input is used to display single value */ &:empty ~ input.multiselect__input { opacity: 1 !important; /* hide default empty text, show input instead */ + span:not(.multiselect__single) { display: none; } } /* selected tag */ .multiselect__tag { flex: 1 0 0; line-height: 20px; padding: 1px 5px; background-image: none; color: var(--color-text-lighter); border: 1px solid var(--color-border-dark); display: inline-flex; align-items: center; border-radius: var(--border-radius); /* require to override the default width and force the tag to shring properly */ min-width: 0; max-width: 50%; max-width: fit-content; max-width: -moz-fit-content; /* css hack, detect if more than two tags if so, flex-basis is set to half */ &:only-child { flex: 0 1 auto; } &:not(:last-child) { margin-right: $space-between; } /* ellipsis the groups to be sure we display at least two of them */ > span { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } } } /* Single select default value */ .multiselect__single { padding: 8px 10px; flex: 0 0 100%; z-index: 1; /* above input */ background-color: var(--color-main-background); cursor: pointer; line-height: 17px; } /* displayed text if tag limit reached */ .multiselect__strong, .multiselect__limit { flex: 0 0 auto; line-height: 20px; color: var(--color-text-lighter); display: inline-flex; align-items: center; opacity: .7; margin-right: $space-between; /* above the input */ z-index: 5; } /* default multiselect input for search and placeholder */ input.multiselect__input { width: 100% !important; position: absolute !important; margin: 0; opacity: 0; /* let's leave it on top of tags but hide it */ height: 100%; border: none; /* override hide to force show the placeholder */ display: block !important; /* only when not active */ cursor: pointer; } } /* results wrapper */ .multiselect__content-wrapper { position: absolute; width: 100%; margin-top: -1px; border: 1px solid var(--color-border-dark); background: var(--color-main-background); z-index: 50; max-height: 175px !important; // 5 items and a half overflow-y: auto; .multiselect__content { width: 100%; padding: 5px 0; } li { padding: 5px; position: relative; display: flex; align-items: center; background-color: transparent; &, span { cursor: pointer; } > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; height: 20px; margin: 0; 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: var(--color-text-lighter); width: 100%; /* selected checkmark icon */ &::before { content: ' '; background-image: var(--icon-checkmark-dark); background-repeat: no-repeat; background-position: center; min-width: 16px; min-height: 16px; display: block; opacity: .5; margin-right: 5px; visibility: hidden; } &.multiselect__option--disabled { background-color: var(--color-background-dark); opacity: .5; } /* add the prop tag-placeholder="create" to add the + * icon on top of an unknown-and-ready-to-be-created entry */ &[data-select='create'] { &::before { background-image: var(--icon-add-dark); visibility: visible; } } &.multiselect__option--highlight { color: var(--color-main-text); } &:not(.multiselect__option--disabled):hover::before { opacity: .3; } &.multiselect__option--selected, &:not(.multiselect__option--disabled):hover { &::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); transition: 250ms all ease-in-out; } &::-webkit-progress-value { border-radius: var(--border-radius); background: var(--color-primary); 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; left: -10000px; top: -10000px; width: 1px; height: 1px; overflow: hidden; } ::placeholder, ::-ms-input-placeholder, ::-webkit-input-placeholder { color: var(--color-text-maxcontrast); }