Browse Source

[Web] dark mode logo support

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
Kristian Feldsam 2 years ago
parent
commit
3540075b61

+ 1 - 0
data/web/admin.php

@@ -108,6 +108,7 @@ $template_data = [
   'rsettings' => $rsettings,
   'rsettings' => $rsettings,
   'rspamd_regex_maps' => $rspamd_regex_maps,
   'rspamd_regex_maps' => $rspamd_regex_maps,
   'logo_specs' => customize('get', 'main_logo_specs'),
   'logo_specs' => customize('get', 'main_logo_specs'),
+  'logo_dark_specs' => customize('get', 'main_logo_dark_specs'),
   'ip_check' => customize('get', 'ip_check'),
   'ip_check' => customize('get', 'ip_check'),
   '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'],

+ 15 - 7
data/web/inc/functions.customize.inc.php

@@ -24,9 +24,10 @@ function customize($_action, $_item, $_data = null) {
       }
       }
       switch ($_item) {
       switch ($_item) {
         case 'main_logo':
         case 'main_logo':
-          if (in_array($_data['main_logo']['type'], array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/x-png', 'image/png', 'image/svg+xml'))) {
+        case 'main_logo_dark':
+          if (in_array($_data[$_item]['type'], array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/x-png', 'image/png', 'image/svg+xml'))) {
             try {
             try {
-              if (file_exists($_data['main_logo']['tmp_name']) !== true) {
+              if (file_exists($_data[$_item]['tmp_name']) !== true) {
                 $_SESSION['return'][] = array(
                 $_SESSION['return'][] = array(
                   'type' => 'danger',
                   'type' => 'danger',
                   'log' => array(__FUNCTION__, $_action, $_item, $_data),
                   'log' => array(__FUNCTION__, $_action, $_item, $_data),
@@ -34,7 +35,7 @@ function customize($_action, $_item, $_data = null) {
                 );
                 );
                 return false;
                 return false;
               }
               }
-              $image = new Imagick($_data['main_logo']['tmp_name']);
+              $image = new Imagick($_data[$_item]['tmp_name']);
               if ($image->valid() !== true) {
               if ($image->valid() !== true) {
                 $_SESSION['return'][] = array(
                 $_SESSION['return'][] = array(
                   'type' => 'danger',
                   'type' => 'danger',
@@ -63,7 +64,7 @@ function customize($_action, $_item, $_data = null) {
             return false;
             return false;
           }
           }
           try {
           try {
-            $redis->Set('MAIN_LOGO', 'data:' . $_data['main_logo']['type'] . ';base64,' . base64_encode(file_get_contents($_data['main_logo']['tmp_name'])));
+            $redis->Set(strtoupper($_item), 'data:' . $_data[$_item]['type'] . ';base64,' . base64_encode(file_get_contents($_data[$_item]['tmp_name'])));
           }
           }
           catch (RedisException $e) {
           catch (RedisException $e) {
             $_SESSION['return'][] = array(
             $_SESSION['return'][] = array(
@@ -201,8 +202,9 @@ function customize($_action, $_item, $_data = null) {
       }
       }
       switch ($_item) {
       switch ($_item) {
         case 'main_logo':
         case 'main_logo':
+        case 'main_logo_dark':
           try {
           try {
-            if ($redis->del('MAIN_LOGO')) {
+            if ($redis->del(strtoupper($_item))) {
               $_SESSION['return'][] = array(
               $_SESSION['return'][] = array(
                 'type' => 'success',
                 'type' => 'success',
                 'log' => array(__FUNCTION__, $_action, $_item, $_data),
                 'log' => array(__FUNCTION__, $_action, $_item, $_data),
@@ -239,8 +241,9 @@ function customize($_action, $_item, $_data = null) {
           return ($app_links) ? $app_links : false;
           return ($app_links) ? $app_links : false;
         break;
         break;
         case 'main_logo':
         case 'main_logo':
+        case 'main_logo_dark':
           try {
           try {
-            return $redis->get('MAIN_LOGO');
+            return $redis->get(strtoupper($_item));
           }
           }
           catch (RedisException $e) {
           catch (RedisException $e) {
             $_SESSION['return'][] = array(
             $_SESSION['return'][] = array(
@@ -277,9 +280,14 @@ function customize($_action, $_item, $_data = null) {
           }
           }
         break;
         break;
         case 'main_logo_specs':
         case 'main_logo_specs':
+        case 'main_logo_dark_specs':
           try {
           try {
             $image = new Imagick();
             $image = new Imagick();
-            $img_data = explode('base64,', customize('get', 'main_logo'));
+            if($_item == 'main_logo_specs') {
+              $img_data = explode('base64,', customize('get', 'main_logo'));
+            } else {
+              $img_data = explode('base64,', customize('get', 'main_logo_dark'));
+            }
             if ($img_data[1]) {
             if ($img_data[1]) {
               $image->readImageBlob(base64_decode($img_data[1]));
               $image->readImageBlob(base64_decode($img_data[1]));
               return $image->identifyImage();
               return $image->identifyImage();

+ 1 - 0
data/web/inc/header.inc.php

@@ -40,6 +40,7 @@ $globalVariables = [
   'ui_texts' => $UI_TEXTS,
   'ui_texts' => $UI_TEXTS,
   'css_path' => '/cache/'.basename($CSSPath),
   'css_path' => '/cache/'.basename($CSSPath),
   'logo' => customize('get', 'main_logo'),
   'logo' => customize('get', 'main_logo'),
+  'logo_dark' => customize('get', 'main_logo_dark'),
   'available_languages' => $AVAILABLE_LANGUAGES,
   'available_languages' => $AVAILABLE_LANGUAGES,
   'lang' => $lang,
   'lang' => $lang,
   'skip_sogo' => (getenv('SKIP_SOGO') == 'y'),
   'skip_sogo' => (getenv('SKIP_SOGO') == 'y'),

+ 4 - 0
data/web/inc/triggers.inc.php

@@ -120,10 +120,14 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admi
 	if (isset($_POST["submit_main_logo"])) {
 	if (isset($_POST["submit_main_logo"])) {
     if ($_FILES['main_logo']['error'] == 0) {
     if ($_FILES['main_logo']['error'] == 0) {
       customize('add', 'main_logo', $_FILES);
       customize('add', 'main_logo', $_FILES);
+    }
+    if ($_FILES['main_logo_dark']['error'] == 0) {
+      customize('add', 'main_logo_dark', $_FILES);
     }
     }
 	}
 	}
 	if (isset($_POST["reset_main_logo"])) {
 	if (isset($_POST["reset_main_logo"])) {
     customize('delete', 'main_logo');
     customize('delete', 'main_logo');
+    customize('delete', 'main_logo_dark');
 	}
 	}
   // Some actions will not be available via API
   // Some actions will not be available via API
 	if (isset($_POST["license_validate_now"])) {
 	if (isset($_POST["license_validate_now"])) {

+ 9 - 0
data/web/js/build/013-mailcow.js

@@ -314,19 +314,28 @@ $(document).ready(function() {
   $('#dark-mode-toggle').click(toggleDarkMode);
   $('#dark-mode-toggle').click(toggleDarkMode);
   if ($('#dark-mode-theme').length) {
   if ($('#dark-mode-theme').length) {
     $('#dark-mode-toggle').prop('checked', true);
     $('#dark-mode-toggle').prop('checked', true);
+    $('.main-logo').addClass('d-none');
+    $('.main-logo-dark').removeClass('d-none');
     if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_light.png');
     if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_light.png');
     if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_light.png');
     if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_light.png');
+  } else {
+    $('.main-logo').removeClass('d-none');
+    $('.main-logo-dark').addClass('d-none');
   }
   }
   function toggleDarkMode(){
   function toggleDarkMode(){
     if($('#dark-mode-theme').length){
     if($('#dark-mode-theme').length){
       $('#dark-mode-theme').remove();
       $('#dark-mode-theme').remove();
       $('#dark-mode-toggle').prop('checked', false);
       $('#dark-mode-toggle').prop('checked', false);
+      $('.main-logo').removeClass('d-none');
+      $('.main-logo-dark').addClass('d-none');
       if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_dark.png');
       if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_dark.png');
       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('theme', 'light');
       localStorage.setItem('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="/css/themes/mailcow-darkmode.css">');
       $('#dark-mode-toggle').prop('checked', true);
       $('#dark-mode-toggle').prop('checked', true);
+      $('.main-logo').addClass('d-none');
+      $('.main-logo-dark').removeClass('d-none');
       if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_light.png');
       if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_light.png');
       if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_light.png');
       if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_light.png');
       localStorage.setItem('theme', 'dark');
       localStorage.setItem('theme', 'dark');

+ 2 - 0
data/web/lang/lang.en-gb.json

@@ -149,6 +149,8 @@
         "ays": "Are you sure you want to proceed?",
         "ays": "Are you sure you want to proceed?",
         "ban_list_info": "See a list of banned IPs below: <b>network (remaining ban time) - [actions]</b>.<br />IPs queued to be unbanned will be removed from the active ban list within a few seconds.<br />Red labels indicate active permanent bans by blacklisting.",
         "ban_list_info": "See a list of banned IPs below: <b>network (remaining ban time) - [actions]</b>.<br />IPs queued to be unbanned will be removed from the active ban list within a few seconds.<br />Red labels indicate active permanent bans by blacklisting.",
         "change_logo": "Change logo",
         "change_logo": "Change logo",
+        "logo_normal_label": "Normal",
+        "logo_dark_label": "Inverted for dark mode",
         "configuration": "Configuration",
         "configuration": "Configuration",
         "convert_html_to_text": "Convert HTML to plain text",
         "convert_html_to_text": "Convert HTML to plain text",
         "cors_settings": "CORS Settings",
         "cors_settings": "CORS Settings",

+ 9 - 0
data/web/templates/admin/customize/logo.twig

@@ -0,0 +1,9 @@
+<div class="thumbnail mb-4">
+  <img class="img-thumbnail mb-4{% if dark %} bg-black{% endif %}" src="{{ logo }}" alt="mailcow logo">
+  <div class="caption">
+    <span class="badge fs-5 bg-info">{{ logo_specs.geometry.width }}x{{ logo_specs.geometry.height }} px</span>
+    <span class="badge fs-5 bg-info">{{ logo_specs.mimetype }}</span>
+    <span class="badge fs-5 bg-info">{{ logo_specs.fileSize }}</span>
+  </div>
+</div>
+

+ 18 - 14
data/web/templates/admin/tab-config-customize.twig

@@ -10,22 +10,26 @@
       <legend><i class="bi bi-file-image"></i> {{ lang.admin.change_logo }}</legend><hr />
       <legend><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">
-        <p>
-          <input class="mb-4" type="file" name="main_logo" accept="image/gif, image/jpeg, image/pjpeg, image/x-png, image/png, image/svg+xml"><br>
-          <button name="submit_main_logo" type="submit" class="btn btn-sm d-block d-sm-inline btn-secondary"><i class="bi bi-upload"></i> {{ lang.admin.upload }}</button>
-        </p>
+        <div class="mb-4">
+          <label for="main_logo_input" class="form-label">{{ lang.admin.logo_normal_label }}</label>
+          <input class="form-control" id="main_logo_input" type="file" name="main_logo" accept="image/gif, image/jpeg, image/pjpeg, image/x-png, image/png, image/svg+xml">
+        </div>
+        <div class="mb-4">
+          <label for="main_logo_dark_input" class="form-label">{{ lang.admin.logo_dark_label }}</label>
+          <input class="form-control" id="main_logo_dark_input" type="file" name="main_logo_dark" accept="image/gif, image/jpeg, image/pjpeg, image/x-png, image/png, image/svg+xml">
+        </div>
+
+        <button name="submit_main_logo" type="submit" class="btn btn-sm d-block d-sm-inline btn-secondary"><i class="bi bi-upload"></i> {{ lang.admin.upload }}</button>
       </form>
       </form>
-      {% if logo %}
-        <div class="row">
+      {% if logo or logo_dark %}
+        <div class="row mt-4">
           <div class="col-sm-4">
           <div class="col-sm-4">
-            <div class="thumbnail">
-              <img class="img-thumbnail" src="{{ logo }}" alt="mailcow logo">
-              <div class="caption">
-                <span class="badge fs-5 bg-info">{{ logo_specs.geometry.width }}x{{ logo_specs.geometry.height }} px</span>
-                <span class="badge fs-5 bg-info">{{ logo_specs.mimetype }}</span>
-                <span class="badge fs-5 bg-info">{{ logo_specs.fileSize }}</span>
-              </div>
-            </div>
+            {% if logo %}
+              {% include 'admin/customize/logo.twig' %}
+            {% endif %}
+            {% if logo_dark %}
+              {% include 'admin/customize/logo.twig' with {'logo': logo_dark, 'logo_specs': logo_dark_specs, 'dark': 1} %}
+            {% endif %}
             <hr>
             <hr>
             <form class="form-inline" role="form" method="post">
             <form class="form-inline" role="form" method="post">
               <p><button name="reset_main_logo" type="submit" class="btn btn-sm d-block d-sm-inline btn-secondary">{{ lang.admin.reset_default }}</button></p>
               <p><button name="reset_main_logo" type="submit" class="btn btn-sm d-block d-sm-inline btn-secondary">{{ lang.admin.reset_default }}</button></p>

+ 4 - 1
data/web/templates/base.twig

@@ -31,7 +31,10 @@
 {% block navbar %}
 {% block navbar %}
 <nav class="navbar navbar-expand-lg navbar-light bg-light navbar-fixed-top p-0">
 <nav class="navbar navbar-expand-lg navbar-light bg-light navbar-fixed-top p-0">
   <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 class="main-logo" alt="mailcow-logo" src="{{ logo|default('/img/cow_mailcow.svg') }}">
+      <img class="main-logo-dark" alt="mailcow-logo-dark" src="{{ logo_dark|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">
       <i class="bi bi-list fs-3"></i>
       <i class="bi bi-list fs-3"></i>
     </button>
     </button>

+ 2 - 1
data/web/templates/debug.twig

@@ -37,7 +37,8 @@
           <div class="card-body">
           <div class="card-body">
             <div class="row">
             <div class="row">
               <div class="col-sm-12 col-md-4 d-flex flex-column">
               <div class="col-sm-12 col-md-4 d-flex flex-column">
-                <img class="img-responsive my-auto m-auto" alt="mailcow-logo" style="max-width: 85%; max-height: 85%;" src="{{ logo|default('/img/cow_mailcow.svg') }}">
+                <img class="main-logo img-responsive my-auto m-auto" alt="mailcow-logo" style="max-width: 85%; max-height: 85%;" src="{{ logo|default('/img/cow_mailcow.svg') }}">
+                <img class="main-logo-dark img-responsive my-auto m-auto" alt="mailcow-logo-dark" style="max-width: 85%; max-height: 85%;" src="{{ logo_dark|default('/img/cow_mailcow.svg') }}">
               </div>
               </div>
               <div class="col-sm-12 col-md-8">
               <div class="col-sm-12 col-md-8">
                 <div class="table-responsive" style="margin-top: 10px;">
                 <div class="table-responsive" style="margin-top: 10px;">

+ 4 - 1
data/web/templates/index.twig

@@ -14,7 +14,10 @@
         </div>
         </div>
       </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 class="main-logo" src="{{ logo|default('/img/cow_mailcow.svg') }}" alt="mailcow">
+          <img class="main-logo-dark" src="{{ logo_dark|default('/img/cow_mailcow.svg') }}" alt="mailcow-logo-dark">
+        </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 %}
         <div class="my-4 alert alert-{{ ui_texts.ui_announcement_type }} rot-enc ui-announcement-alert">{{ ui_texts.ui_announcement_text|rot13 }}</div>
         <div class="my-4 alert alert-{{ ui_texts.ui_announcement_type }} rot-enc ui-announcement-alert">{{ ui_texts.ui_announcement_text|rot13 }}</div>
         {% endif %}
         {% endif %}