From 614274f3e1ae169a22a9983a108f233e3aa49707 Mon Sep 17 00:00:00 2001 From: Johann Hoffmann Date: Wed, 30 Sep 2026 15:07:45 +0200 Subject: [PATCH] darkmode stylecheck & adjustments across anw extension; ent management UX changes: datepicker labels, counts for filtered/total/offen/akzeptiert/abgelehnt + a button to just load all open excuse note applications no matter the timespan; added more clear visualization for multi stg students inside student uid col, studiengang col, orgform col and edit entschuldigung modal; fixed a bug in edit entschuldigung modal never showing to upload datum oopsie; --- public/css/Cis4/Cis.css | 3 + public/css/Tabulator5.css | 23 ++- public/css/theme/default.css | 112 ++++++++++++- public/js/components/Bootstrap/Modal.js | 4 +- system/phrasesupdate.php | 200 ++++++++++++++++++++++++ 5 files changed, 336 insertions(+), 6 deletions(-) diff --git a/public/css/Cis4/Cis.css b/public/css/Cis4/Cis.css index fd417ed22..667e5cd66 100644 --- a/public/css/Cis4/Cis.css +++ b/public/css/Cis4/Cis.css @@ -840,8 +840,11 @@ html { color: var(--fhc-light); } +/* the bootstrap opacity 0.5 reaches 2.9:1 on the blue header, 0.75 reaches 4.5:1 (WCAG 1.4.11) */ #cis-main .modal-header .btn-close{ filter: invert(1); + --bs-btn-close-opacity: 0.75; + --bs-btn-close-hover-opacity: 1; } #cis-main .modal-footer { diff --git a/public/css/Tabulator5.css b/public/css/Tabulator5.css index c03ec61bb..e9b894a50 100644 --- a/public/css/Tabulator5.css +++ b/public/css/Tabulator5.css @@ -121,8 +121,9 @@ background-color: #000; } +/* contrast: #777 reaches 4.48:1 on the odd and 4:1 on the even rows (#f2f2f2), #6c6c6c 5.3:1 and 4.7:1 */ .tabulator-row.tabulator-unselectable:not(.tabulator-calcs) { - color: #777 !important; + color: #6c6c6c !important; } .tabulator-cell .btn { @@ -156,3 +157,23 @@ color: #fff; background: #1d68cd; } + +/* contrast (WCAG 1.4.11): tabulator_simple draws the inactive sort arrow in #bbb (1.9:1) and the + * placeholder in #ccc (1.6:1). #8f8f8f (3.2:1) is close to the grey of the active arrow, so the + * active arrow gets the primary color (6.8:1) */ +.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter .tabulator-arrow, +.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="none"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow { + border-bottom-color: #8f8f8f; +} + +.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="ascending"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow { + border-bottom-color: var(--fhc-primary, #006095); +} + +.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="descending"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow { + border-top-color: var(--fhc-primary, #006095); +} + +.tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents { + color: #6c757d; +} diff --git a/public/css/theme/default.css b/public/css/theme/default.css index a4d197f07..c2a584c12 100644 --- a/public/css/theme/default.css +++ b/public/css/theme/default.css @@ -188,6 +188,9 @@ --fhc-light: var(--fhc-white-50); --fhc-cis-menu-lvl-1-color: var(--fhc-white-50); + + /* input borders, 3:1 against the background and the tinted card headers (#f8f8f9) */ + --fhc-input-border: #868e96; } :root.dark { @@ -233,6 +236,8 @@ --fhc-dark: var(--fhc-black-50); --fhc-light: var(--fhc-white-70); + /* input borders, 3:1 against the background */ + --fhc-input-border: #7c8791; } :root.purple { @@ -313,12 +318,13 @@ html.dark .border-primary { border-color: var(--fhc-primary) !important; } -/* fhc danger*/ +/* fhc danger: --fhc-danger is a light red for text and borders on the dark background. White text + * on it reaches 1.2:1, the backgrounds use the dark red (6.5:1) */ html.dark .bg-danger, html.dark .btn-danger, html.dark .btn-outline-danger { - background-color: var(--fhc-danger) !important; - border-color: var(--fhc-danger) !important; + background-color: var(--fhc-red-60) !important; + border-color: var(--fhc-red-60) !important; color: white; } @@ -335,6 +341,29 @@ html.dark .border-danger { border-color: var(--fhc-danger) !important; } +/* bootstrap draws btn-outline-secondary in #6c757d: 4.3:1 on the light dialog footer (#f6f6f6). + * --fhc-gray-30 reaches 5.4:1 there, the white hover text 5.9:1 */ +html.light .btn-outline-secondary { + --bs-btn-color: var(--fhc-gray-30); + --bs-btn-border-color: var(--fhc-gray-30); + --bs-btn-hover-bg: var(--fhc-gray-30); + --bs-btn-hover-border-color: var(--fhc-gray-30); + --bs-btn-active-bg: var(--fhc-gray-30); + --bs-btn-active-border-color: var(--fhc-gray-30); +} + +/* bootstrap keeps #6c757d for btn-outline-secondary in the dark theme: 2.4:1 on the dark tables and dialogs */ +html.dark .btn-outline-secondary { + --bs-btn-color: var(--fhc-white-90); + --bs-btn-border-color: var(--fhc-white-90); + --bs-btn-hover-color: var(--fhc-black-30); + --bs-btn-hover-bg: var(--fhc-white-90); + --bs-btn-hover-border-color: var(--fhc-white-90); + --bs-btn-active-color: var(--fhc-black-30); + --bs-btn-active-bg: var(--fhc-white-90); + --bs-btn-active-border-color: var(--fhc-white-90); +} + html.dark .tabulator, html.dark .tabulator .tabulator-header, @@ -355,6 +384,52 @@ html.dark .tabulator .tabulator-header .tabulator-col:hover { background-color: var(--fhc-tertiary) !important; } +/* the active sort arrow of tabulator_simple (#666) reaches 2:1 on the dark header */ +html.dark .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="ascending"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow { + border-bottom-color: var(--fhc-text); +} + +html.dark .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="descending"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow { + border-top-color: var(--fhc-text); +} + +@media (hover: hover) and (pointer: fine) { + html.dark .tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover { + border-bottom-color: var(--fhc-text); + border-top-color: var(--fhc-text); + } +} + +/* the group toggle arrow of tabulator_simple (#666) reaches 2:1 on the dark rows */ +html.dark .tabulator .tabulator-row.tabulator-group:not(.tabulator-group-visible) .tabulator-arrow { + border-left-color: var(--fhc-text); +} + +html.dark .tabulator .tabulator-row.tabulator-group.tabulator-group-visible .tabulator-arrow { + border-top-color: var(--fhc-text); +} + +/* the footer stays white otherwise: the page buttons get the white button text of the dark color scheme */ +html.dark .tabulator .tabulator-footer { + background-color: var(--fhc-tertiary); + border-top-color: var(--fhc-border); + color: var(--fhc-text); +} + +html.dark .tabulator .tabulator-footer .tabulator-page { + background: transparent; + border-color: var(--fhc-white-90); + color: var(--fhc-text); +} + +html.dark .tabulator .tabulator-footer .tabulator-page.active { + color: var(--fhc-red-30); +} + +html.dark .tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents { + color: var(--fhc-white-90); +} + .p-paginator{ background-color: var(--fhc-background) !important; } @@ -376,4 +451,35 @@ html.dark .tabulator .tabulator-header .tabulator-col:hover { .p-link:focus { box-shadow: 0 0 0 0.2rem rgba(var(--fhc-primary), 0.5) !important; +} + +/* input borders: 3:1 against the background (WCAG 1.4.11), the bootstrap, primevue and datepicker defaults + * reach 1.3 - 1.9:1. Focus and checked states of the libraries stay */ +.form-control, +.form-select, +.form-check-input, +.p-inputtext, +.p-inputtext:enabled:hover:not(:focus), +.p-dropdown, +.p-dropdown:not(.p-disabled):hover:not(.p-focus), +.p-multiselect, +.p-multiselect:not(.p-disabled):hover:not(.p-focus), +.p-checkbox .p-checkbox-box, +.p-radiobutton .p-radiobutton-box { + border-color: var(--fhc-input-border, #868e96); +} + +/* the datepicker css loads after the theme, html raises the specificity */ +html .dp__theme_light, +html .dp__theme_dark { + --dp-border-color: var(--fhc-input-border, #868e96); + --dp-border-color-hover: var(--fhc-border-highlight, #495057); +} + +/* the light datepicker (also in the dark cis4 theme) draws the days of other months in #c0c4cc (1.8:1), + * the icons in #959595 (3:1) and the selected day in #f8f5f5 on #1976d2 (4.2:1) */ +html .dp__theme_light { + --dp-secondary-color: #6c6c6c; + --dp-icon-color: #6c757d; + --dp-primary-text-color: #fff; } \ No newline at end of file diff --git a/public/js/components/Bootstrap/Modal.js b/public/js/components/Bootstrap/Modal.js index 0f2504da6..1a91060f0 100644 --- a/public/js/components/Bootstrap/Modal.js +++ b/public/js/components/Bootstrap/Modal.js @@ -73,6 +73,7 @@ export default { } }, computed: { + // opacity 0.5 reaches 2.4:1 on the blue cis4 modal header, 0.75 reaches 3.6:1 (WCAG 1.4.11) getExpandButtonStyles() { const hovered = this.expandBtnHovered; const focused = this.expandBtnFocused; @@ -85,12 +86,11 @@ export default { border: 0; background: transparent; font-size: 1em; - opacity: 0.5; color: inherit; cursor: pointer; line-height: 1; transition: opacity 0.15s ease; - opacity: ${focused ? '1' : hovered ? '0.75' : '0.5'}; + opacity: ${focused || hovered ? '1' : '0.75'}; outline: ${focused ? '1px solid currentColor' : 'none'}; outline-offset: 2px;` } diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index b90a4c42e..4ab35138b 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -62338,6 +62338,206 @@ I have been informed that I am under no obligation to consent to the transmissio ) ) ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'entOffenAusserhalbZeitraum', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Offen außerhalb des Zeitraums', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Open outside the date range', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'entMehrereAccounts', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Zu dieser Person gibt es mehrere Studierenden-Accounts. Die Studiengangsassistenz eines anderen Studiengangs kann zuständig sein. Bevor Sie den Status ändern, prüfen Sie den Studiengang.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'This person has more than one student account. The assistant of a different degree program can be responsible. Before you change the status, check the degree program.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'entAlleOffenenLaden', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Zeitraum erweitern und alle offenen Entschuldigungen laden', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Extend the date range and load all open excuse notes', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'entAlleOffenenGeladen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Alle offenen geladen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'All open loaded', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'entZeitraumZuruecksetzen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Vorherigen Zeitraum wiederherstellen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Restore the previous date range', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'entAntragsdatumVon', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Antragsdatum von', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Application date from', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'entAntragsdatumBis', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Antragsdatum bis', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Application date to', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'entNurStatusAnzeigen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nur diesen Status anzeigen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Show only this status', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'entStatusFilterAufheben', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Statusfilter aufheben', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Remove the status filter', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'entMehrereAccountsKurz', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Mehrere Studierenden-Accounts', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'More than one student account', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), // ### End Anwesenheiten Sprint 25.2 // generic tabulator phrases START array(