mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 06:30:59 +01:00
Kdots dark mode
This commit is contained in:
parent
844eed2eee
commit
c06b1aafda
@ -1229,11 +1229,11 @@ abstract class Framework extends Framework\Extra
|
||||
$topmenu_info_items = [
|
||||
'user_avatar' => $this->_user_avatar_menu(),
|
||||
'update' => ($update = Framework\Updates::notification()) ? $update : null,
|
||||
'logout' => (Header\UserAgent::mobile()) ? self::_logout_menu() : null,
|
||||
'notifications' => ($GLOBALS['egw_info']['user']['apps']['notifications']) ? self::_get_notification_bell() : null,
|
||||
'logout' => (Header\UserAgent::mobile()) ? static::_logout_menu() : null,
|
||||
'notifications' => ($GLOBALS['egw_info']['user']['apps']['notifications']) ? static::_get_notification_bell() : null,
|
||||
'quick_add' => $vars['quick_add'],
|
||||
'print_title' => $this->_print_menu(),
|
||||
'darkmode' => self::_darkmode_menu()
|
||||
'darkmode' => static::_darkmode_menu()
|
||||
];
|
||||
|
||||
// array of topmenu items (orders of the items matter)
|
||||
|
@ -1,3 +1,29 @@
|
||||
/**
|
||||
* kDots main styles
|
||||
*
|
||||
* Note that light / dark colors should go in framework_light.less & framework_dark.less
|
||||
*/
|
||||
/** Theme customisations **/
|
||||
html[data-darkmode="true"] body {
|
||||
background-color: black;
|
||||
color: var(--sl-color-neutral-700);
|
||||
/*** HEADER ***/
|
||||
/*** APPLICATION ***/
|
||||
/*** End APPLICATION ***/
|
||||
/*** WIDGETS ***/
|
||||
/* This should mostly go away with webcomponents */
|
||||
/** End WIDGETS **/
|
||||
}
|
||||
html[data-darkmode="true"] body #egw_fw_topmenu_info_items #topmenu_info_timer:before {
|
||||
filter: initial;
|
||||
}
|
||||
html[data-darkmode="true"] body egw-app {
|
||||
--application-header-text-color: var(--sl-color-neutral-700);
|
||||
}
|
||||
html[data-darkmode="true"] body .nextmatch_sortheader {
|
||||
color: #96bcd9;
|
||||
}
|
||||
/** End theme customisations **/
|
||||
html,
|
||||
body {
|
||||
width: 100vw;
|
||||
@ -118,6 +144,7 @@ egw-framework#egw_fw_basecontainer .egw_fw_ui_sidemenu_entry_header {
|
||||
#egw_fw_topmenu_info_items #topmenu_info_timer #topmenu_timer {
|
||||
display: block;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
#egw_fw_topmenu_info_items #topmenu_info_timer:hover {
|
||||
cursor: pointer;
|
||||
|
@ -1,3 +1,14 @@
|
||||
/**
|
||||
* kDots main styles
|
||||
*
|
||||
* Note that light / dark colors should go in framework_light.less & framework_dark.less
|
||||
*/
|
||||
|
||||
|
||||
/** Theme customisations **/
|
||||
@import "./framework_dark.less";
|
||||
/** End theme customisations **/
|
||||
|
||||
html, body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
@ -6,7 +17,6 @@ html, body {
|
||||
margin: 0px;
|
||||
|
||||
/** Messages **/
|
||||
|
||||
.sl-toast-stack {
|
||||
top: auto;
|
||||
bottom: 0px;
|
||||
@ -140,6 +150,7 @@ egw-framework#egw_fw_basecontainer {
|
||||
#topmenu_timer {
|
||||
display: block;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@ -397,5 +408,4 @@ div.et2_nextmatch {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*** END WIDGETS ***/
|
28
kdots/assets/styles/framework_dark.less
Normal file
28
kdots/assets/styles/framework_dark.less
Normal file
@ -0,0 +1,28 @@
|
||||
html[data-darkmode="true"] body {
|
||||
background-color: black;
|
||||
color: var(--sl-color-neutral-700);
|
||||
|
||||
/*** HEADER ***/
|
||||
#egw_fw_topmenu_info_items {
|
||||
#topmenu_info_timer:before {
|
||||
filter:initial;
|
||||
}
|
||||
}
|
||||
|
||||
/*** APPLICATION ***/
|
||||
|
||||
egw-app {
|
||||
--application-header-text-color: var(--sl-color-neutral-700);
|
||||
}
|
||||
|
||||
/*** End APPLICATION ***/
|
||||
|
||||
/*** WIDGETS ***/
|
||||
/* This should mostly go away with webcomponents */
|
||||
|
||||
.nextmatch_sortheader {
|
||||
color: #96bcd9;
|
||||
}
|
||||
|
||||
/** End WIDGETS **/
|
||||
}
|
@ -34,7 +34,7 @@
|
||||
{include_wz_tooltip}
|
||||
<!-- END head -->
|
||||
<!-- BEGIN framework -->
|
||||
<egw-framework id="egw_fw_basecontainer" class="sl-theme-light "
|
||||
<egw-framework id="egw_fw_basecontainer" class=" "
|
||||
application-list="{application-list}"
|
||||
>
|
||||
<a slot="logo" href="{logo_url}" target="_blank"><img src="{logo_header}" title="{logo_title}" alt="Site logo"/></a>
|
||||
|
@ -76,6 +76,9 @@ class kdots_framework extends Api\Framework\Ajax
|
||||
case 'user_avatar':
|
||||
$vars['topmenu_info_items'] .= "<sl-dropdown class=\"topmenu_info_item\" id=\"topmenu_info_{$id}\" aria-label='" . lang("User menu") . "' tabindex='0'><div slot='trigger'>$item</div> {$vars['topmenu_items']}</sl-dropdown>";
|
||||
break;
|
||||
case 'darkmode':
|
||||
$vars['topmenu_info_items'] .= $item;
|
||||
break;
|
||||
default:
|
||||
$vars['topmenu_info_items'] .= '<button class="topmenu_info_item"' .
|
||||
(is_numeric($id) ? '' : ' id="topmenu_info_' . $id . '"') . '>' . $item . "</button>\n";
|
||||
@ -174,4 +177,17 @@ class kdots_framework extends Api\Framework\Ajax
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns darkmode menu
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function _darkmode_menu()
|
||||
{
|
||||
$mode = $GLOBALS['egw_info']['user']['preferences']['common']['darkmode'] == 1 ? 'dark' : 'light';
|
||||
return '<egw-darkmode-toggle title="' . lang("%1 mode", $mode) . '" class="' .
|
||||
($mode == 'dark' ? 'darkmode_on' : '') . '"' . ($mode == 'dark' ? 'darkmode' : '') . '> </egw-darkmode-toggle>';
|
||||
}
|
||||
}
|
||||
|
94
kdots/js/EgwDarkmodeToggle.ts
Normal file
94
kdots/js/EgwDarkmodeToggle.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import {css, html, LitElement} from "lit";
|
||||
import {customElement} from "lit/decorators/custom-element.js";
|
||||
import {property} from "lit/decorators/property.js";
|
||||
|
||||
/**
|
||||
* @summary System message
|
||||
*
|
||||
* @dependency sl-alert
|
||||
* @dependency sl-icon
|
||||
*
|
||||
* @slot - Content
|
||||
* @slot icon - An icon to show in the message
|
||||
*
|
||||
* @csspart base - Wraps it all.
|
||||
* @csspart icon -
|
||||
*/
|
||||
@customElement('egw-darkmode-toggle')
|
||||
export class EgwDarkmodeToggle extends LitElement
|
||||
{
|
||||
static get styles()
|
||||
{
|
||||
return [
|
||||
css`
|
||||
sl-icon-button::part(base) {
|
||||
padding: 0;
|
||||
}
|
||||
`
|
||||
];
|
||||
}
|
||||
|
||||
@property({type: Boolean})
|
||||
darkmode = false;
|
||||
|
||||
private _initialValue = false;
|
||||
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
this._initialValue = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
this.handleDarkmodeChange = this.handleDarkmodeChange.bind(this);
|
||||
}
|
||||
|
||||
connectedCallback()
|
||||
{
|
||||
super.connectedCallback();
|
||||
this.toggleDarkmode(this.hasAttribute("darkmode") ? this.darkmode : this._initialValue);
|
||||
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", this.handleDarkmodeChange);
|
||||
}
|
||||
|
||||
disconnectedCallback()
|
||||
{
|
||||
super.disconnectedCallback();
|
||||
window.matchMedia("(prefers-color-scheme: dark)").removeEventListener("change", this.handleDarkmodeChange);
|
||||
}
|
||||
|
||||
public toggleDarkmode(force = null)
|
||||
{
|
||||
if(force == null)
|
||||
{
|
||||
force = !(document.documentElement.getAttribute("data-darkmode") == "true");
|
||||
}
|
||||
this.darkmode = force;
|
||||
if(force)
|
||||
{
|
||||
document.documentElement.setAttribute("data-darkmode", "true");
|
||||
}
|
||||
else
|
||||
{
|
||||
document.documentElement.setAttribute("data-darkmode", "0");
|
||||
}
|
||||
// Set class for Shoelace
|
||||
document.documentElement.classList.toggle("sl-theme-dark", this.darkmode);
|
||||
this.requestUpdate("darkmode")
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this.dispatchEvent(new CustomEvent("egw-darkmode-change", {bubbles: true}));
|
||||
});
|
||||
}
|
||||
|
||||
handleDarkmodeChange(e)
|
||||
{
|
||||
this.toggleDarkmode(e.matches ? "dark" : "light");
|
||||
}
|
||||
|
||||
render() : unknown
|
||||
{
|
||||
return html`
|
||||
<sl-icon-button name="${this.darkmode ? "sun" : "moon"}"
|
||||
@click=${(e) => {this.toggleDarkmode()}}
|
||||
></sl-icon-button>
|
||||
`;
|
||||
}
|
||||
|
||||
}
|
@ -111,6 +111,11 @@ export class EgwFramework extends LitElement
|
||||
|
||||
private get tabs() : SlTabGroup { return this.shadowRoot.querySelector("sl-tab-group");}
|
||||
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
this.handleDarkmodeChange = this.handleDarkmodeChange.bind(this);
|
||||
}
|
||||
connectedCallback()
|
||||
{
|
||||
super.connectedCallback();
|
||||
@ -124,6 +129,15 @@ export class EgwFramework extends LitElement
|
||||
// Override framework setSidebox, use arrow function to force context
|
||||
this.egw.framework.setSidebox = (applicationName, sideboxData, hash?) => this.setSidebox(applicationName, sideboxData, hash);
|
||||
}
|
||||
|
||||
document.body.addEventListener("egw-darkmode-change", this.handleDarkmodeChange);
|
||||
}
|
||||
|
||||
disconnectedCallback()
|
||||
{
|
||||
super.disconnectedCallback();
|
||||
|
||||
document.body.removeEventListener("egw-darkmode-change", this.handleDarkmodeChange);
|
||||
}
|
||||
|
||||
protected firstUpdated(_changedProperties : PropertyValues)
|
||||
@ -572,6 +586,15 @@ export class EgwFramework extends LitElement
|
||||
|
||||
protected getBaseUrl() {return "";}
|
||||
|
||||
protected handleDarkmodeChange(event)
|
||||
{
|
||||
// Update CSS classes
|
||||
this.classList.toggle("sl-theme-light", !event.target.darkmode);
|
||||
this.classList.toggle("sl-theme-dark", event.target.darkmode);
|
||||
|
||||
// Update preference
|
||||
this.egw.set_preference("common", "darkmode", (event.target.darkmode ? "1" : "0"));
|
||||
}
|
||||
/**
|
||||
* An application tab is chosen, show the app
|
||||
*
|
||||
|
@ -39,13 +39,13 @@ export default css`
|
||||
max-height: 3em;
|
||||
|
||||
background-color: var(--application-color, --primary-background-color);
|
||||
color: var(--application-header-text-color, white);
|
||||
color: var(--application-header-text-color, var(--sl-color-neutral-0));
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.egw_fw_app__header sl-icon-button::part(base), .egw_fw_app__header et2-button-icon {
|
||||
font-size: inherit;
|
||||
color: var(--application-header-text-color, white);
|
||||
color: var(--application-header-text-color, var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.egw_fw_app__header et2-button-icon {
|
||||
@ -53,7 +53,7 @@ export default css`
|
||||
}
|
||||
|
||||
.egw_fw_app__header sl-icon-button::part(base):hover, .egw_fw_app__header et2-button-icon::part(base):hover {
|
||||
color: var(--application-header-text-color, white);
|
||||
color: var(--application-header-text-color, var(--sl-color-neutral-0));
|
||||
filter: brightness(70%);
|
||||
}
|
||||
|
||||
|
@ -4,11 +4,12 @@
|
||||
|
||||
import {EgwFramework} from "./EgwFramework";
|
||||
import {EgwFrameworkApp} from "./EgwFrameworkApp";
|
||||
import {EgwDarkmodeToggle} from "./EgwDarkmodeToggle";
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () =>
|
||||
{
|
||||
// Not sure what's up here
|
||||
// Not sure what's up here, but it makes sure everything is loaded
|
||||
if(!window.customElements.get("egw-framework"))
|
||||
{
|
||||
window.customElements.define("egw-framework", EgwFramework);
|
||||
@ -17,6 +18,10 @@ document.addEventListener('DOMContentLoaded', () =>
|
||||
{
|
||||
window.customElements.define("egw-app", EgwFrameworkApp);
|
||||
}
|
||||
if(!window.customElements.get("egw-darkmode-toggle"))
|
||||
{
|
||||
window.customElements.define("egw-darkmode-toggle", EgwDarkmodeToggle);
|
||||
}
|
||||
/* Set up listener on avatar menu */
|
||||
const avatarMenu = document.querySelector("#topmenu_info_user_avatar");
|
||||
if(avatarMenu)
|
||||
|
Loading…
Reference in New Issue
Block a user