* @returns {*|string}
*/
function getTheme() {
- return window.codeTheme || 'default';
+ const darkMode = document.documentElement.classList.contains('dark-mode');
+ return window.codeTheme || (darkMode ? 'darcula' : 'default');
}
/**
*/
.card {
- background-color: #FFF;
+ @include lightDark(background-color, #FFF, #222);
box-shadow: $bs-card;
border-radius: 3px;
border: 1px solid transparent;
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 {
.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 {
/* 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
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; }
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);
}
}
}
.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;
}
/*
.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%;
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 {
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;
display: inline-block;
padding: $-m;
color: #FFF;
- fill: #FFF;
}
.dropdown-container {
padding-inline-start: $-m;
}
}
button {
- fill: #EEE;
z-index: 1;
left: 16px;
@include rtl {
&.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;
}
\ No newline at end of file
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;
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;
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;
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;
}
}
.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;
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;
a, button {
display: block;
padding: $-xs $-m;
- color: #555;
+ @include lightDark(color, #555, #eee);
fill: currentColor;
white-space: nowrap;
&:hover, &:focus {
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;
}
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;
+ }
}
\ No newline at end of file
font-weight: bold;
}
tr:hover {
- background-color: #EEE;
+ @include lightDark(background-color, #eee, #333);
}
.text-right {
text-align: end;
font-weight: 400;
position: relative;
display: block;
- color: #222;
+ @include lightDark(color, #222, #BBB);
.subheader {
font-size: 0.5em;
line-height: 1em;
*/
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;
}
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);
small, p.small, span.small, .text-small {
font-size: 0.75rem;
- color: lighten($text-dark, 10%);
+ @include lightDark(color, #5e5e5e, #999);
}
sup, .superscript {
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;
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);
}
}
}
.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 {
bottom: -0.105em;
margin-inline-end: $-xs;
pointer-events: none;
+ fill: currentColor;
}
// 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);
.entity-selector {
border: 1px solid #DDD;
+ @include lightDark(border-color, #ddd, #111);
border-radius: 3px;
overflow: hidden;
font-size: 0.8em;
.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;
<!-- 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')">
<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',
<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>
<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',
<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">
<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>
<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>