feat(darkmode): dark mode toggle (#82)

* feat(darkmode): initial support for dark mode toggle

* fix(darkmode): add svg icons

* feat(darkmode): dispatch onColorSchemeChange event

* add head/darkmode

* feat(darkmode); add colorScheme config

* style: remove empty line

* refactor(darkmode): simplify code

* style: add comment for darkmode config

* i18n support for dark mode toggle

* Some renaming
This commit is contained in:
Jimmy Cai
2020-12-23 19:03:40 +01:00
committed by GitHub
parent df74fe5f19
commit 358e63e799
17 changed files with 209 additions and 20 deletions
+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-toggle-left" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z"/>
<circle cx="8" cy="12" r="2" />
<rect x="2" y="6" width="20" height="12" rx="6" />
</svg>

After

Width:  |  Height:  |  Size: 369 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-toggle-right" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z"/>
<circle cx="16" cy="12" r="2" />
<rect x="2" y="6" width="20" height="12" rx="6" />
</svg>

After

Width:  |  Height:  |  Size: 371 B

@@ -3,11 +3,6 @@
* https://xyproto.github.io/splash/docs/monokai.html
*/
:root {
--pre-text-color: #f8f8f2;
--pre-background-color: #272822;
}
/* Background */
.chroma {
color: #f8f8f2;
@@ -2,10 +2,6 @@
* Style: monokailight
* https://xyproto.github.io/splash/docs/monokailight.html
*/
:root {
--pre-text-color: #272822;
--pre-background-color: #fafafa;
}
/* Background */
.chroma {
+2 -1
View File
@@ -129,6 +129,8 @@
margin-top: var(--sidebar-element-separation);
margin-bottom: 0;
overflow-y: auto;
flex-grow: 1;
font-size: 1.5rem;
@media (min-width: $on-desktop-large) {
margin-top: 30px;
@@ -192,7 +194,6 @@
display: inline-flex;
align-items: center;
color: var(--body-text-color);
font-size: 1.5rem;
@media (max-width: $on-desktop-large) {
font-size: 1.4rem;
+27
View File
@@ -134,3 +134,30 @@
}
}
}
[data-scheme="dark"] {
#dark-mode-toggle {
color: var(--accent-color);
font-weight: 700;
.icon-tabler-toggle-left {
display: none;
}
.icon-tabler-toggle-right {
display: unset;
}
}
}
#dark-mode-toggle {
margin-top: auto;
color: var(--body-text-color);
display: flex;
align-items: center;
cursor: pointer;
.icon-tabler-toggle-right {
display: none;
}
}
+15 -4
View File
@@ -1,6 +1,18 @@
$defaultTagBackgrounds: #8ea885, #df7988, #0177b8, #ffb900, #6b69d6;
$defaultTagColors: #fff, #fff, #fff, #fff, #fff;
[data-scheme="light"] {
--pre-text-color: #272822;
--pre-background-color: #fafafa;
@import "partials/highlight/light.scss";
}
[data-scheme="dark"] {
--pre-text-color: #f8f8f2;
--pre-background-color: #272822;
@import "partials/highlight/dark.scss";
}
/*
* Global style
*/
@@ -13,7 +25,6 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff;
--main-top-padding: 50px;
}
--body-background: #f5f5fa;
--accent-color: #34495e;
@@ -25,7 +36,7 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff;
--section-separation: 40px;
@media (prefers-color-scheme: dark) {
[data-scheme="dark"] {
--body-background: #303030;
--accent-color: #ecf0f1;
--accent-color-darker: #bdc3c7;
@@ -72,7 +83,7 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff;
--small-card-padding: 25px 20px;
}
@media (prefers-color-scheme: dark) {
[data-scheme="dark"] {
--card-background: #424242;
--card-background-selected: rgba(255, 255, 255, 0.16);
--card-text-color-main: rgba(255, 255, 255, 0.9);
@@ -116,7 +127,7 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff;
--table-border-color: #dadada;
--tr-even-background-color: #efefee;
@media (prefers-color-scheme: dark) {
[data-scheme="dark"] {
--code-background-color: #272822;
--code-text-color: rgba(255, 255, 255, 0.9);
+86
View File
@@ -0,0 +1,86 @@
type colorScheme = 'light' | 'dark' | 'auto';
class StackColorScheme {
private localStorageKey = 'StackColorScheme';
private currentScheme: colorScheme;
private systemPreferScheme: colorScheme;
constructor(toggleEl: HTMLElement) {
this.bindMatchMedia();
this.currentScheme = this.getSavedScheme();
if (toggleEl)
this.bindClick(toggleEl);
if (document.body.style.transition == '')
document.body.style.setProperty('transition', 'background-color .3s ease');
}
private saveScheme() {
localStorage.setItem(this.localStorageKey, this.currentScheme);
}
private bindClick(toggleEl) {
toggleEl.addEventListener('click', (e) => {
if (this.isDark()) {
/// Disable dark mode
this.currentScheme = 'light';
}
else {
this.currentScheme = 'dark';
}
this.setBodyClass();
if (this.currentScheme == this.systemPreferScheme) {
/// Set to auto
this.currentScheme = 'auto';
}
this.saveScheme();
})
}
private isDark() {
return (this.currentScheme == 'dark' || this.currentScheme == 'auto' && this.systemPreferScheme == 'dark');
}
private dispatchEvent(colorScheme: colorScheme) {
const event = new CustomEvent('onColorSchemeChange', {
detail: colorScheme
});
window.dispatchEvent(event);
}
private setBodyClass() {
if (this.isDark()) {
document.body.dataset.scheme = 'dark';
}
else {
document.body.dataset.scheme = 'light';
}
this.dispatchEvent(document.body.dataset.scheme as colorScheme);
}
private getSavedScheme(): colorScheme {
const savedScheme = localStorage.getItem(this.localStorageKey);
if (savedScheme == 'light' || savedScheme == 'dark' || savedScheme == 'auto') return savedScheme;
else return 'auto';
}
private bindMatchMedia() {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
if (e.matches) {
this.systemPreferScheme = 'dark';
}
else {
this.systemPreferScheme = 'light';
}
this.setBodyClass();
});
}
}
export default StackColorScheme;
+3
View File
@@ -9,6 +9,7 @@ import StackGallery from "ts/gallery";
import { getColor } from 'ts/color';
import menu from 'ts/menu';
import createElement from 'ts/createElement';
import StackColorScheme from 'ts/colorScheme';
let Stack = {
init: () => {
@@ -52,6 +53,8 @@ let Stack = {
observer.observe(articleTile)
}
new StackColorScheme(document.getElementById('dark-mode-toggle'));
}
}