Introduce dark/light mode theme switch into framework

This commit is contained in:
Hadi Nategh 2020-12-15 20:24:25 +01:00
parent 7011faba18
commit f21ac58c87
13 changed files with 143 additions and 2 deletions

View File

@ -63,6 +63,9 @@ var fw_base = (function(){ "use strict"; return Class.extend(
// keep track of opened popups
this.popups = [];
// initiate dark mode
this._setDarkMode(egw.preference('darkmode', 'common'));
},
/**
@ -1299,5 +1302,10 @@ var fw_base = (function(){ "use strict"; return Class.extend(
isAnInternalApp: function(_app)
{
return _app && _app.appName != _app.internalName;
},
_setDarkMode: function(_state)
{
jQuery('html').attr('data-darkmode', _state);
}
});}).call(this);

View File

@ -535,6 +535,27 @@
execPushBroadcastAppStatus: function(_data)
{
if (app.status) app.status.mergeContent(_data, true);
},
/**
*
* @param node
*/
toggle_darkmode: function(node)
{
let state = node.firstElementChild.classList.contains('darkmode_on');
egw.set_preference('common', 'darkmode',state?'0':'1');
this._setDarkMode(state?'0':'1');
if (state == 1)
{
node.firstElementChild.classList.remove('darkmode_on');
node.firstElementChild.title = egw.lang('light mode');
}
else
{
node.firstElementChild.classList.add('darkmode_on');
node.firstElementChild.title = egw.lang('dark mode');
}
}
});
})(window);

View File

@ -117,6 +117,8 @@ var EgwApp = /** @class */ (function () {
this._set_Window_title();
// Highlights the favorite based on initial list state
this.highlight_favorite();
// apply theme mode
jQuery('html').attr('data-darkmode', egw.preference('darkmode', 'common'));
};
/**
* Observer method receives update notifications from all applications

View File

@ -207,6 +207,8 @@ export abstract class EgwApp
// Highlights the favorite based on initial list state
this.highlight_favorite();
// apply theme mode
jQuery('html').attr('data-darkmode', <string> egw.preference('darkmode', 'common'));
}
/**

View File

@ -534,6 +534,7 @@ abstract class Framework extends Framework\Extra
'dir_code' => lang('language_direction_rtl') != 'rtl' ? '' : ' dir="rtl"',
'include_wz_tooltip'=> $include_wz_tooltip,
'webserver_url' => $GLOBALS['egw_info']['server']['webserver_url'],
'darkmode' => $GLOBALS['egw_info']['user']['preferences']['common']['darkmode']
);
}
@ -670,6 +671,17 @@ abstract class Framework extends Framework\Extra
return '<span title="'.lang("Print current view").'"</span>';
}
/**
* Returns darkmode menu
*
* @return string
*/
protected static function _darkmode_menu()
{
$mode = $GLOBALS['egw_info']['user']['preferences']['common']['darkmode'] == 1?'dark':'light';
return '<span title="'.lang("%1 mode", $mode).'" class="'.
($mode == 'dark'?'darkmode_on':'').'"> </span>';
}
/**
* Prepare the current users
@ -1177,7 +1189,8 @@ abstract class Framework extends Framework\Extra
'update' => ($update = Framework\Updates::notification()) ? $update : null,
'notifications' => ($GLOBALS['egw_info']['user']['apps']['notifications']) ? self::_get_notification_bell() : null,
'quick_add' => $vars['quick_add'],
'print_title' => $this->_print_menu()
'print_title' => $this->_print_menu(),
'darkmode' => self::_darkmode_menu()
];
// array of topmenu items (orders of the items matter)

View File

@ -43,6 +43,18 @@
* Stefan Reinhardt
*/
/*@import (less) "../../api/templates/default/etemplate2.css";*/
/**
* DARK THEME
*/
@media all {
html[data-darkmode='1'] {
background: #000;
filter: invert(1) hue-rotate(180deg);
}
html[data-darkmode='1'] img {
filter: invert(1) hue-rotate(180deg);
}
}
@media all {
/**
* Top level

View File

@ -1,5 +1,5 @@
<!-- BEGIN head --><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xml:lang="{lang_code}" xmlns="http://www.w3.org/1999/xhtml"{dir_code}>
<html xml:lang="{lang_code}" xmlns="http://www.w3.org/1999/xhtml"{dir_code} data-darkmode={darkmode}>
<head>
<title>{website_title}</title>
<meta http-equiv="content-type" content="text/html; charset={charset}" />

View File

@ -0,0 +1,24 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#62686A"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle fill="#FFF49C" cx="12" cy="12" r="5"/>
<g stroke="#62686A">
<line x1="12" y1="1" x2="12" y2="3" />
<line x1="12" y1="21" x2="12" y2="23" />
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
<line x1="1" y1="12" x2="3" y2="12" />
<line x1="21" y1="12" x2="23" y2="12" />
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 659 B

View File

@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#62686A"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<mask id="mask" >
<rect x="0" y="0" width="100%" height="100%" fill="white" />
<circle cx="5" cy="16" r="9" fill="black" />
</mask>
<circle fill="#FFF49C" cx="12" cy="12" r="9" mask="url(#mask)" />
</svg>

After

Width:  |  Height:  |  Size: 408 B

View File

@ -124,6 +124,7 @@
window.framework = new fw_pixelegg("egw_fw_sidemenu", "egw_fw_tabs",
window.egw_webserverUrl, egw_setSideboxSize,"egw_fw_splitter", 255, 245); // should be identical to jdots_framework::(DEFAULT|MIN)_SIDEBAR_WIDTH
window.callManual = window.framework.callManual;
jQuery('#topmenu_info_darkmode').click(function(){window.framework.toggle_darkmode(this);});
jQuery('#topmenu_info_user_avatar').click(function(){window.framework.toggle_avatar_menu();});
jQuery('#topmenu_info_print_title').click(function(){window.framework.print();});
jQuery('#topmenu_info_logout').click(function(){ window.framework.redirect(this.getAttribute('data-logout-url')); });

View File

@ -10,9 +10,24 @@
@import (reference) "./def_buttons.less";
/*@import (less) "../../api/templates/default/etemplate2.css";*/
/**
* DARK THEME
*/
@media all {
html[data-darkmode='1'] {
background: #000;
filter: invert(1) hue-rotate(180deg)
}
html[data-darkmode='1'] img {
filter: invert(1) hue-rotate(180deg)
}
}
@media all {
/**
* Top level
*/

View File

@ -108,6 +108,23 @@
display: inline-block;
}
}
/*darkmode*/
#topmenu_info_darkmode {
span {
background-image: url(../images/darkmode_off.svg);
width: 45px;
height: 45px;
display: inline-block;
background-position: center;
background-repeat: no-repeat;
}
span.darkmode_on {
background-image: url(../images/darkmode_on.svg);
filter:invert(1) hue-rotate(180deg);
}
}
/*Notification*/
#topmenu_info_notifications {
line-height: 45px;

View File

@ -178,6 +178,15 @@ class preferences_hooks
'admin' => False,
'forced' => file_exists(EGW_SERVER_ROOT.'/pixelegg') ? 'pixelegg' : 'idots',
),
'darkmode' => array(
'type' => 'select',
'label' => 'Dark mode theme',
'name' => 'darkmode',
'values' => array('0' => 'off', '1' => 'on'),
'help' => 'Dark mode theme',
'admin' => False,
'default' => '0'
),
'audio_effect'=> array(
'type' => 'select',
'label' => 'Audio effect',