mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-10-17 15:02:36 +00:00
[Web] Update Bootstrap to 5.3.8, add theme support
This commit is contained in:
@@ -64,6 +64,8 @@ data/web/templates/cache/*
|
|||||||
!data/web/templates/cache/.gitkeep
|
!data/web/templates/cache/.gitkeep
|
||||||
data/web/.well-known/acme-challenge
|
data/web/.well-known/acme-challenge
|
||||||
data/web/css/build/0081-custom-mailcow.css
|
data/web/css/build/0081-custom-mailcow.css
|
||||||
|
data/web/css/themes/*/
|
||||||
|
!data/web/css/themes/servercow/
|
||||||
data/web/inc/vars.local.inc.php
|
data/web/inc/vars.local.inc.php
|
||||||
data/web/inc/app_info.inc.php
|
data/web/inc/app_info.inc.php
|
||||||
data/web/nextcloud*/
|
data/web/nextcloud*/
|
||||||
|
|||||||
@@ -115,6 +115,8 @@ $template_data = [
|
|||||||
'logo_dark_specs' => customize('get', 'main_logo_dark_specs'),
|
'logo_dark_specs' => customize('get', 'main_logo_dark_specs'),
|
||||||
'ip_check' => customize('get', 'ip_check'),
|
'ip_check' => customize('get', 'ip_check'),
|
||||||
'custom_login' => customize('get', 'custom_login'),
|
'custom_login' => customize('get', 'custom_login'),
|
||||||
|
'ui_themes' => customize('get', 'ui_themes'),
|
||||||
|
'ui_theme' => customize('get', 'ui_theme'),
|
||||||
'password_complexity' => password_complexity('get'),
|
'password_complexity' => password_complexity('get'),
|
||||||
'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'],
|
'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'],
|
||||||
'cors_settings' => $cors_settings,
|
'cors_settings' => $cors_settings,
|
||||||
|
|||||||
@@ -17,15 +17,15 @@ table.dataTable>tbody>tr.child ul.dtr-details>li {
|
|||||||
}
|
}
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
|
||||||
background-color: #5e5e5e;
|
background-color: var(--mc-dtr-hover-bg);
|
||||||
}
|
}
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before,
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before,
|
||||||
table.dataTable td.dt-control:before {
|
table.dataTable td.dt-control:before {
|
||||||
background-color: #979797 !important;
|
background-color: var(--mc-dtr-bg) !important;
|
||||||
border: 1.5px solid #616161 !important;
|
border: 1.5px solid var(--mc-dtr-border) !important;
|
||||||
border-radius: 2px !important;
|
border-radius: 2px !important;
|
||||||
color: #fff;
|
color: var(--mc-dtr-color);
|
||||||
height: 1em;
|
height: 1em;
|
||||||
width: 1em;
|
width: 1em;
|
||||||
line-height: 1.25em;
|
line-height: 1.25em;
|
||||||
@@ -37,7 +37,7 @@ table.dataTable td.dt-control:before {
|
|||||||
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before,
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before,
|
||||||
table.dataTable td.dt-control:before {
|
table.dataTable td.dt-control:before {
|
||||||
background-color: #979797 !important;
|
background-color: var(--mc-dtr-active-bg) !important;
|
||||||
}
|
}
|
||||||
table.dataTable.table-striped>tbody>tr>td {
|
table.dataTable.table-striped>tbody>tr>td {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|||||||
@@ -34,11 +34,41 @@
|
|||||||
url('/fonts/noto-sans-v12-latin_greek_cyrillic-700italic.woff') format('woff');
|
url('/fonts/noto-sans-v12-latin_greek_cyrillic-700italic.woff') format('woff');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* theme tokens, override in css/themes/<name>/theme.css */
|
||||||
|
:root {
|
||||||
|
--mc-font-family: "Noto Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||||
|
--mc-font-size: 10.5pt;
|
||||||
|
--mc-body-bg: #fbfbfb;
|
||||||
|
--mc-primary: #0F688D;
|
||||||
|
--mc-primary-border: #0d526d;
|
||||||
|
--mc-info: #148DBC;
|
||||||
|
--mc-info-border: #127ea8;
|
||||||
|
--mc-border: #dfdfdf;
|
||||||
|
--mc-surface: #fff;
|
||||||
|
--mc-surface-alt: #f7f7f7;
|
||||||
|
--mc-muted: #959595;
|
||||||
|
--mc-hr: #ccc;
|
||||||
|
--mc-progress-bg: #d5d5d5;
|
||||||
|
--mc-placeholder: rgb(137 137 137);
|
||||||
|
--mc-btn-outline-color: #000000;
|
||||||
|
--mc-btn-outline-border: #cfcfcf;
|
||||||
|
--mc-btn-outline-hover-bg: #f0f0f0;
|
||||||
|
--mc-btn-outline-active-bg: #f0f0f0;
|
||||||
|
--mc-btn-light-active-color: #fff;
|
||||||
|
--mc-btn-light-active-bg: #555;
|
||||||
|
--mc-btn-light-active-border: #4d4d4d;
|
||||||
|
--mc-dtr-bg: #979797;
|
||||||
|
--mc-dtr-border: #616161;
|
||||||
|
--mc-dtr-color: #fff;
|
||||||
|
--mc-dtr-hover-bg: #5e5e5e;
|
||||||
|
--mc-dtr-active-bg: #979797;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background-color: #fbfbfb;
|
background-color: var(--mc-body-bg);
|
||||||
}
|
}
|
||||||
#maxmsgsize { min-width: 80px; }
|
#maxmsgsize { min-width: 80px; }
|
||||||
#slider1 .slider-selection {
|
#slider1 .slider-selection {
|
||||||
@@ -86,17 +116,17 @@ body {
|
|||||||
max-height: 1000px
|
max-height: 1000px
|
||||||
}
|
}
|
||||||
.nav-tabs .nav-link, .nav-tabs .nav-link.disabled, .nav-tabs .nav-link.disabled:hover, .nav-tabs .nav-link.disabled:focus {
|
.nav-tabs .nav-link, .nav-tabs .nav-link.disabled, .nav-tabs .nav-link.disabled:hover, .nav-tabs .nav-link.disabled:focus {
|
||||||
border-color: #dfdfdf;
|
border-color: var(--mc-border);
|
||||||
}
|
}
|
||||||
.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link {
|
.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link {
|
||||||
border-color: #dfdfdf;
|
border-color: var(--mc-border);
|
||||||
border-bottom: 1px solid #ffffff;
|
border-bottom: 1px solid var(--mc-surface);
|
||||||
}
|
}
|
||||||
.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {
|
.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {
|
||||||
border-color: #dfdfdf;
|
border-color: var(--mc-border);
|
||||||
}
|
}
|
||||||
.nav-tabs {
|
.nav-tabs {
|
||||||
border-bottom: 1px solid #dfdfdf;
|
border-bottom: 1px solid var(--mc-border);
|
||||||
}
|
}
|
||||||
.bi {
|
.bi {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -164,13 +194,13 @@ body.modal-open {
|
|||||||
padding-right: inherit !important;
|
padding-right: inherit !important;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
font-family: "Noto Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
|
font-family: var(--mc-font-family);
|
||||||
font-size: 10.5pt;
|
font-size: var(--mc-font-size);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
html {
|
html {
|
||||||
font-family: "Noto Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
|
font-family: var(--mc-font-family);
|
||||||
font-size: 10.5pt;
|
font-size: var(--mc-font-size);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
#mailcow-alert {
|
#mailcow-alert {
|
||||||
@@ -206,7 +236,7 @@ legend {
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
.overlay {
|
.overlay {
|
||||||
background: #fff;
|
background: var(--mc-surface);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
top: 0; right: 0; bottom: 0; left: 0;
|
top: 0; right: 0; bottom: 0; left: 0;
|
||||||
@@ -215,9 +245,6 @@ legend {
|
|||||||
.bootstrap-select.btn-group .no-results {
|
.bootstrap-select.btn-group .no-results {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
|
|
||||||
color: rgb(197, 197, 197) !important;
|
|
||||||
}
|
|
||||||
.haveibeenpwned {
|
.haveibeenpwned {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
@@ -239,7 +266,7 @@ legend {
|
|||||||
.footer {
|
.footer {
|
||||||
margin-top: 27px;
|
margin-top: 27px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
color: #959595;
|
color: var(--mc-muted);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@@ -337,7 +364,7 @@ code {
|
|||||||
overflow-x: auto!important;
|
overflow-x: auto!important;
|
||||||
}
|
}
|
||||||
.well {
|
.well {
|
||||||
border: 1px solid #dfdfdf;
|
border: 1px solid var(--mc-border);
|
||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
@@ -356,47 +383,47 @@ button[aria-expanded='true'] > .caret {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.list-group-details {
|
.list-group-details {
|
||||||
background: #fff;
|
background: var(--mc-surface);
|
||||||
}
|
}
|
||||||
.list-group-header {
|
.list-group-header {
|
||||||
background: #f7f7f7;
|
background: var(--mc-surface-alt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.bg-primary, .alert-primary, .btn-primary {
|
.bg-primary, .alert-primary, .btn-primary {
|
||||||
background-color: #0F688D !important;
|
background-color: var(--mc-primary) !important;
|
||||||
border-color: #0d526d !important;
|
border-color: var(--mc-primary-border) !important;
|
||||||
}
|
}
|
||||||
.bg-info, .alert-info, .btn-info {
|
.bg-info, .alert-info, .btn-info {
|
||||||
background-color: #148DBC !important;
|
background-color: var(--mc-info) !important;
|
||||||
border-color: #127ea8 !important;
|
border-color: var(--mc-info-border) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
|
.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
|
||||||
color: rgb(137 137 137)!important;
|
color: var(--mc-placeholder) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress {
|
.progress {
|
||||||
height: 16px;
|
height: 16px;
|
||||||
background-color: #d5d5d5;
|
background-color: var(--mc-progress-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.btn-outline-secondary:hover {
|
.btn-outline-secondary:hover {
|
||||||
background-color: #f0f0f0;
|
background-color: var(--mc-btn-outline-hover-bg);
|
||||||
}
|
}
|
||||||
.btn.btn-outline-secondary {
|
.btn.btn-outline-secondary {
|
||||||
color: #000000 !important;
|
color: var(--mc-btn-outline-color) !important;
|
||||||
border-color: #cfcfcf !important;
|
border-color: var(--mc-btn-outline-border) !important;
|
||||||
}
|
}
|
||||||
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
|
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
|
||||||
background-color: #f0f0f0 !important;
|
background-color: var(--mc-btn-outline-active-bg) !important;
|
||||||
}
|
}
|
||||||
.btn-check:checked+.btn-light, .btn-check:active+.btn-light, .btn-light:active, .btn-light.active, .show>.btn-light.dropdown-toggle {
|
.btn-check:checked+.btn-light, .btn-check:active+.btn-light, .btn-light:active, .btn-light.active, .show>.btn-light.dropdown-toggle {
|
||||||
color: #fff;
|
color: var(--mc-btn-light-active-color);
|
||||||
background-color: #555;
|
background-color: var(--mc-btn-light-active-bg);
|
||||||
background-image: none;
|
background-image: none;
|
||||||
border-color: #4d4d4d;
|
border-color: var(--mc-btn-light-active-border);
|
||||||
}
|
}
|
||||||
.btn-check:checked+.btn-light:focus, .btn-check:active+.btn-light:focus, .btn-light:active:focus, .btn-light.active:focus, .show>.btn-light.dropdown-toggle:focus,
|
.btn-check:checked+.btn-light:focus, .btn-check:active+.btn-light:focus, .btn-light:active:focus, .btn-light.active:focus, .show>.btn-light.dropdown-toggle:focus,
|
||||||
.btn-check:focus+.btn-light, .btn-light:focus {
|
.btn-check:focus+.btn-light, .btn-light:focus {
|
||||||
@@ -423,7 +450,7 @@ button[aria-expanded='true'] > .caret {
|
|||||||
.hr-title::after {
|
.hr-title::after {
|
||||||
content: "";
|
content: "";
|
||||||
flex: 1;
|
flex: 1;
|
||||||
border-bottom: 1px solid #ccc;
|
border-bottom: 1px solid var(--mc-hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hr-title:not(:empty)::before {
|
.hr-title:not(:empty)::before {
|
||||||
|
|||||||
+3750
-2935
File diff suppressed because it is too large
Load Diff
@@ -1,62 +1,103 @@
|
|||||||
|
/* theme tokens, override in css/themes/<name>/dark.css */
|
||||||
|
:root {
|
||||||
|
--mc-body-bg: #1c1c1e;
|
||||||
|
--mc-body-color: #f2f2f7;
|
||||||
|
--mc-surface: #2c2c2e;
|
||||||
|
--mc-surface-alt: #282828;
|
||||||
|
--mc-text: #ccc;
|
||||||
|
--mc-text-soft: #bbb;
|
||||||
|
--mc-muted: #8e8e93;
|
||||||
|
--mc-border: #555;
|
||||||
|
--mc-tab-border: #444444;
|
||||||
|
--mc-link: #6fc7e9;
|
||||||
|
--mc-link-hover: #3daedb;
|
||||||
|
--mc-btn-bg: #5e5e5e;
|
||||||
|
--mc-btn-border: #4c4c4e;
|
||||||
|
--mc-input-bg: #424242;
|
||||||
|
--mc-input-color: #e2e2e2;
|
||||||
|
--mc-input-border: #999;
|
||||||
|
--mc-dropdown-bg: #424242;
|
||||||
|
--mc-table-bg: #3a3a3a;
|
||||||
|
--mc-table-stripe: #282828;
|
||||||
|
--mc-table-stripe-row: #424242;
|
||||||
|
--mc-table-hover: #343434;
|
||||||
|
--mc-table-border: #5c5c5c;
|
||||||
|
--mc-progress-bg: #555;
|
||||||
|
--mc-placeholder: #d4d4d4;
|
||||||
|
--mc-btn-outline-color: #e0e0e0;
|
||||||
|
--mc-btn-outline-border: #7a7a7a;
|
||||||
|
--mc-btn-outline-hover-bg: #5c5c5c;
|
||||||
|
--mc-btn-outline-active-bg: #7a7a7a;
|
||||||
|
--mc-btn-light-active-color: #f2f2f7;
|
||||||
|
--mc-btn-light-active-bg: #242424;
|
||||||
|
--mc-btn-light-active-border: #1c1c1e;
|
||||||
|
--mc-btn-dark-bg: #242424;
|
||||||
|
--mc-input-disabled-bg: #6e6e6e;
|
||||||
|
--mc-input-disabled-color: #a8a8a8;
|
||||||
|
--mc-list-header-bg: #444;
|
||||||
|
--mc-list-details-bg: #555;
|
||||||
|
--mc-chip-bg: #444;
|
||||||
|
--mc-table-child-bg: #414141;
|
||||||
|
--mc-dtr-bg: #7a7a7a;
|
||||||
|
--mc-dtr-border: #5c5c5c;
|
||||||
|
--mc-dtr-color: #e0e0e0;
|
||||||
|
--mc-dtr-hover-bg: #7a7a7a;
|
||||||
|
--mc-dtr-active-bg: #949494;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #1c1c1e;
|
background-color: var(--mc-body-bg);
|
||||||
color: #f2f2f7;
|
color: var(--mc-body-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
border: 1px solid #2c2c2e;
|
border: 1px solid var(--mc-surface);
|
||||||
background-color: #2c2c2e;
|
background-color: var(--mc-surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
legend {
|
legend {
|
||||||
color: #f2f2f7;
|
color: var(--mc-body-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-header {
|
.card-header {
|
||||||
color: #8e8e93;
|
color: var(--mc-muted);
|
||||||
background-color: #1c1c1e;
|
background-color: var(--mc-body-bg);
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-body {
|
.card-body {
|
||||||
--bs-card-color: #bbb;
|
--bs-card-color: var(--mc-text-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary, .paginate_button, .page-link, .btn-light {
|
.btn-secondary, .paginate_button, .page-link, .btn-light {
|
||||||
color: #f2f2f7 !important;
|
color: var(--mc-body-color) !important;
|
||||||
background-color: #5e5e5e !important;
|
background-color: var(--mc-btn-bg) !important;
|
||||||
border-color: #4c4c4e !important;
|
border-color: var(--mc-btn-border) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-dark {
|
.btn-dark {
|
||||||
color: #f2f2f7 !important;
|
color: var(--mc-body-color) !important;
|
||||||
background-color: #242424 !important;
|
background-color: var(--mc-btn-dark-bg) !important;
|
||||||
border-color: #1c1c1e !important;
|
border-color: var(--mc-body-bg) !important;
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary:focus, .btn-secondary:hover, .btn-group.open .dropdown-toggle.btn-secondary {
|
|
||||||
background-color: #444444;
|
|
||||||
border-color: #4c4c4e !important;
|
|
||||||
color: #f2f2f7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-check:checked+.btn-secondary, .btn-check:active+.btn-secondary, .btn-secondary:active, .btn-secondary.active, .show>.btn-secondary.dropdown-toggle {
|
.btn-check:checked+.btn-secondary, .btn-check:active+.btn-secondary, .btn-secondary:active, .btn-secondary.active, .show>.btn-secondary.dropdown-toggle {
|
||||||
border-color: #5e5e5e !important;
|
border-color: var(--mc-btn-bg) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-secondary {
|
.alert-secondary {
|
||||||
color: #f2f2f7 !important;
|
color: var(--mc-body-color) !important;
|
||||||
background-color: #5e5e5e !important;
|
background-color: var(--mc-btn-bg) !important;
|
||||||
border-color: #4c4c4e !important;
|
border-color: var(--mc-btn-border) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-secondary {
|
.bg-secondary {
|
||||||
color: #f2f2f7 !important;
|
color: var(--mc-body-color) !important;
|
||||||
background-color: #5e5e5e !important;
|
background-color: var(--mc-btn-bg) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-secondary, .alert-secondary a, .alert-secondary .alert-link {
|
.alert-secondary, .alert-secondary a, .alert-secondary .alert-link {
|
||||||
color: #f2f2f7;
|
color: var(--mc-body-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-item.active .page-link {
|
.page-item.active .page-link {
|
||||||
@@ -65,18 +106,18 @@ legend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary:focus, .btn-secondary:hover, .btn-group.open .dropdown-toggle.btn-secondary {
|
.btn-secondary:focus, .btn-secondary:hover, .btn-group.open .dropdown-toggle.btn-secondary {
|
||||||
background-color: #5e5e5e;
|
background-color: var(--mc-btn-bg);
|
||||||
border-color: #4c4c4e !important;
|
border-color: var(--mc-btn-border) !important;
|
||||||
color: #f2f2f7;
|
color: var(--mc-body-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary:disabled, .btn-secondary.disabled {
|
.btn-secondary:disabled, .btn-secondary.disabled {
|
||||||
border-color: #5e5e5e !important;
|
border-color: var(--mc-btn-bg) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
--bs-modal-color: #bbb;
|
--bs-modal-color: var(--mc-text-soft);
|
||||||
background-color: #2c2c2e;
|
background-color: var(--mc-surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
@@ -84,7 +125,7 @@ legend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
color: #bbb;
|
color: var(--mc-text-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal .btn-close {
|
.modal .btn-close {
|
||||||
@@ -92,12 +133,12 @@ legend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navbar.bg-light {
|
.navbar.bg-light {
|
||||||
background-color: #1c1c1e !important;
|
background-color: var(--mc-body-bg) !important;
|
||||||
border-color: #2c2c2e;
|
border-color: var(--mc-surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-link {
|
.nav-link {
|
||||||
color: #8e8e93 !important;
|
color: var(--mc-muted) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link {
|
.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link {
|
||||||
@@ -105,23 +146,23 @@ legend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nav-tabs, .nav-tabs .nav-link {
|
.nav-tabs, .nav-tabs .nav-link {
|
||||||
border-color: #444444 !important;
|
border-color: var(--mc-tab-border) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tabs .nav-link:not(.disabled):hover, .nav-tabs .nav-link:not(.disabled):focus, .nav-tabs .nav-link.active {
|
.nav-tabs .nav-link:not(.disabled):hover, .nav-tabs .nav-link:not(.disabled):focus, .nav-tabs .nav-link.active {
|
||||||
border-bottom-color: #1c1c1e !important;
|
border-bottom-color: var(--mc-body-bg) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card .nav-tabs .nav-link:not(.disabled):hover, .card .nav-tabs .nav-link:not(.disabled):focus, .card .nav-tabs .nav-link.active {
|
.card .nav-tabs .nav-link:not(.disabled):hover, .card .nav-tabs .nav-link:not(.disabled):focus, .card .nav-tabs .nav-link.active {
|
||||||
border-bottom-color: #2c2c2e !important;
|
border-bottom-color: var(--mc-surface) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table, .table-striped>tbody>tr:nth-of-type(odd)>*, tbody tr {
|
.table, .table-striped>tbody>tr:nth-of-type(odd)>*, tbody tr {
|
||||||
color: #f2f2f7 !important;
|
color: var(--mc-body-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
background-color: #424242;
|
background-color: var(--mc-dropdown-bg);
|
||||||
border: 1px solid #282828;
|
border: 1px solid #282828;
|
||||||
}
|
}
|
||||||
.dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover {
|
.dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover {
|
||||||
@@ -132,79 +173,79 @@ legend {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
.bootstrap-select>.dropdown-toggle.bs-placeholder, .bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
|
.bootstrap-select>.dropdown-toggle.bs-placeholder, .bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
|
||||||
color: #d4d4d4 !important;
|
color: var(--mc-placeholder) !important;
|
||||||
}
|
}
|
||||||
tbody tr {
|
tbody tr {
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
}
|
}
|
||||||
.navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:focus, .navbar-default .navbar-nav>.open>a:hover {
|
.navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:focus, .navbar-default .navbar-nav>.open>a:hover {
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
}
|
}
|
||||||
.navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:focus, .navbar-default .navbar-nav>.active>a:hover {
|
.navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:focus, .navbar-default .navbar-nav>.active>a:hover {
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
}
|
}
|
||||||
.list-group-item {
|
.list-group-item {
|
||||||
background-color: #282828;
|
background-color: var(--mc-surface-alt);
|
||||||
border: 1px solid #555;
|
border: 1px solid var(--mc-border);
|
||||||
}
|
}
|
||||||
.table-striped>tbody>tr:nth-of-type(odd) {
|
.table-striped>tbody>tr:nth-of-type(odd) {
|
||||||
background-color: #424242;
|
background-color: var(--mc-table-stripe-row);
|
||||||
}
|
}
|
||||||
table.dataTable>tbody>tr.child ul.dtr-details>li {
|
table.dataTable>tbody>tr.child ul.dtr-details>li {
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.13);
|
border-bottom: 1px solid rgba(255, 255, 255, 0.13);
|
||||||
}
|
}
|
||||||
.label.label-last-login {
|
.label.label-last-login {
|
||||||
color: #ccc !important;
|
color: var(--mc-text) !important;
|
||||||
background-color: #555 !important;
|
background-color: #555 !important;
|
||||||
}
|
}
|
||||||
.progress {
|
.progress {
|
||||||
background-color: #555;
|
background-color: var(--mc-progress-bg);
|
||||||
}
|
}
|
||||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
}
|
}
|
||||||
div.numberedtextarea-number {
|
div.numberedtextarea-number {
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
.well {
|
.well {
|
||||||
border: 1px solid #555;
|
border: 1px solid var(--mc-border);
|
||||||
background-color: #282828;
|
background-color: var(--mc-surface-alt);
|
||||||
}
|
}
|
||||||
pre {
|
pre {
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
background-color: #282828;
|
background-color: var(--mc-surface-alt);
|
||||||
border: 1px solid #555;
|
border: 1px solid var(--mc-border);
|
||||||
}
|
}
|
||||||
.form-control {
|
.form-control {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
input.form-control, textarea.form-control {
|
input.form-control, textarea.form-control {
|
||||||
color: #e2e2e2 !important;
|
color: var(--mc-input-color) !important;
|
||||||
background-color: #424242 !important;
|
background-color: var(--mc-input-bg) !important;
|
||||||
border: 1px solid #999;
|
border: 1px solid var(--mc-input-border);
|
||||||
}
|
}
|
||||||
input.form-control:focus, textarea.form-control {
|
input.form-control:focus, textarea.form-control {
|
||||||
background-color: #424242 !important;
|
background-color: var(--mc-input-bg) !important;
|
||||||
}
|
}
|
||||||
input.form-control:disabled, textarea.form-disabled {
|
input.form-control:disabled, textarea.form-disabled {
|
||||||
color: #a8a8a8 !important;
|
color: var(--mc-input-disabled-color) !important;
|
||||||
background-color: #6e6e6e !important;
|
background-color: var(--mc-input-disabled-bg) !important;
|
||||||
}
|
}
|
||||||
.input-group-addon {
|
.input-group-addon {
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
background-color: #424242 !important;
|
background-color: var(--mc-input-bg) !important;
|
||||||
border: 1px solid #999;
|
border: 1px solid var(--mc-input-border);
|
||||||
}
|
}
|
||||||
.input-group-text {
|
.input-group-text {
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
background-color: #1c1c1c;
|
background-color: #1c1c1c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-group-item {
|
.list-group-item {
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
}
|
}
|
||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
}
|
}
|
||||||
.dropdown-item:hover {
|
.dropdown-item:hover {
|
||||||
color: #616161 !important;
|
color: #616161 !important;
|
||||||
@@ -214,9 +255,9 @@ input.form-control:disabled, textarea.form-disabled {
|
|||||||
background-color: #007aff;
|
background-color: #007aff;
|
||||||
}
|
}
|
||||||
.form-select {
|
.form-select {
|
||||||
color: #e2e2e2!important;
|
color: var(--mc-input-color)!important;
|
||||||
background-color: #424242!important;
|
background-color: var(--mc-input-bg)!important;
|
||||||
border: 1px solid #999;
|
border: 1px solid var(--mc-input-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.responsive-tabs .card-header button[data-bs-toggle="collapse"] {
|
.responsive-tabs .card-header button[data-bs-toggle="collapse"] {
|
||||||
@@ -240,15 +281,15 @@ input.form-control:disabled, textarea.form-disabled {
|
|||||||
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #6fc7e9;
|
color: var(--mc-link);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
a:hover {
|
a:hover {
|
||||||
color: #3daedb;
|
color: var(--mc-link-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumb-item.active {
|
.breadcrumb-item.active {
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -273,11 +314,11 @@ a:hover {
|
|||||||
background-color: #3a3a3a;
|
background-color: #3a3a3a;
|
||||||
}
|
}
|
||||||
.accordion-button {
|
.accordion-button {
|
||||||
color: #bbb;
|
color: var(--mc-text-soft);
|
||||||
background-color: #2c2c2c;
|
background-color: #2c2c2c;
|
||||||
}
|
}
|
||||||
.accordion-button:not(.collapsed) {
|
.accordion-button:not(.collapsed) {
|
||||||
color: #6fc7e9;
|
color: var(--mc-link);
|
||||||
background-color: #2c2c2c;
|
background-color: #2c2c2c;
|
||||||
}
|
}
|
||||||
.accordion-button::after {
|
.accordion-button::after {
|
||||||
@@ -300,15 +341,15 @@ a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tag-box {
|
.tag-box {
|
||||||
background-color: #282828;
|
background-color: var(--mc-surface-alt);
|
||||||
border: 1px solid #555;
|
border: 1px solid var(--mc-border);
|
||||||
}
|
}
|
||||||
.tag-input {
|
.tag-input {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #282828;
|
background-color: var(--mc-surface-alt);
|
||||||
}
|
}
|
||||||
.tag-add {
|
.tag-add {
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
}
|
}
|
||||||
.tag-add:hover {
|
.tag-add:hover {
|
||||||
color: #d1d1d1;
|
color: #d1d1d1;
|
||||||
@@ -318,19 +359,19 @@ a:hover {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
.btn-outline-secondary:hover {
|
.btn-outline-secondary:hover {
|
||||||
background-color: #5c5c5c;
|
background-color: var(--mc-btn-outline-hover-bg);
|
||||||
}
|
}
|
||||||
.btn.btn-outline-secondary {
|
.btn.btn-outline-secondary {
|
||||||
color: #e0e0e0 !important;
|
color: var(--mc-btn-outline-color) !important;
|
||||||
border-color: #7a7a7a !important;
|
border-color: var(--mc-btn-outline-border) !important;
|
||||||
}
|
}
|
||||||
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
|
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
|
||||||
background-color: #7a7a7a !important;
|
background-color: var(--mc-btn-outline-active-bg) !important;
|
||||||
}
|
}
|
||||||
.btn-check:checked+.btn-light, .btn-check:active+.btn-light, .btn-light:active, .btn-light.active, .show>.btn-light.dropdown-toggle {
|
.btn-check:checked+.btn-light, .btn-check:active+.btn-light, .btn-light:active, .btn-light.active, .show>.btn-light.dropdown-toggle {
|
||||||
color: #f2f2f7 !important;
|
color: var(--mc-btn-light-active-color) !important;
|
||||||
background-color: #242424 !important;
|
background-color: var(--mc-btn-light-active-bg) !important;
|
||||||
border-color: #1c1c1e !important;
|
border-color: var(--mc-btn-light-active-border) !important;
|
||||||
}
|
}
|
||||||
.btn-input-missing,
|
.btn-input-missing,
|
||||||
.btn-input-missing:hover,
|
.btn-input-missing:hover,
|
||||||
@@ -348,16 +389,16 @@ a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.list-group-details {
|
.list-group-details {
|
||||||
background: #555;
|
background: var(--mc-list-details-bg);
|
||||||
}
|
}
|
||||||
.list-group-header {
|
.list-group-header {
|
||||||
background: #444;
|
background: var(--mc-list-header-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
span.mail-address-item {
|
span.mail-address-item {
|
||||||
background-color: #444;
|
background-color: var(--mc-chip-bg);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid #555;
|
border: 1px solid var(--mc-border);
|
||||||
padding: 2px 7px;
|
padding: 2px 7px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 2px 6px 2px 0;
|
margin: 2px 6px 2px 0;
|
||||||
@@ -365,52 +406,52 @@ span.mail-address-item {
|
|||||||
|
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
|
||||||
background-color: #7a7a7a !important;
|
background-color: var(--mc-dtr-hover-bg) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before {
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before {
|
||||||
background-color: #7a7a7a !important;
|
background-color: var(--mc-dtr-bg) !important;
|
||||||
border: 1.5px solid #5c5c5c !important;
|
border: 1.5px solid var(--mc-dtr-border) !important;
|
||||||
color: #e0e0e0 !important;
|
color: var(--mc-dtr-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before {
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before {
|
||||||
background-color: #949494;
|
background-color: var(--mc-dtr-active-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,
|
||||||
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
|
||||||
background-color: #414141;
|
background-color: var(--mc-table-child-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
table.table, .table-striped>tbody>tr:nth-of-type(odd)>*, tbody tr {
|
table.table, .table-striped>tbody>tr:nth-of-type(odd)>*, tbody tr {
|
||||||
color: #ccc !important;
|
color: var(--mc-text) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-secondary {
|
.table-secondary {
|
||||||
--bs-table-bg: #282828;
|
--bs-table-bg: #282828;
|
||||||
--bs-table-striped-bg: #343434;
|
--bs-table-striped-bg: #343434;
|
||||||
--bs-table-striped-color: #f2f2f7;
|
--bs-table-striped-color: var(--mc-body-color);
|
||||||
--bs-table-active-bg: #4c4c4c;
|
--bs-table-active-bg: #4c4c4c;
|
||||||
--bs-table-active-color: #f2f2f7;
|
--bs-table-active-color: var(--mc-body-color);
|
||||||
--bs-table-hover-bg: #3a3a3a;
|
--bs-table-hover-bg: #3a3a3a;
|
||||||
--bs-table-hover-color: #f2f2f7;
|
--bs-table-hover-color: var(--mc-body-color);
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
border-color: #3a3a3a;
|
border-color: #3a3a3a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-light {
|
.table-light {
|
||||||
--bs-table-bg: #3a3a3a;
|
--bs-table-bg: #3a3a3a;
|
||||||
--bs-table-striped-bg: #444444;
|
--bs-table-striped-bg: #444444;
|
||||||
--bs-table-striped-color: #f2f2f7;
|
--bs-table-striped-color: var(--mc-body-color);
|
||||||
--bs-table-active-bg: #5c5c5c;
|
--bs-table-active-bg: #5c5c5c;
|
||||||
--bs-table-active-color: #f2f2f7;
|
--bs-table-active-color: var(--mc-body-color);
|
||||||
--bs-table-hover-bg: #4c4c4c;
|
--bs-table-hover-bg: #4c4c4c;
|
||||||
--bs-table-hover-color: #f2f2f7;
|
--bs-table-hover-color: var(--mc-body-color);
|
||||||
color: #ccc;
|
color: var(--mc-text);
|
||||||
border-color: #4c4c4c;
|
border-color: #4c4c4c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,23 +471,23 @@ table.table, .table-striped>tbody>tr:nth-of-type(odd)>*, tbody tr {
|
|||||||
|
|
||||||
.table-striped>tbody>tr:nth-of-type(odd)>td,
|
.table-striped>tbody>tr:nth-of-type(odd)>td,
|
||||||
.table-striped>tbody>tr:nth-of-type(odd)>th {
|
.table-striped>tbody>tr:nth-of-type(odd)>th {
|
||||||
background-color: #282828;
|
background-color: var(--mc-table-stripe);
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-hover>tbody>tr:hover {
|
.table-hover>tbody>tr:hover {
|
||||||
background-color: #343434;
|
background-color: var(--mc-table-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.table>:not(caption)>*>* {
|
.table>:not(caption)>*>* {
|
||||||
border-color: #5c5c5c;
|
border-color: var(--mc-table-border);
|
||||||
--bs-table-color-state:#bbb;
|
--bs-table-color-state:var(--mc-text-soft);
|
||||||
--bs-table-bg: #3a3a3a;
|
--bs-table-bg: var(--mc-table-bg);
|
||||||
}
|
}
|
||||||
.text-muted {
|
.text-muted {
|
||||||
--bs-secondary-color: #8e8e93;
|
--bs-secondary-color: var(--mc-muted);
|
||||||
}
|
}
|
||||||
input::placeholder {
|
input::placeholder {
|
||||||
color: #8e8e93 !important;
|
color: var(--mc-muted) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-select {
|
.form-select {
|
||||||
|
|||||||
@@ -233,6 +233,38 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
'msg' => 'custom_login_modified'
|
'msg' => 'custom_login_modified'
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 'ui_theme':
|
||||||
|
$ui_theme = is_array($_data['ui_theme']) ? (string)reset($_data['ui_theme']) : (string)$_data['ui_theme'];
|
||||||
|
if ($ui_theme !== '' && !array_key_exists($ui_theme, customize('get', 'ui_themes'))) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
|
'msg' => 'ui_theme_invalid'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if ($ui_theme === '') {
|
||||||
|
$redis->del('UI_THEME');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$redis->set('UI_THEME', $ui_theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
|
'msg' => array('redis_error', $e)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
|
'msg' => 'ui_theme_modified'
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
@@ -402,6 +434,42 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'ui_themes':
|
||||||
|
// theme folders in css/themes/<name>/ with a theme.css
|
||||||
|
$themes = array();
|
||||||
|
foreach (glob('/web/css/themes/*/theme.css') as $theme_css) {
|
||||||
|
$theme_dir = dirname($theme_css);
|
||||||
|
$theme = basename($theme_dir);
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $theme)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$meta = json_decode(@file_get_contents($theme_dir . '/theme.json'), true);
|
||||||
|
$themes[$theme] = array(
|
||||||
|
'name' => (!empty($meta['name'])) ? $meta['name'] : $theme,
|
||||||
|
'description' => (!empty($meta['description'])) ? $meta['description'] : '',
|
||||||
|
'dark' => file_exists($theme_dir . '/dark.css')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ksort($themes);
|
||||||
|
return $themes;
|
||||||
|
break;
|
||||||
|
case 'ui_theme':
|
||||||
|
try {
|
||||||
|
$ui_theme = $redis->get('UI_THEME');
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
|
'msg' => array('redis_error', $e)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (empty($ui_theme) || !preg_match('/^[a-zA-Z0-9_-]+$/', $ui_theme) || !file_exists('/web/css/themes/' . $ui_theme . '/theme.css')) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return $ui_theme;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ if (preg_match("/debug/i", $_SERVER['REQUEST_URI'])) {
|
|||||||
if ($_SERVER['REQUEST_URI'] == '/') {
|
if ($_SERVER['REQUEST_URI'] == '/') {
|
||||||
$css_minifier->add('/web/css/site/index.css');
|
$css_minifier->add('/web/css/site/index.css');
|
||||||
}
|
}
|
||||||
|
if (file_exists('/web/css/themes/'.$UI_THEME.'/theme.css')) {
|
||||||
|
$css_minifier->add('/web/css/themes/'.$UI_THEME.'/theme.css');
|
||||||
|
}
|
||||||
|
|
||||||
$hash = $css_minifier->getDataHash();
|
$hash = $css_minifier->getDataHash();
|
||||||
$CSSPath = '/tmp/' . $hash . '.css';
|
$CSSPath = '/tmp/' . $hash . '.css';
|
||||||
@@ -30,6 +33,17 @@ if(!file_exists($CSSPath)) {
|
|||||||
cleanupCSS($hash);
|
cleanupCSS($hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dark mode bundle, core dark mode + theme dark.css
|
||||||
|
$dark_minifier = new CSSminifierExtended('/web/css/themes/mailcow-darkmode.css');
|
||||||
|
if (file_exists('/web/css/themes/'.$UI_THEME.'/dark.css')) {
|
||||||
|
$dark_minifier->add('/web/css/themes/'.$UI_THEME.'/dark.css');
|
||||||
|
}
|
||||||
|
$DarkCSSPath = '/tmp/' . $hash . '-' . $dark_minifier->getDataHash() . '.css';
|
||||||
|
if(!file_exists($DarkCSSPath)) {
|
||||||
|
$dark_minifier->minify($DarkCSSPath);
|
||||||
|
}
|
||||||
|
$dark_css_path = '/cache/' . basename($DarkCSSPath);
|
||||||
|
|
||||||
$mailcow_apps_processed = $MAILCOW_APPS;
|
$mailcow_apps_processed = $MAILCOW_APPS;
|
||||||
$app_links = customize('get', 'app_links');
|
$app_links = customize('get', 'app_links');
|
||||||
$app_links_processed = $app_links;
|
$app_links_processed = $app_links;
|
||||||
@@ -77,6 +91,7 @@ $globalVariables = [
|
|||||||
'dual_login' => @$_SESSION['dual-login'],
|
'dual_login' => @$_SESSION['dual-login'],
|
||||||
'ui_texts' => $UI_TEXTS,
|
'ui_texts' => $UI_TEXTS,
|
||||||
'css_path' => '/cache/'.basename($CSSPath),
|
'css_path' => '/cache/'.basename($CSSPath),
|
||||||
|
'dark_css_path' => $dark_css_path,
|
||||||
'logo' => customize('get', 'main_logo'),
|
'logo' => customize('get', 'main_logo'),
|
||||||
'logo_dark' => customize('get', 'main_logo_dark'),
|
'logo_dark' => customize('get', 'main_logo_dark'),
|
||||||
'available_languages' => $AVAILABLE_LANGUAGES,
|
'available_languages' => $AVAILABLE_LANGUAGES,
|
||||||
|
|||||||
@@ -319,10 +319,16 @@ $css_minifier = new CSSminifierExtended();
|
|||||||
$css_dir = array_diff(scandir('/web/css/build'), array('..', '.'));
|
$css_dir = array_diff(scandir('/web/css/build'), array('..', '.'));
|
||||||
// get customized ui data
|
// get customized ui data
|
||||||
$UI_TEXTS = customize('get', 'ui_texts');
|
$UI_TEXTS = customize('get', 'ui_texts');
|
||||||
|
// theme selected in admin UI overrides $UI_THEME
|
||||||
|
if ($ui_theme_selected = customize('get', 'ui_theme')) {
|
||||||
|
$UI_THEME = $ui_theme_selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// minify bootstrap theme
|
// minify bootstrap theme
|
||||||
if (file_exists('/web/css/themes/'.$UI_THEME.'-bootstrap.css'))
|
if (file_exists('/web/css/themes/'.$UI_THEME.'/bootstrap.css'))
|
||||||
|
$css_minifier->add('/web/css/themes/'.$UI_THEME.'/bootstrap.css');
|
||||||
|
elseif (file_exists('/web/css/themes/'.$UI_THEME.'-bootstrap.css'))
|
||||||
$css_minifier->add('/web/css/themes/'.$UI_THEME.'-bootstrap.css');
|
$css_minifier->add('/web/css/themes/'.$UI_THEME.'-bootstrap.css');
|
||||||
else
|
else
|
||||||
$css_minifier->add('/web/css/themes/lumen-bootstrap.css');
|
$css_minifier->add('/web/css/themes/lumen-bootstrap.css');
|
||||||
|
|||||||
@@ -121,6 +121,8 @@ $AVAILABLE_LANGUAGES = array(
|
|||||||
// default theme is lumen
|
// default theme is lumen
|
||||||
// additional themes can be found here: https://bootswatch.com/
|
// additional themes can be found here: https://bootswatch.com/
|
||||||
// copy them to data/web/css/themes/{THEME-NAME}-bootstrap.css
|
// copy them to data/web/css/themes/{THEME-NAME}-bootstrap.css
|
||||||
|
// or use a theme folder data/web/css/themes/{THEME-NAME}/ (theme.css, optional dark.css, bootstrap.css, theme.json)
|
||||||
|
// theme folders can be selected in System > Configuration > Customize, which overrides $UI_THEME
|
||||||
$UI_THEME = "lumen";
|
$UI_THEME = "lumen";
|
||||||
|
|
||||||
// Show DKIM private keys - false by default
|
// Show DKIM private keys - false by default
|
||||||
|
|||||||
+3
-3
File diff suppressed because one or more lines are too long
@@ -124,6 +124,9 @@ $(document).ready(function() {
|
|||||||
var lastTab = localStorage.getItem(key);
|
var lastTab = localStorage.getItem(key);
|
||||||
if (lastTab) {
|
if (lastTab) {
|
||||||
$('[data-bs-target="#' + lastTab + '"]').click();
|
$('[data-bs-target="#' + lastTab + '"]').click();
|
||||||
|
var dropdown = $('[data-bs-target="#' + lastTab + '"]').closest('.dropdown');
|
||||||
|
dropdown.find('.dropdown-menu').removeClass('show');
|
||||||
|
dropdown.find('.dropdown-toggle').attr('aria-expanded', 'false');
|
||||||
var tab = $('[id^="' + lastTab + '"]');
|
var tab = $('[id^="' + lastTab + '"]');
|
||||||
$(tab).find('.card-body.collapse:first').collapse('show');
|
$(tab).find('.card-body.collapse:first').collapse('show');
|
||||||
}
|
}
|
||||||
@@ -347,7 +350,7 @@ $(document).ready(function() {
|
|||||||
if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_dark.png');
|
if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_dark.png');
|
||||||
localStorage.setItem('mailcow_theme', 'light');
|
localStorage.setItem('mailcow_theme', 'light');
|
||||||
}else{
|
}else{
|
||||||
$('head').append('<link id="dark-mode-theme" rel="stylesheet" type="text/css" href="/css/themes/mailcow-darkmode.css">');
|
$('head').append('<link id="dark-mode-theme" rel="stylesheet" type="text/css" href="' + mailcow_dark_css + '">');
|
||||||
$('#dark-mode-toggle').prop('checked', true);
|
$('#dark-mode-toggle').prop('checked', true);
|
||||||
$('.main-logo').addClass('d-none');
|
$('.main-logo').addClass('d-none');
|
||||||
$('.main-logo-dark').removeClass('d-none');
|
$('.main-logo-dark').removeClass('d-none');
|
||||||
|
|||||||
@@ -2038,6 +2038,9 @@ if (isset($_GET['query'])) {
|
|||||||
case "custom_login":
|
case "custom_login":
|
||||||
process_edit_return(customize('edit', 'custom_login', $attr));
|
process_edit_return(customize('edit', 'custom_login', $attr));
|
||||||
break;
|
break;
|
||||||
|
case "ui_theme":
|
||||||
|
process_edit_return(customize('edit', 'ui_theme', $attr));
|
||||||
|
break;
|
||||||
case "self":
|
case "self":
|
||||||
if ($_SESSION['mailcow_cc_role'] == "domainadmin") {
|
if ($_SESSION['mailcow_cc_role'] == "domainadmin") {
|
||||||
process_edit_return(domain_admin('edit', $attr));
|
process_edit_return(domain_admin('edit', $attr));
|
||||||
|
|||||||
@@ -395,6 +395,11 @@
|
|||||||
"ui_header_announcement_type_info": "Info",
|
"ui_header_announcement_type_info": "Info",
|
||||||
"ui_header_announcement_type_warning": "Wichtig",
|
"ui_header_announcement_type_warning": "Wichtig",
|
||||||
"ui_texts": "UI-Label und Texte",
|
"ui_texts": "UI-Label und Texte",
|
||||||
|
"ui_theme": "Theme",
|
||||||
|
"ui_theme_dark": "Enthält eine Darkmode-Variante",
|
||||||
|
"ui_theme_default": "Standard (mailcow)",
|
||||||
|
"ui_theme_info": "Themes sind Ordner in <code>data/web/css/themes/<name>/</code> mit einer <code>theme.css</code>. Optional: <code>dark.css</code> (Darkmode), <code>bootstrap.css</code> (ersetzt das Bootstrap-Basistheme) und <code>theme.json</code> (<code>name</code>, <code>description</code>).",
|
||||||
|
"ui_theme_none": "Keine Themes gefunden.",
|
||||||
"unban_pending": "ausstehend",
|
"unban_pending": "ausstehend",
|
||||||
"unchanged_if_empty": "Unverändert, wenn leer",
|
"unchanged_if_empty": "Unverändert, wenn leer",
|
||||||
"upload": "Hochladen",
|
"upload": "Hochladen",
|
||||||
@@ -550,6 +555,7 @@
|
|||||||
"webauthn_authenticator_failed": "Der ausgewählte Authenticator wurde nicht gefunden",
|
"webauthn_authenticator_failed": "Der ausgewählte Authenticator wurde nicht gefunden",
|
||||||
"webauthn_publickey_failed": "Zu dem ausgewählten Authenticator wurde kein Publickey hinterlegt",
|
"webauthn_publickey_failed": "Zu dem ausgewählten Authenticator wurde kein Publickey hinterlegt",
|
||||||
"webauthn_username_failed": "Der ausgewählte Authenticator gehört zu einem anderen Konto",
|
"webauthn_username_failed": "Der ausgewählte Authenticator gehört zu einem anderen Konto",
|
||||||
|
"ui_theme_invalid": "Theme nicht gefunden",
|
||||||
"unknown": "Ein unbekannter Fehler trat auf",
|
"unknown": "Ein unbekannter Fehler trat auf",
|
||||||
"unknown_tfa_method": "Unbekannte TFA-Methode",
|
"unknown_tfa_method": "Unbekannte TFA-Methode",
|
||||||
"unlimited_quota_acl": "Unendliche Quota untersagt durch ACL",
|
"unlimited_quota_acl": "Unendliche Quota untersagt durch ACL",
|
||||||
@@ -1206,6 +1212,7 @@
|
|||||||
"tls_policy_map_entry_deleted": "TLS-Richtlinie mit der ID %s wurde gelöscht",
|
"tls_policy_map_entry_deleted": "TLS-Richtlinie mit der ID %s wurde gelöscht",
|
||||||
"tls_policy_map_entry_saved": "TLS-Richtlinieneintrag \"%s\" wurde gespeichert",
|
"tls_policy_map_entry_saved": "TLS-Richtlinieneintrag \"%s\" wurde gespeichert",
|
||||||
"ui_texts": "Änderungen an UI-Texten",
|
"ui_texts": "Änderungen an UI-Texten",
|
||||||
|
"ui_theme_modified": "Theme wurde erfolgreich gespeichert",
|
||||||
"upload_success": "Datei wurde erfolgreich hochgeladen",
|
"upload_success": "Datei wurde erfolgreich hochgeladen",
|
||||||
"verified_fido2_login": "FIDO2-Anmeldung verifiziert",
|
"verified_fido2_login": "FIDO2-Anmeldung verifiziert",
|
||||||
"verified_totp_login": "TOTP-Anmeldung verifiziert",
|
"verified_totp_login": "TOTP-Anmeldung verifiziert",
|
||||||
|
|||||||
@@ -405,6 +405,11 @@
|
|||||||
"ui_header_announcement_type_info": "Info",
|
"ui_header_announcement_type_info": "Info",
|
||||||
"ui_header_announcement_type_warning": "Important",
|
"ui_header_announcement_type_warning": "Important",
|
||||||
"ui_texts": "UI labels and texts",
|
"ui_texts": "UI labels and texts",
|
||||||
|
"ui_theme": "Theme",
|
||||||
|
"ui_theme_dark": "Includes a dark mode variant",
|
||||||
|
"ui_theme_default": "Default (mailcow)",
|
||||||
|
"ui_theme_info": "Themes are folders in <code>data/web/css/themes/<name>/</code> containing a <code>theme.css</code>. Optional: <code>dark.css</code> (dark mode), <code>bootstrap.css</code> (replaces the Bootstrap base theme) and <code>theme.json</code> (<code>name</code>, <code>description</code>).",
|
||||||
|
"ui_theme_none": "No themes found.",
|
||||||
"unban_pending": "unban pending",
|
"unban_pending": "unban pending",
|
||||||
"unchanged_if_empty": "If unchanged leave blank",
|
"unchanged_if_empty": "If unchanged leave blank",
|
||||||
"upload": "Upload",
|
"upload": "Upload",
|
||||||
@@ -554,6 +559,7 @@
|
|||||||
"webauthn_authenticator_failed": "The selected authenticator was not found",
|
"webauthn_authenticator_failed": "The selected authenticator was not found",
|
||||||
"webauthn_publickey_failed": "No public key was stored for the selected authenticator",
|
"webauthn_publickey_failed": "No public key was stored for the selected authenticator",
|
||||||
"webauthn_username_failed": "The selected authenticator belongs to another account",
|
"webauthn_username_failed": "The selected authenticator belongs to another account",
|
||||||
|
"ui_theme_invalid": "Theme not found",
|
||||||
"unknown": "An unknown error occurred",
|
"unknown": "An unknown error occurred",
|
||||||
"unknown_tfa_method": "Unknown TFA method",
|
"unknown_tfa_method": "Unknown TFA method",
|
||||||
"unlimited_quota_acl": "Unlimited quota prohibited by ACL",
|
"unlimited_quota_acl": "Unlimited quota prohibited by ACL",
|
||||||
@@ -1214,6 +1220,7 @@
|
|||||||
"tls_policy_map_entry_deleted": "TLS policy map ID %s has been deleted",
|
"tls_policy_map_entry_deleted": "TLS policy map ID %s has been deleted",
|
||||||
"tls_policy_map_entry_saved": "TLS policy map entry \"%s\" has been saved",
|
"tls_policy_map_entry_saved": "TLS policy map entry \"%s\" has been saved",
|
||||||
"ui_texts": "Saved changes to UI texts",
|
"ui_texts": "Saved changes to UI texts",
|
||||||
|
"ui_theme_modified": "Theme was saved successfully",
|
||||||
"upload_success": "File uploaded successfully",
|
"upload_success": "File uploaded successfully",
|
||||||
"verified_fido2_login": "Verified FIDO2 login",
|
"verified_fido2_login": "Verified FIDO2 login",
|
||||||
"verified_totp_login": "Verified TOTP login",
|
"verified_totp_login": "Verified TOTP login",
|
||||||
|
|||||||
@@ -7,7 +7,33 @@
|
|||||||
<span class="d-none d-md-block">{{ lang.admin.customize }}</span>
|
<span class="d-none d-md-block">{{ lang.admin.customize }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="collapse-tab-config-customize" class="card-body collapse" data-bs-parent="#admin-content">
|
<div id="collapse-tab-config-customize" class="card-body collapse" data-bs-parent="#admin-content">
|
||||||
<legend><i class="bi bi-file-image"></i> {{ lang.admin.change_logo }}</legend><hr />
|
<legend><i class="bi bi-palette"></i> {{ lang.admin.ui_theme }}</legend><hr />
|
||||||
|
<p class="text-muted">{{ lang.admin.ui_theme_info|raw }}</p>
|
||||||
|
<form class="form" data-id="ui_theme" role="form" method="post">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-6 col-lg-4">
|
||||||
|
<p><select data-width="100%" id="ui_theme" name="ui_theme" class="selectpicker show-tick">
|
||||||
|
<option value="" {% if not ui_theme %}selected{% endif %}>{{ lang.admin.ui_theme_default }}</option>
|
||||||
|
{% for key, theme in ui_themes %}
|
||||||
|
<option value="{{ key }}" {% if ui_theme == key %}selected{% endif %}>{{ theme.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if ui_themes %}
|
||||||
|
<ul class="list-unstyled text-muted small mb-4">
|
||||||
|
{% for key, theme in ui_themes %}
|
||||||
|
<li><b>{{ theme.name }}</b> <code>{{ key }}</code>{% if theme.dark %} <i class="bi bi-moon-fill" title="{{ lang.admin.ui_theme_dark }}"></i>{% endif %}{% if theme.description %} - {{ theme.description }}{% endif %}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<p class="text-muted small mb-4">{{ lang.admin.ui_theme_none }}</p>
|
||||||
|
{% endif %}
|
||||||
|
<p><div class="btn-group">
|
||||||
|
<button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-success" data-action="edit_selected" data-item="admin" data-id="ui_theme" data-api-url='edit/ui_theme' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
|
||||||
|
</div></p>
|
||||||
|
</form>
|
||||||
|
<legend style="padding-top:20px"><i class="bi bi-file-image"></i> {{ lang.admin.change_logo }}</legend><hr />
|
||||||
<p class="text-muted">{{ lang.admin.logo_info }}</p>
|
<p class="text-muted">{{ lang.admin.logo_info }}</p>
|
||||||
<form class="form-inline" role="form" method="post" enctype="multipart/form-data">
|
<form class="form-inline" role="form" method="post" enctype="multipart/form-data">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="{{ css_path }}">
|
<link rel="stylesheet" href="{{ css_path }}">
|
||||||
<script>
|
<script>
|
||||||
|
var mailcow_dark_css = '{{ dark_css_path }}';
|
||||||
// check if darkmode is preferred by OS or set by localStorage
|
// check if darkmode is preferred by OS or set by localStorage
|
||||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches && localStorage.getItem("mailcow_theme") !== "light" ||
|
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches && localStorage.getItem("mailcow_theme") !== "light" ||
|
||||||
localStorage.getItem("mailcow_theme") === "dark") {
|
localStorage.getItem("mailcow_theme") === "dark") {
|
||||||
@@ -18,7 +19,7 @@
|
|||||||
link.id = 'dark-mode-theme';
|
link.id = 'dark-mode-theme';
|
||||||
link.rel = 'stylesheet';
|
link.rel = 'stylesheet';
|
||||||
link.type = 'text/css';
|
link.type = 'text/css';
|
||||||
link.href = '/css/themes/mailcow-darkmode.css';
|
link.href = mailcow_dark_css;
|
||||||
head.appendChild(link);
|
head.appendChild(link);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
<li class="nav-item dropdown" role="presentation">
|
<li class="nav-item dropdown" role="presentation">
|
||||||
<a class="nav-link dropdown-toggle active" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.domains }}</a>
|
<a class="nav-link dropdown-toggle active" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.domains }}</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><button class="dropdown-item" aria-selected="false" aria-controls="tab-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-domains">{{ lang.mailbox.domains }}</button></li>
|
<li><button class="dropdown-item active" aria-selected="true" aria-controls="tab-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-domains">{{ lang.mailbox.domains }}</button></li>
|
||||||
<li><button class="dropdown-item" aria-selected="false" aria-controls="tab-templates-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-templates-domains">{{ lang.mailbox.templates }}</button></li>
|
<li><button class="dropdown-item" aria-selected="false" aria-controls="tab-templates-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-templates-domains">{{ lang.mailbox.templates }}</button></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="nav-item" role="presentation"><button class="nav-link" aria-controls="tab-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-domains">{{ lang.mailbox.domains }}</button></li>
|
<li class="nav-item" role="presentation"><button class="nav-link active" aria-selected="true" aria-controls="tab-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-domains">{{ lang.mailbox.domains }}</button></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if mailcow_cc_role == 'admin' %}
|
{% if mailcow_cc_role == 'admin' %}
|
||||||
<li class="nav-item dropdown" role="presentation">
|
<li class="nav-item dropdown" role="presentation">
|
||||||
|
|||||||
Reference in New Issue
Block a user