diff --git a/messages/uniworx/de.msg b/messages/uniworx/de.msg index 08f096088..0616590e1 100644 --- a/messages/uniworx/de.msg +++ b/messages/uniworx/de.msg @@ -87,6 +87,7 @@ CourseRegisterToTip: Anmeldung darf auch unbegrenzt offen bleiben CourseDeregisterUntilTip: Abmeldung darf auch unbegrenzt erlaubt bleiben CourseFilterSearch: Volltext-Suche CourseFilterRegistered: Registriert +CourseFilterNone: Egal CourseDeleteQuestion: Wollen Sie den unten aufgeführten Kurs wirklich löschen? CourseDeleted: Kurs gelöscht CourseUserNote: Notiz diff --git a/src/Foundation.hs b/src/Foundation.hs index 718c1c705..047e3f670 100644 --- a/src/Foundation.hs +++ b/src/Foundation.hs @@ -1035,9 +1035,11 @@ siteLayout' headingOverride widget = do addStylesheet $ StaticR css_utils_asyncForm_scss addStylesheet $ StaticR css_utils_asyncTable_scss addStylesheet $ StaticR css_utils_asyncTableFilter_scss + addStylesheet $ StaticR css_utils_checkbox_scss addStylesheet $ StaticR css_utils_form_scss addStylesheet $ StaticR css_utils_inputs_scss addStylesheet $ StaticR css_utils_modal_scss + addStylesheet $ StaticR css_utils_radio_scss addStylesheet $ StaticR css_utils_showHide_scss addStylesheet $ StaticR css_utils_tabber_scss addStylesheet $ StaticR css_utils_tooltip_scss diff --git a/static/css/utils/asidenav.scss b/static/css/utils/asidenav.scss index 51fe73163..1ac580d58 100644 --- a/static/css/utils/asidenav.scss +++ b/static/css/utils/asidenav.scss @@ -57,7 +57,7 @@ padding-left: 10px; &.js-show-hide__toggle::before { - top: 25px; + z-index: 1; } } } @@ -103,7 +103,6 @@ &::before { left: auto; right: 20px; - top: 30px; color: var(--color-font); } } @@ -314,6 +313,10 @@ word-break: break-all; background-color: var(--color-dark); color: var(--color-lightwhite); + + &:hover { + background-color: var(--color-dark); + } } .asidenav__link-shorthand { diff --git a/static/css/utils/checkbox.scss b/static/css/utils/checkbox.scss new file mode 100644 index 000000000..4cab1568e --- /dev/null +++ b/static/css/utils/checkbox.scss @@ -0,0 +1,74 @@ + +/* CUSTOM CHECKBOXES */ +/* Completely replaces legacy checkbox */ +.checkbox { + position: relative; + display: inline-block; + + [type="checkbox"] { + position: fixed; + top: -1px; + left: -1px; + width: 1px; + height: 1px; + overflow: hidden; + } + + label { + display: block; + height: 24px; + width: 24px; + background-color: #f3f3f3; + box-shadow: inset 0 1px 2px 1px rgba(50, 50, 50, 0.05); + border: 2px solid var(--color-primary); + border-radius: 4px; + color: white; + cursor: pointer; + } + + label::before, + label::after { + position: absolute; + display: block; + top: 12px; + left: 8px; + height: 2px; + width: 8px; + background-color: var(--color-font); + } + + :checked + label { + background-color: var(--color-primary); + } + + [type="checkbox"]:focus + label { + border-color: #3273dc; + box-shadow: 0 0 0 0.125em rgba(50,115,220,.25); + outline: 0; + } + + :checked + label::before, + :checked + label::after { + content: ''; + } + + :checked + label::before { + background-color: white; + transform: rotate(45deg); + left: 4px; + } + + :checked + label::after { + background-color: white; + transform: rotate(-45deg); + top: 11px; + width: 13px; + } + + [disabled] + label { + pointer-events: none; + border: none; + opacity: 0.6; + filter: grayscale(1); + } +} diff --git a/static/css/utils/inputs.scss b/static/css/utils/inputs.scss index f30155892..05f60e294 100644 --- a/static/css/utils/inputs.scss +++ b/static/css/utils/inputs.scss @@ -183,130 +183,6 @@ option { } } -/* CUSTOM LEGACY CHECKBOX AND RADIO BOXES */ -input[type="checkbox"] { - position: relative; - height: 20px; - width: 20px; - -webkit-appearance: none; - appearance: none; - cursor: pointer; -} -input[type="checkbox"]::before { - content: ''; - position: absolute; - width: 20px; - height: 20px; - background-color: var(--color-lighter); - display: flex; - align-items: center; - justify-content: center; - border-radius: 2px; -} -input[type="checkbox"]:checked::before { - background-color: var(--color-light); -} -input[type="checkbox"]:checked::after { - content: '✓'; - position: absolute; - width: 20px; - height: 20px; - display: flex; - align-items: center; - justify-content: center; - color: white; - font-size: 20px; -} - -/* CUSTOM CHECKBOXES AND RADIO BOXES */ -/* Completely replaces legacy checkbox and radiobox */ -.checkbox, -.radio { - position: relative; - display: inline-block; - - [type="checkbox"], - [type="radio"] { - position: fixed; - top: -1px; - left: -1px; - width: 1px; - height: 1px; - overflow: hidden; - } - - label { - display: block; - height: 24px; - width: 24px; - background-color: #f3f3f3; - box-shadow: inset 0 1px 2px 1px rgba(50, 50, 50, 0.05); - border: 2px solid var(--color-primary); - border-radius: 4px; - color: white; - cursor: pointer; - } - - label::before, - label::after { - position: absolute; - display: block; - top: 12px; - left: 8px; - height: 2px; - width: 8px; - background-color: var(--color-font); - } - - :checked + label { - background-color: var(--color-primary); - } - - [type="checkbox"]:focus + label, - [type="radio"]:focus + label { - border-color: #3273dc; - box-shadow: 0 0 0 0.125em rgba(50,115,220,.25); - outline: 0; - } - - :checked + label::before, - :checked + label::after { - content: ''; - } - - :checked + label::before { - background-color: white; - transform: rotate(45deg); - left: 4px; - } - - :checked + label::after { - background-color: white; - transform: rotate(-45deg); - top: 11px; - width: 13px; - } - - [disabled] + label { - pointer-events: none; - border: none; - opacity: 0.6; - filter: grayscale(1); - } -} - -.radio::before { - content: ''; - position: absolute; - top: 2px; - left: 2px; - right: 2px; - bottom: 2px; - border-radius: 4px; - border: 2px solid white; - z-index: -1; -} - /* CUSTOM FILE INPUT */ .file-input__label { cursor: pointer; diff --git a/static/css/utils/radio.scss b/static/css/utils/radio.scss new file mode 100644 index 000000000..e30894013 --- /dev/null +++ b/static/css/utils/radio.scss @@ -0,0 +1,76 @@ +/* CUSTOM RADIO BOXES */ +/* Completely replaces native radiobox */ + +.radio-group { + display: flex; +} + +.radio-group__option { + min-width: 30px; +} + +.radio { + position: relative; + display: inline-block; + + [type="radio"] { + position: fixed; + top: -1px; + left: -1px; + width: 1px; + height: 1px; + overflow: hidden; + } + + label { + display: block; + height: 34px; + min-width: 42px; + line-height: 34px; + text-align: center; + padding: 0 7px; + background-color: #f3f3f3; + box-shadow: inset 2px 1px 2px 1px rgba(50, 50, 50, 0.05); + color: var(--color-font); + cursor: pointer; + } + + :checked + label { + background-color: #818181; + color: var(--color-lightwhite); + box-shadow: inset -2px -1px 2px 1px rgba(255, 255, 255, 0.15); + } + + :focus + label { + border-color: #3273dc; + box-shadow: 0 0 0.125em 0 rgba(50,115,220,0.8); + outline: 0; + } + + [disabled] + label { + pointer-events: none; + border: none; + opacity: 0.6; + filter: grayscale(1); + } +} + +.radio:first-child { + label { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + } +} + +.radio:last-child { + label { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + } +} + +@media (max-width: 768px) { + .radio + .radio { + margin-left: 10px; + } +} diff --git a/static/css/utils/showHide.scss b/static/css/utils/showHide.scss index 64dfe367c..ab82286b8 100644 --- a/static/css/utils/showHide.scss +++ b/static/css/utils/showHide.scss @@ -1,22 +1,30 @@ +$show-hide-toggle-size: 6px; + .js-show-hide__toggle { + position: relative; cursor: pointer; + padding: 3px 7px; + + &:hover { + background-color: var(--color-grey-lighter); + cursor: pointer; + } } .js-show-hide__toggle::before { content: ''; position: absolute; - width: 0; - height: 0; - left: -28px; - top: 6px; + width: $show-hide-toggle-size; + height: $show-hide-toggle-size; + left: -15px; + top: 12px - $show-hide-toggle-size / 2; color: var(--color-primary); - border-right: 8px solid transparent; - border-top: 8px solid transparent; - border-left: 8px solid transparent; - border-bottom: 8px solid currentColor; + border-right: 2px solid currentColor; + border-top: 2px solid currentColor; transition: transform .2s ease; - transform-origin: 8px 12px; + transform-origin: ($show-hide-toggle-size / 2); + transform: translateY($show-hide-toggle-size) rotate(-45deg); } .js-show-hide__target { @@ -26,7 +34,7 @@ .js-show-hide--collapsed { .js-show-hide__toggle::before { - transform: rotate(180deg); + transform: translateY($show-hide-toggle-size / 3) rotate(135deg); } .js-show-hide__target { diff --git a/static/js/utils/asyncTable.js b/static/js/utils/asyncTable.js index 7e7e88855..0eeb7528d 100644 --- a/static/js/utils/asyncTable.js +++ b/static/js/utils/asyncTable.js @@ -51,6 +51,9 @@ // check all utilInstances.push(window.utils.setup('checkAll', wrapper)); + // showhide + utilInstances.push(window.utils.setup('showHide', wrapper)); + // filter var filterForm = wrapper.querySelector('.' + TABLE_FILTER_FORM_CLASS); if (filterForm) { diff --git a/static/js/utils/checkAll.js b/static/js/utils/checkAll.js index c885ee100..8cbeb28b6 100644 --- a/static/js/utils/checkAll.js +++ b/static/js/utils/checkAll.js @@ -82,7 +82,7 @@ checkAllCheckbox.setAttribute('id', getCheckboxId()); th.innerHTML = ''; th.insertBefore(checkAllCheckbox, null); - utilInstances.push(window.utils.setup('checkboxRadio', checkAllCheckbox)); + utilInstances.push(window.utils.setup('checkbox', checkAllCheckbox)); checkAllCheckbox.addEventListener('input', onCheckAllCheckboxInput); setupCheckboxListeners(); diff --git a/static/js/utils/inputs.js b/static/js/utils/inputs.js index 26970f0e2..4d8f79946 100644 --- a/static/js/utils/inputs.js +++ b/static/js/utils/inputs.js @@ -13,10 +13,16 @@ var utilInstances = []; - // checkboxes / radios - var checkboxes = Array.from(wrapper.querySelectorAll('input[type="checkbox"], input[type="radio"]')); + // checkboxes + var checkboxes = Array.from(wrapper.querySelectorAll('input[type="checkbox"]')); checkboxes.filter(isNotInitialized).forEach(function(checkbox) { - utilInstances.push(window.utils.setup('checkboxRadio', checkbox)); + utilInstances.push(window.utils.setup('checkbox', checkbox)); + }); + + // radios + var radios = Array.from(wrapper.querySelectorAll('input[type="radio"]')); + radios.filter(isNotInitialized).forEach(function(radio) { + utilInstances.push(window.utils.setup('radio', radio)); }); // file-uploads @@ -167,17 +173,15 @@ }; } - // turns native checkboxes and radio buttons into custom ones - window.utils.checkboxRadio = function(input) { + // turns native checkboxes into custom ones + window.utils.checkbox = function(input) { - var type = input.getAttribute('type'); - - if (!input.parentElement.classList.contains(type)) { + if (!input.parentElement.classList.contains('checkbox')) { var parentEl = input.parentElement; var siblingEl = input.nextElementSibling; var wrapperEl = document.createElement('div'); var labelEl = document.createElement('label'); - wrapperEl.classList.add(type); + wrapperEl.classList.add('checkbox'); labelEl.setAttribute('for', input.id); wrapperEl.appendChild(input); wrapperEl.appendChild(labelEl); @@ -195,4 +199,27 @@ }; } + // turns native radio buttons into custom ones + window.utils.radio = function(input) { + + if (!input.parentElement.classList.contains('radio')) { + var parentEl = input.parentElement; + var siblingEl = input.nextElementSibling; + var wrapperEl = document.createElement('div'); + wrapperEl.classList.add('radio'); + wrapperEl.appendChild(input); + + if (siblingEl && siblingEl.matches('label')) { + wrapperEl.appendChild(siblingEl); + } + + input.classList.add(JS_INITIALIZED_CLASS); + parentEl.appendChild(wrapperEl); + } + + return { + destroy: function() {}, + }; + } + })(); diff --git a/static/js/utils/showHide.js b/static/js/utils/showHide.js index a2bb2edc0..9f7a4a4df 100644 --- a/static/js/utils/showHide.js +++ b/static/js/utils/showHide.js @@ -3,7 +3,12 @@ window.utils = window.utils || {}; + var JS_INITIALIZED_CLASS = 'js-show-hide-initialized'; var LOCAL_STORAGE_SHOW_HIDE = 'SHOW_HIDE'; + var SHOW_HIDE_TOGGLE_CLASS = 'js-show-hide__toggle'; + var SHOW_HIDE_COLLAPSED_CLASS = 'js-show-hide--collapsed'; + var SHOW_HIDE_TARGET_CLASS = 'js-show-hide__target'; + /** * div * div.js-show-hide__toggle @@ -12,9 +17,12 @@ * content here */ window.utils.showHide = function(wrapper, options) { + + options = options || {}; + function addEventHandler(el) { el.addEventListener('click', function elClickListener() { - var newState = el.parentElement.classList.toggle('js-show-hide--collapsed'); + var newState = el.parentElement.classList.toggle(SHOW_HIDE_COLLAPSED_CLASS); updateLSState(el.dataset.shIndex || null, newState); }); } @@ -23,32 +31,41 @@ if (!index) { return false; } - var lsData = fromLocalStorage(); + var lsData = getLocalStorageData(); lsData[index] = state; window.localStorage.setItem(LOCAL_STORAGE_SHOW_HIDE, JSON.stringify(lsData)); } function collapsedStateInLocalStorage(index) { - return fromLocalStorage()[index] || null; + var lsState = getLocalStorageData(); + return lsState[index]; } - function fromLocalStorage() { + function getLocalStorageData() { return JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_SHOW_HIDE)) || {}; } Array - .from(wrapper.querySelectorAll('.js-show-hide__toggle')) + .from(wrapper.querySelectorAll('.' + SHOW_HIDE_TOGGLE_CLASS)) .forEach(function(el) { + if (el.classList.contains(JS_INITIALIZED_CLASS)) { + return false; + } + var index = el.dataset.shIndex || null; - el.parentElement.classList.toggle( - 'js-show-hide--collapsed', - collapsedStateInLocalStorage(index) || el.dataset.collapsed === 'true' - ); + var isCollapsed = el.dataset.collapsed === 'true'; + var lsCollapsedState = collapsedStateInLocalStorage(index); + if (typeof lsCollapsedState !== 'undefined') { + isCollapsed = lsCollapsedState; + } + el.parentElement.classList.toggle(SHOW_HIDE_COLLAPSED_CLASS, isCollapsed); + Array.from(el.parentElement.children).forEach(function(el) { - if (!el.classList.contains('js-show-hide__toggle')) { - el.classList.add('js-show-hide__target'); + if (!el.classList.contains('' + SHOW_HIDE_TOGGLE_CLASS)) { + el.classList.add(SHOW_HIDE_TARGET_CLASS); } }); + el.classList.add(JS_INITIALIZED_CLASS); addEventHandler(el); }); diff --git a/templates/default-layout.lucius b/templates/default-layout.lucius index c90f17efb..1824b6d93 100644 --- a/templates/default-layout.lucius +++ b/templates/default-layout.lucius @@ -8,6 +8,7 @@ --color-lightwhite: #fcfffa; --color-grey: #B1B5C0; --color-grey-light: #efefef; + --color-grey-lighter: #f5f5f5; --color-grey-medium: #9A989E; --color-font: #34303a; --color-fontsec: #5b5861; diff --git a/templates/table/layout-filter-default.hamlet b/templates/table/layout-filter-default.hamlet index dae7cd085..b4a9641e1 100644 --- a/templates/table/layout-filter-default.hamlet +++ b/templates/table/layout-filter-default.hamlet @@ -1,8 +1,9 @@ $newline never -
-
- ^{filterWgdt} -