[BS5] remove ui theme selector - add darkmode toggler

This commit is contained in:
FreddleSpl0it 2022-06-23 16:34:58 +02:00
parent 560df58bb4
commit 052959f435
38 changed files with 233 additions and 286379 deletions

View File

@ -83,16 +83,12 @@ foreach ($RSPAMD_MAPS['regex'] as $rspamd_regex_desc => $rspamd_regex_map) {
]; ];
} }
$themes = array_diff(scandir('/web/css/themes'), array('..', '.'));
$themes = array_filter((str_replace("-bootstrap.css", "", $themes)));
$template = 'admin.twig'; $template = 'admin.twig';
$template_data = [ $template_data = [
'tfa_data' => $tfa_data, 'tfa_data' => $tfa_data,
'tfa_id' => @$_SESSION['tfa_id'], 'tfa_id' => @$_SESSION['tfa_id'],
'fido2_cid' => @$_SESSION['fido2_cid'], 'fido2_cid' => @$_SESSION['fido2_cid'],
'fido2_data' => $fido2_data, 'fido2_data' => $fido2_data,
'themes' => $themes,
'gal' => @$_SESSION['gal'], 'gal' => @$_SESSION['gal'],
'license_guid' => license('guid'), 'license_guid' => license('guid'),
'api' => [ 'api' => [

View File

@ -63,6 +63,10 @@
.navbar-nav { .navbar-nav {
margin: 0; margin: 0;
} }
.navbar-nav .nav-item {
display: flex;
padding: 0 10px !important;
}
.navbar-nav .nav-link { .navbar-nav .nav-link {
height: 44px; height: 44px;
display: flex; display: flex;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -597,7 +597,7 @@ progress {
color: #999; color: #999;
} }
.blockquote-footer::before { .blockquote-footer::before {
content: "— "; content: "— ";
} }
.img-fluid { .img-fluid {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,181 @@
body {
background-color: #414141;
color: #ccc;
}
.card {
border: 1px solid #1c1c1c;
background-color: #3a3a3a;
}
legend {
color: #f5f5f5;
}
.card-header {
color: #bbb;
background-color: #2c2c2c;
border-color: transparent;
}
.btn-secondary, .paginate_button .page-link, .btn-light {
color: #fff;
background-color: #7a7a7a !important;
border-color: #5c5c5c !important;
}
.btn-secondary:focus, .btn-secondary:hover, .btn-group.open .dropdown-toggle.btn-secondary {
background-color: #7a7a7a;
border-color: #5c5c5c !important;
color: #fff;
}
.modal-content {
background-color: #383838;
}
.modal-header {
border-bottom: 1px solid #161616;
}
.modal-title {
color: white;
}
.modal .btn-close {
filter: invert(1) grayscale(100%) brightness(200%);
}
.navbar.bg-light {
background-color: #222222 !important;
border-color: #181818;
}
.nav-link {
color: #ccc !important;
}
.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link {
background: none;
}
.nav-tabs .nav-link:not(.disabled):hover, .nav-tabs .nav-link:not(.disabled):focus, .nav-tabs .nav-link.active {
border-bottom-color: #414141;
}
.table, .table-striped>tbody>tr:nth-of-type(odd)>*, tbody tr {
color: #ccc !important;
}
.dropdown-menu {
background-color: #585858;
border: 1px solid #333;
}
.dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover {
color: #fafafa;
}
.bootstrap-select>.dropdown-toggle.bs-placeholder, .bootstrap-select>.dropdown-toggle.bs-placeholder:active, .bootstrap-select>.dropdown-toggle.bs-placeholder:focus, .bootstrap-select>.dropdown-toggle.bs-placeholder:hover {
color: #fff;
}
tbody tr {
color: #555;
}
.navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:focus, .navbar-default .navbar-nav>.open>a:hover {
color: #ccc;
}
.navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:focus, .navbar-default .navbar-nav>.active>a:hover {
color: #ccc;
}
.list-group-item {
background-color: #333;
border: 1px solid #555;
}
.table-striped>tbody>tr:nth-of-type(odd) {
background-color: #333;
}
tbody tr {
color: #ccc;
}
.label.label-last-login {
color: #ccc !important;
background-color: #555 !important;
}
.progress {
background-color: #555;
}
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
color: #ccc;
}
div.numberedtextarea-number {
color: #999;
}
.well {
border: 1px solid #555;
background-color: #333;
}
pre {
color: #ccc;
background-color: #333;
border: 1px solid #555;
}
input.form-control, textarea.form-control {
color: #e2e2e2 !important;
background-color: #555;
border: 1px solid #999;
}
input.form-control:focus, textarea.form-control {
background-color: #555 !important;
}
input.form-control:disabled, textarea.form-disabled {
color: #a8a8a8 !important;
background-color: #1a1a1a !important;
}
.input-group-addon {
color: #ccc;
background-color: #555;
border: 1px solid #999;
}
.input-group-text {
color: #ccc;
background-color: #242424;
}
.tag-add {
color: #ccc;
}
.tag-add:hover {
color: #d1d1d1;
}
/* Update 2022-02-09 */
/* Rspamd Settings */
a.list-group-item, button.list-group-item {
color: #fafafa;
background-color: #28b62c;
border-color: #23a127;
}
a.list-group-item:focus, a.list-group-item:hover, button.list-group-item:focus, button.list-group-item:hover {
margin-top: 1px;
border-bottom-width: 3px;
background-color: #28b62c;
border-color: #23a127;
color: white;
}
.list-group-item {
color: #ccc;
}
.dropdown-item {
color: #ccc;
}
.dropdown-item:hover {
color: #616161 !important;
}
.dropdown-item.active:hover {
color: #fff !important;
background-color: #31b1e4;
}
.form-select {
color: #e2e2e2!important;
background-color: #555!important;
border: 1px solid #999;
}
.responsive-tabs .card-header .btn {
color: #c7c7c7;
}
.responsive-tabs .card-header .btn:hover {
color: #fff;
}
.navbar-toggler {
color: #fff !important;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -117,20 +117,6 @@ function customize($_action, $_item, $_data = null) {
$ui_announcement_type = (in_array($_data['ui_announcement_type'], array('info', 'warning', 'danger'))) ? $_data['ui_announcement_type'] : false; $ui_announcement_type = (in_array($_data['ui_announcement_type'], array('info', 'warning', 'danger'))) ? $_data['ui_announcement_type'] : false;
$ui_announcement_active = (!empty($_data['ui_announcement_active']) ? 1 : 0); $ui_announcement_active = (!empty($_data['ui_announcement_active']) ? 1 : 0);
// check theme
$theme = strtolower($_data['ui_theme']);
$themes = array_diff(scandir('/web/css/themes'), array('..', '.'));
$themes = array_filter((str_replace("-bootstrap.css", "", $themes)));
if (!in_array($theme, $themes)){
// err, theme not found
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => "Theme not found"
);
return false;
}
try { try {
$redis->set('TITLE_NAME', htmlspecialchars($title_name)); $redis->set('TITLE_NAME', htmlspecialchars($title_name));
$redis->set('MAIN_NAME', htmlspecialchars($main_name)); $redis->set('MAIN_NAME', htmlspecialchars($main_name));
@ -140,7 +126,6 @@ function customize($_action, $_item, $_data = null) {
$redis->set('UI_ANNOUNCEMENT_TEXT', $ui_announcement_text); $redis->set('UI_ANNOUNCEMENT_TEXT', $ui_announcement_text);
$redis->set('UI_ANNOUNCEMENT_TYPE', $ui_announcement_type); $redis->set('UI_ANNOUNCEMENT_TYPE', $ui_announcement_type);
$redis->set('UI_ANNOUNCEMENT_ACTIVE', $ui_announcement_active); $redis->set('UI_ANNOUNCEMENT_ACTIVE', $ui_announcement_active);
$redis->set('UI_THEME', $theme);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
@ -244,19 +229,6 @@ function customize($_action, $_item, $_data = null) {
return false; return false;
} }
break; break;
case 'ui_theme':
try {
return $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;
}
break;
case 'main_logo_specs': case 'main_logo_specs':
try { try {
$image = new Imagick(); $image = new Imagick();

View File

@ -252,7 +252,8 @@ $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');
$UI_THEME = customize('get', 'ui_theme');
// 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'); $css_minifier->add('/web/css/themes/'.$UI_THEME.'-bootstrap.css');

View File

@ -104,6 +104,11 @@ $AVAILABLE_LANGUAGES = array(
'zh' => '中文 (Chinese)' 'zh' => '中文 (Chinese)'
); );
// default theme is lumen
// additional themes can be found here: https://bootswatch.com/
// copy them to data/web/css/themes/{THEME-NAME}-bootstrap.css
$UI_THEME = "lumen";
// Show DKIM private keys - false by default // Show DKIM private keys - false by default
$SHOW_DKIM_PRIV_KEYS = false; $SHOW_DKIM_PRIV_KEYS = false;

View File

@ -320,6 +320,28 @@ $(document).ready(function() {
$(tagValuesElem).val(JSON.stringify(value_tags)); $(tagValuesElem).val(JSON.stringify(value_tags));
$(tagInputElem).val(''); $(tagInputElem).val('');
} }
// Dark Mode Loader
// check if darkmode is preferred by OS
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)
toggleDarkMode();
// check if darkmode is set by localStorage
if (JSON.parse(localStorage.getItem("darkmode")) === true)
toggleDarkMode();
// register dark mode toggle event listener
$('#dark-mode-toggle').click(toggleDarkMode);
// dark mode toggle funtion
function toggleDarkMode(){
if($('#dark-mode-theme').length){
$('#dark-mode-theme').remove();
$('#dark-mode-toggle').prop('checked', false);
localStorage.setItem('darkmode', 'false');
}else{
$('head').append('<link id="dark-mode-theme" rel="stylesheet" type="text/css" href="/css/themes/mailcow-darkmode.css">');
$('#dark-mode-toggle').prop('checked', true);
localStorage.setItem('darkmode', 'true');
}
}
}); });

View File

@ -1,3 +1,5 @@
$(document).ready(function() { $(document).ready(function() {
var darkmode = localStorage.getItem("darkmode");
localStorage.clear(); localStorage.clear();
localStorage.setItem("darkmode", darkmode);
}); });

View File

@ -338,7 +338,6 @@
"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": "Design",
"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",

View File

@ -67,14 +67,6 @@
<legend data-bs-target="#ui_texts" style="padding-top:20px" unselectable="on">{{ lang.admin.ui_texts }}</legend><hr /> <legend data-bs-target="#ui_texts" style="padding-top:20px" unselectable="on">{{ lang.admin.ui_texts }}</legend><hr />
<div id="ui_texts"> <div id="ui_texts">
<form class="form" data-id="uitexts" role="form" method="post"> <form class="form" data-id="uitexts" role="form" method="post">
<div class="mb-4 d-flex flex-column">
<label for="uitests_theme">{{ lang.admin.ui_theme }}:</label>
<select class="full-width-select" data-live-search="true" id="uitests_theme" name="ui_theme" required>
{% for theme in themes %}
<option>{{ theme }}</option>
{% endfor %}
</select>
</div>
<div class="mb-2"> <div class="mb-2">
<label for="uitests_title_name">{{ lang.admin.title_name }}:</label> <label for="uitests_title_name">{{ lang.admin.title_name }}:</label>
<input type="text" class="form-control" id="uitests_title_name" name="title_name" placeholder="mailcow UI" value="{{ ui_texts.title_name|raw }}"> <input type="text" class="form-control" id="uitests_title_name" name="title_name" placeholder="mailcow UI" value="{{ ui_texts.title_name|raw }}">

View File

@ -19,10 +19,16 @@
<div class="container-fluid"> <div class="container-fluid">
<a class="navbar-brand" href="/"><img alt="mailcow-logo" src="{{ logo|default('/img/cow_mailcow.svg') }}"></a> <a class="navbar-brand" href="/"><img alt="mailcow-logo" src="{{ logo|default('/img/cow_mailcow.svg') }}"></a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <i class="bi bi-list fs-3"></i>
</button> </button>
<div id="navbar" class="navbar-collapse collapse"> <div id="navbar" class="navbar-collapse collapse">
<ul class="navbar-nav ms-auto"> <ul class="navbar-nav ms-auto">
<li class="nav-item">
<div class="nav-link form-check form-switch my-auto d-flex align-items-center">
<label class="form-check-label"><i class="bi bi-moon-fill"></i></label>
<input class="form-check-input ms-2" type="checkbox" id="dark-mode-toggle">
</div>
</li>
{% if mailcow_locale %} {% if mailcow_locale %}
<li class="nav-item dropdown{% if available_languages|length == 1 %}lang-link-disabled{% endif %}"> <li class="nav-item dropdown{% if available_languages|length == 1 %}lang-link-disabled{% endif %}">
<a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" role="button" aria-expanded="false"><span class="flag-icon flag-icon-{{ mailcow_locale }}"></span></a> <a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" role="button" aria-expanded="false"><span class="flag-icon flag-icon-{{ mailcow_locale }}"></span></a>
@ -78,9 +84,9 @@
</li> </li>
{% endif %} {% endif %}
{% if not dual_login and mailcow_cc_username %} {% if not dual_login and mailcow_cc_username %}
<li class="logged-in-as" class="nav-item"><a href="#" onclick="logout.submit()" class="nav-link"><b class="username-lia">{{ mailcow_cc_username }}</b> <i class="bi bi-power ms-2"></i></a></li> <li class="logged-in-as nav-item"><a href="#" onclick="logout.submit()" class="nav-link"><b class="username-lia">{{ mailcow_cc_username }}</b> <i class="bi bi-power ms-2"></i></a></li>
{% elseif dual_login %} {% elseif dual_login %}
<li class="logged-in-as" class="nav-item"><a href="#" onclick="logout.submit()" class="nav-link"><b class="username-lia">{{ mailcow_cc_username }} <span class="text-info">({{ dual_login.username }})</span> </b><i class="bi bi-power ms-2"></i></a></li> <li class="logged-in-as nav-item"><a href="#" onclick="logout.submit()" class="nav-link"><b class="username-lia">{{ mailcow_cc_username }} <span class="text-info">({{ dual_login.username }})</span> </b><i class="bi bi-power ms-2"></i></a></li>
{% endif %} {% endif %}
{% if not is_master %} {% if not is_master %}
<li class="text-warning slave-info nav-item">[ slave ]</li> <li class="text-warning slave-info nav-item">[ slave ]</li>

View File

@ -6,7 +6,13 @@
<div class="row my-4"> <div class="row my-4">
<div class="col-12 col-md-7 col-lg-6 col-xl-5 ms-auto me-auto"> <div class="col-12 col-md-7 col-lg-6 col-xl-5 ms-auto me-auto">
<div class="card"> <div class="card">
<div class="card-header"><i class="bi bi-person-fill"></i> {{ lang.login.login }}</div> <div class="card-header d-flex">
<i class="bi bi-person-fill"></i> {{ lang.login.login }}
<div class="ms-auto form-check form-switch my-auto d-flex align-items-center">
<label class="form-check-label"><i class="bi bi-moon-fill"></i></label>
<input class="form-check-input ms-2" type="checkbox" id="dark-mode-toggle">
</div>
</div>
<div class="card-body"> <div class="card-body">
<div class="text-center mailcow-logo mb-4"><img src="{{ logo|default('/img/cow_mailcow.svg') }}" alt="mailcow"></div> <div class="text-center mailcow-logo mb-4"><img src="{{ logo|default('/img/cow_mailcow.svg') }}" alt="mailcow"></div>
{% if ui_texts.ui_announcement_text and ui_texts.ui_announcement_active %} {% if ui_texts.ui_announcement_text and ui_texts.ui_announcement_active %}