Started work on supporting a dark-mode

- Most elements done, but still need to do editors, tables and final
pass.
- Toggled only by quick js check at the moment, checking via css media
query. Need to make into user-preference toggle.

For #1234
This commit is contained in:
Dan Brown 2020-04-10 22:38:29 +01:00
parent d4df18098f
commit 1ba5a1274c
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
16 changed files with 149 additions and 56 deletions

View File

@ -191,7 +191,8 @@ function getMode(suggestion, content) {
* @returns {*|string}
*/
function getTheme() {
return window.codeTheme || 'default';
const darkMode = document.documentElement.classList.contains('dark-mode');
return window.codeTheme || (darkMode ? 'darcula' : 'default');
}
/**

View File

@ -58,7 +58,7 @@
*/
.card {
background-color: #FFF;
@include lightDark(background-color, #FFF, #222);
box-shadow: $bs-card;
border-radius: 3px;
border: 1px solid transparent;

View File

@ -22,17 +22,17 @@ button {
box-shadow: none;
background-color: var(--color-primary);
color: #FFF;
fill: #FFF;
text-transform: uppercase;
border: 1px solid var(--color-primary);
vertical-align: top;
@include lightDark(filter, none, saturate(0.8) brightness(0.8));
&:hover, &:focus, &:active {
background-color: var(--color-primary);
text-decoration: none;
color: #FFFFFF;
}
&:hover {
box-shadow: $bs-light;
@include lightDark(box-shadow, $bs-light, $bs-dark);
filter: brightness(110%);
}
&:focus {
@ -48,13 +48,14 @@ button {
.button.outline {
background-color: transparent;
color: #666;
@include lightDark(color, #666, #aaa);
fill: currentColor;
border: 1px solid #CCC;
&:hover, &:focus, &:active {
border: 1px solid #CCC;
box-shadow: none;
background-color: #F2F2F2;
@include lightDark(background-color, #f2f2f2, #555);
filter: none;
}
&:active {

View File

@ -390,6 +390,63 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
/* STOP */
/**
* Codemirror Darcula theme
*/
/**
Name: IntelliJ IDEA darcula theme
From IntelliJ IDEA by JetBrains
*/
.cm-s-darcula { font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif;}
.cm-s-darcula.CodeMirror { background: #2B2B2B; color: #A9B7C6; }
.cm-s-darcula span.cm-meta { color: #BBB529; }
.cm-s-darcula span.cm-number { color: #6897BB; }
.cm-s-darcula span.cm-keyword { color: #CC7832; line-height: 1em; font-weight: bold; }
.cm-s-darcula span.cm-def { color: #A9B7C6; font-style: italic; }
.cm-s-darcula span.cm-variable { color: #A9B7C6; }
.cm-s-darcula span.cm-variable-2 { color: #A9B7C6; }
.cm-s-darcula span.cm-variable-3 { color: #9876AA; }
.cm-s-darcula span.cm-type { color: #AABBCC; font-weight: bold; }
.cm-s-darcula span.cm-property { color: #FFC66D; }
.cm-s-darcula span.cm-operator { color: #A9B7C6; }
.cm-s-darcula span.cm-string { color: #6A8759; }
.cm-s-darcula span.cm-string-2 { color: #6A8759; }
.cm-s-darcula span.cm-comment { color: #61A151; font-style: italic; }
.cm-s-darcula span.cm-link { color: #CC7832; }
.cm-s-darcula span.cm-atom { color: #CC7832; }
.cm-s-darcula span.cm-error { color: #BC3F3C; }
.cm-s-darcula span.cm-tag { color: #629755; font-weight: bold; font-style: italic; text-decoration: underline; }
.cm-s-darcula span.cm-attribute { color: #6897bb; }
.cm-s-darcula span.cm-qualifier { color: #6A8759; }
.cm-s-darcula span.cm-bracket { color: #A9B7C6; }
.cm-s-darcula span.cm-builtin { color: #FF9E59; }
.cm-s-darcula span.cm-special { color: #FF9E59; }
.cm-s-darcula span.cm-matchhighlight { color: #FFFFFF; background-color: rgba(50, 89, 48, .7); font-weight: normal;}
.cm-s-darcula span.cm-searching { color: #FFFFFF; background-color: rgba(61, 115, 59, .7); font-weight: normal;}
.cm-s-darcula .CodeMirror-cursor { border-left: 1px solid #A9B7C6; }
.cm-s-darcula .CodeMirror-activeline-background { background: #323232; }
.cm-s-darcula .CodeMirror-gutters { background: #313335; border-right: 1px solid #313335; }
.cm-s-darcula .CodeMirror-guttermarker { color: #FFEE80; }
.cm-s-darcula .CodeMirror-guttermarker-subtle { color: #D0D0D0; }
.cm-s-darcula .CodeMirrir-linenumber { color: #606366; }
.cm-s-darcula .CodeMirror-matchingbracket { background-color: #3B514D; color: #FFEF28 !important; font-weight: bold; }
.cm-s-darcula div.CodeMirror-selected { background: #214283; }
.CodeMirror-hints.darcula {
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
color: #9C9E9E;
background-color: #3B3E3F !important;
}
.CodeMirror-hints.darcula .CodeMirror-hint-active {
background-color: #494D4E !important;
color: #9C9E9E !important;
}
/**
* Custom BookStack overrides
@ -401,7 +458,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
font-size: 12px;
height: auto;
margin-bottom: $-l;
border: 1px solid #DDD;;
border: 1px solid;
@include lightDark(border-color, #DDD, #111)
}
.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 0; color: #333; }
@ -424,24 +482,25 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
top: -1px;
right: -1px;
background-color: #EEE;
border: 1px solid #DDD;
@include lightDark(background-color, #eee, #333);
@include lightDark(border-color, #ddd, #444);
@include lightDark(fill, #444, #888);
padding: $-xs;
line-height: 0;
border: 1px solid #DDD;
cursor: pointer;
fill: #444;
z-index: 5;
transition: all ease-in 240ms;
user-select: none;
opacity: 0;
pointer-events: none;
svg {
transition: transform ease-in 240ms;
transition: all ease-in 240ms;
transform: translateY(0);
}
&.success {
background-color: lighten($positive, 10%);
fill: #FFF;
svg {
fill: #FFF;
transform: translateY(-3px);
}
}

View File

@ -36,13 +36,13 @@
}
.text-muted {
color: #575757 !important;
fill: #575757 !important;
@include lightDark(color, #575757, #888888, true);
fill: currentColor !important;
}
.text-dark {
color: #222 !important;
fill: #222 !important;
@include lightDark(color, #222, #ccc, true);
fill: currentColor !important;
}
/*

View File

@ -1,12 +1,13 @@
.input-base {
background-color: #FFF;
border-radius: 3px;
border: 1px solid #D4D4D4;
@include lightDark(background-color, #fff, #333);
@include lightDark(border-color, #d4d4d4, #111);
@include lightDark(color, #666, #AAA);
display: inline-block;
font-size: $fs-s;
font-size: $fs-m;
padding: $-xs*1.5;
color: #666;
width: 250px;
max-width: 100%;
@ -139,11 +140,11 @@
label {
@include lightDark(color, #666, #ddd);
display: block;
line-height: 1.4em;
font-size: 0.94em;
font-weight: 400;
color: #666;
padding-bottom: 2px;
margin-bottom: 0.2em;
&.inline {

View File

@ -18,11 +18,14 @@ header {
display: block;
z-index: 11;
top: 0;
color: #fff;
fill: #fff;
color: rgb(250, 250, 250);
border-bottom: 1px solid #DDD;
box-shadow: $bs-card;
padding: $-xxs 0;
@include lightDark(border-bottom-color, #DDD, #000);
@include whenDark {
filter: saturate(0.6) brightness(0.8);
}
.links {
display: inline-block;
vertical-align: top;
@ -31,7 +34,6 @@ header {
display: inline-block;
padding: $-m;
color: #FFF;
fill: #FFF;
}
.dropdown-container {
padding-inline-start: $-m;
@ -94,7 +96,6 @@ header .search-box {
}
}
button {
fill: #EEE;
z-index: 1;
left: 16px;
@include rtl {

View File

@ -15,12 +15,14 @@ html {
&.flexbox {
overflow-y: hidden;
}
&.dark-mode {
background-color: #111;
}
}
body {
font-size: $fs-m;
line-height: 1.6;
color: #444;
@include lightDark(color, #444, #AAA);
-webkit-font-smoothing: antialiased;
background-color: #F2F2F2;
}

View File

@ -99,7 +99,7 @@
left: auto;
right: 0;
}
background-color: rgba(0, 0, 0, 0.2);
@include lightDark(background-color, rgba(0, 0, 0, 0.2), rgba(255, 255, 255, 0.2));
width: 2px;
top: 5px;
bottom: 5px;
@ -132,7 +132,7 @@
font-weight: bold;
}
li:not(.current-heading) .sidebar-page-nav-bullet {
background-color: #BBB !important;
@include lightDark(background-color, #BBB, #666, true);
}
.sidebar-page-nav-bullet {
width: 6px;
@ -142,6 +142,7 @@
top: 30%;
border-radius: 50%;
box-shadow: 0 0 0 6px #F2F2F2;
@include lightDark(box-shadow, 0 0 0 6px #F2F2F2, 0 0 0 6px #111);
z-index: 1;
@include rtl {
left: auto;
@ -438,7 +439,7 @@ ul.pagination {
border-color: rgba(0, 0, 0, 0.1);
}
&:focus {
background-color: #eee;
@include lightDark(background-color, #eee, #222);
outline: 1px dotted #666;
outline-offset: -2px;
}
@ -455,7 +456,7 @@ ul.pagination {
}
.card .entity-list-item:not(.no-hover):hover {
background-color: #F2F2F2;
@include lightDark(background-color, #F2F2F2, #2d2d2d)
}
.card .entity-list-item .entity-list-item:hover {
background-color: #EEEEEE;
@ -554,14 +555,15 @@ ul.pagination {
list-style: none;
right: 0;
margin: $-m 0;
background-color: #FFFFFF;
@include lightDark(background-color, #fff, #333);
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.1);
border-radius: 1px;
border: 1px solid #EEE;
@include lightDark(border-color, #eee, #000);
min-width: 180px;
padding: $-xs 0;
color: #555;
fill: #555;
@include lightDark(color, #555, #eee);
fill: currentColor;
text-align: start !important;
&.wide {
min-width: 220px;
@ -576,7 +578,7 @@ ul.pagination {
a, button {
display: block;
padding: $-xs $-m;
color: #555;
@include lightDark(color, #555, #eee);
fill: currentColor;
white-space: nowrap;
&:hover, &:focus {
@ -653,11 +655,10 @@ ul.pagination {
padding: $-s;
}
a:not(.active) {
color: #444;
fill: #444;
@include lightDark(color, #444, #666);
}
a:hover {
background-color: rgba(0, 0, 0, 0.05);
@include lightDark(background-color, rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));
border-radius: 3px;
text-decoration: none;
}

View File

@ -31,4 +31,18 @@
html[dir=rtl] & {
@content;
}
}
// Define a property for both light and dark mode
@mixin lightDark($prop, $light, $dark, $important: false) {
#{$prop}: if($important, $light !important, $light);
html.dark-mode & {
#{$prop}: if($important, $dark !important, $dark);
}
}
@mixin whenDark {
html.dark-mode & {
@content;
}
}

View File

@ -33,7 +33,7 @@ table.table {
font-weight: bold;
}
tr:hover {
background-color: #EEE;
@include lightDark(background-color, #eee, #333);
}
.text-right {
text-align: end;

View File

@ -42,7 +42,7 @@ h1, h2, h3, h4, h5, h6 {
font-weight: 400;
position: relative;
display: block;
color: #222;
@include lightDark(color, #222, #BBB);
.subheader {
font-size: 0.5em;
line-height: 1em;
@ -91,11 +91,14 @@ h2.list-heading {
*/
a {
color: var(--color-primary);
fill: var(--color-primary);
fill: currentColor;
cursor: pointer;
text-decoration: none;
transition: filter ease-in-out 80ms;
line-height: 1.6;
@include whenDark {
filter: brightness(1.3) saturate(0.7);
}
&:hover {
text-decoration: underline;
}
@ -130,7 +133,7 @@ p, ul, ol, pre, table, blockquote {
hr {
border: 0;
height: 1px;
background: #EAEAEA;
@include lightDark(background, #eaeaea, #222);
margin-bottom: $-l;
&.faded {
background-image: linear-gradient(to right, #FFF, #e3e0e0 20%, #e3e0e0 80%, #FFF);
@ -153,7 +156,7 @@ em, i, .italic {
small, p.small, span.small, .text-small {
font-size: 0.75rem;
color: lighten($text-dark, 10%);
@include lightDark(color, #5e5e5e, #999);
}
sup, .superscript {
@ -168,8 +171,9 @@ sub, .subscript {
pre {
font-size: 12px;
background-color: #f5f5f5;
border: 1px solid #DDD;
@include lightDark(background-color, #f5f5f5, #2B2B2B);
@include lightDark(border-color, #DDD, #111);
padding-left: 31px;
position: relative;
padding-top: 3px;
@ -181,9 +185,9 @@ pre {
top: 0;
width: 29px;
left: 0;
background-color: #f5f5f5;
height: 100%;
border-right: 1px solid #DDD;
@include lightDark(background-color, #f5f5f5, #313335);
@include lightDark(border-right, 1px solid #DDD, none);
}
}
@ -226,10 +230,11 @@ blockquote {
}
.code-base {
background-color: #F8F8F8;
font-size: 0.80em;
border: 1px solid #DDD;
border-radius: 3px;
font-size: 0.84em;
border: 1px solid #DDD;
border-radius: 3px;
@include lightDark(background-color, #f8f8f8f, #2b2b2b);
@include lightDark(border-color, #DDD, #444);
}
code {
@ -385,4 +390,5 @@ span.sep {
bottom: -0.105em;
margin-inline-end: $-xs;
pointer-events: none;
fill: currentColor;
}

View File

@ -63,6 +63,7 @@ $text-light: #EEE;
// Shadows
$bs-light: 0 0 4px 1px #CCC;
$bs-dark: 0 0 4px 1px rgba(0, 0, 0, 0.5);
$bs-med: 0 1px 3px 1px rgba(76, 76, 76, 0.26);
$bs-large: 0 1px 6px 1px rgba(22, 22, 22, 0.2);
$bs-card: 0 1px 6px -1px rgba(0, 0, 0, 0.1);

View File

@ -161,6 +161,7 @@ $btt-size: 40px;
.entity-selector {
border: 1px solid #DDD;
@include lightDark(border-color, #ddd, #111);
border-radius: 3px;
overflow: hidden;
font-size: 0.8em;
@ -176,12 +177,12 @@ $btt-size: 40px;
.entity-list {
overflow-y: scroll;
height: 400px;
background-color: #EEEEEE;
@include lightDark(background-color, #eee, #222);
margin-inline-end: 0;
margin-inline-start: 0;
}
.entity-list-item {
background-color: #FFF;
@include lightDark(background-color, #fff, #222);
}
.entity-list-item p {
margin-bottom: 0;

View File

@ -24,6 +24,11 @@
<!-- Translations for JS -->
@stack('translations')
<script>
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark-mode');
}
</script>
</head>
<body class="@yield('body-class')">

View File

@ -92,7 +92,7 @@
<label for="setting-app-name" class="setting-list-label">{{ trans('settings.app_name') }}</label>
<p class="small">{{ trans('settings.app_name_desc') }}</p>
</div>
<div>
<div class="pt-xs">
<input type="text" value="{{ setting('app-name', 'BookStack') }}" name="setting-app-name" id="setting-app-name">
@include('components.toggle-switch', [
'name' => 'setting-app-name-header',
@ -107,7 +107,7 @@
<label class="setting-list-label">{{ trans('settings.app_editor') }}</label>
<p class="small">{{ trans('settings.app_editor_desc') }}</p>
</div>
<div>
<div class="pt-xs">
<select name="setting-app-editor" id="setting-app-editor">
<option @if(setting('app-editor') === 'wysiwyg') selected @endif value="wysiwyg">WYSIWYG</option>
<option @if(setting('app-editor') === 'markdown') selected @endif value="markdown">Markdown</option>
@ -120,7 +120,7 @@
<label class="setting-list-label">{{ trans('settings.app_logo') }}</label>
<p class="small">{!! trans('settings.app_logo_desc') !!}</p>
</div>
<div>
<div class="pt-xs">
@include('components.image-picker', [
'removeName' => 'setting-app-logo',
'removeValue' => 'none',
@ -138,7 +138,7 @@
<label class="setting-list-label">{{ trans('settings.app_primary_color') }}</label>
<p class="small">{!! trans('settings.app_primary_color_desc') !!}</p>
</div>
<div setting-app-color-picker class="text-m-right">
<div setting-app-color-picker class="text-m-right pt-xs">
<input type="color" data-default="#206ea7" data-current="{{ setting('app-color') }}" value="{{ setting('app-color') }}" name="setting-app-color" id="setting-app-color" placeholder="#206ea7">
<input type="hidden" value="{{ setting('app-color-light') }}" name="setting-app-color-light" id="setting-app-color-light">
<div class="pr-s">
@ -174,7 +174,7 @@
<label for="setting-app-homepage" class="setting-list-label">{{ trans('settings.app_homepage') }}</label>
<p class="small">{{ trans('settings.app_homepage_desc') }}</p>
</div>
<div>
<div class="pt-xs">
<select name="setting-app-homepage-type" id="setting-app-homepage-type">
<option @if(setting('app-homepage-type') === 'default') selected @endif value="default">{{ trans('common.default') }}</option>
<option @if(setting('app-homepage-type') === 'books') selected @endif value="books">{{ trans('entities.books') }}</option>
@ -246,7 +246,7 @@
<label for="setting-registration-restrict" class="setting-list-label">{{ trans('settings.reg_confirm_restrict_domain') }}</label>
<p class="small">{!! trans('settings.reg_confirm_restrict_domain_desc') !!}</p>
</div>
<div>
<div class="pt-xs">
<input type="text" id="setting-registration-restrict" name="setting-registration-restrict" placeholder="{{ trans('settings.reg_confirm_restrict_domain_placeholder') }}" value="{{ setting('registration-restrict', '') }}">
</div>
</div>