diff --git a/README.md b/README.md
index 266aba6..39ad58d 100644
--- a/README.md
+++ b/README.md
@@ -62,3 +62,6 @@ The file is in this format:
Publishing the site content requires AWS credentials which are not stored in this repository. Attempts to use the `gulp publish` command will fail.
+## Attributions
+
+Sun/moon svg icons forked from [glow-ui/glow-icons](https://github.com/glow-ui/glow-icons). Licensed under the [MIT license](https://github.com/glow-ui/glow-icons/blob/main/LICENSE).
diff --git a/js/_dark.js b/js/_dark.js
new file mode 100644
index 0000000..eefb467
--- /dev/null
+++ b/js/_dark.js
@@ -0,0 +1,25 @@
+(function () {
+ // Check if local storage is available and if dark mode is set; overrides everything else
+ if (window.localStorage && window.localStorage.getItem('dark-mode') !== null) {
+ if (window.localStorage.getItem('dark-mode') === 'true') {
+ document.documentElement.classList.add('dark-mode');
+ }
+ // Evaluate device preferences
+ } else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ document.documentElement.classList.add('dark-mode');
+ }
+}());
+
+$(function () {
+ $('.dark-toggle').on('click', function toggleDarkMode (e) {
+ e.preventDefault();
+
+ if (document.documentElement.classList.contains('dark-mode')) {
+ document.documentElement.classList.remove('dark-mode');
+ window.localStorage.setItem('dark-mode', 'false');
+ } else {
+ document.documentElement.classList.add('dark-mode');
+ window.localStorage.setItem('dark-mode', 'true');
+ }
+ });
+});
diff --git a/scss/_card.scss b/scss/_card.scss
index e220200..fc0394f 100644
--- a/scss/_card.scss
+++ b/scss/_card.scss
@@ -3,12 +3,30 @@
text-decoration: none;
background: white;
+ @include dark-mode {
+ background: $content-bg-dark;
+ border: 1px solid $primary;
+ box-shadow: 0 0 5px 2px rgba($primary, 0.5);
+
+ .card-header {
+ background: lighten($content-bg-dark, 5);
+ }
+ }
+
&.borderless {
border: none;
+
+ @include dark-mode {
+ box-shadow: none;
+ }
}
.card-img, .card-img-top {
// width: unset;
+ @include dark-mode {
+ // Some card images don't work on dark backgrounds
+ background-color: white;
+ }
}
.card-img-top + .card-img-top {
@@ -23,6 +41,10 @@
font-size: 12px;
font-family: $font-secondary;
+ @include dark-mode {
+ color: $body-color-dark;
+ }
+
ul { padding-left: 1.2em; }
}
@@ -70,6 +92,10 @@
font-family: Roboto, Helvetica, Arial,sans-serif;
text-decoration:none;
+ @include dark-mode {
+ background: $content-bg-dark;
+ color: $body-color-dark;
+ }
.ig-header {
display: flex;
diff --git a/scss/_dark.scss b/scss/_dark.scss
new file mode 100644
index 0000000..565f849
--- /dev/null
+++ b/scss/_dark.scss
@@ -0,0 +1,17 @@
+$disable-dark-mode: false !default;
+
+@mixin dark-mode {
+ @if not $disable-dark-mode {
+ .dark-mode & {
+ @content
+ }
+ }
+}
+
+@mixin light-mode {
+ @if not $disable-dark-mode {
+ :root:not(.dark-mode) & {
+ @content
+ }
+ }
+}
diff --git a/scss/_dropdown.scss b/scss/_dropdown.scss
new file mode 100644
index 0000000..495de2a
--- /dev/null
+++ b/scss/_dropdown.scss
@@ -0,0 +1,13 @@
+.dropdown-menu {
+ @include dark-mode {
+ background-color: #2d2d2d;
+
+ .dropdown-item, .dropdown-item:hover:active:not(.active) {
+ color: white;
+ }
+
+ .dropdown-item:hover:not(:active) {
+ color: black;
+ }
+ }
+}
diff --git a/scss/_global.scss b/scss/_global.scss
index f37f3fd..f57760b 100644
--- a/scss/_global.scss
+++ b/scss/_global.scss
@@ -1,6 +1,19 @@
+a {
+ @include dark-mode {
+ color: lighten($primary, 10%);
+
+ &:hover {
+ color: lighten($primary, 20%);
+ }
+ }
+}
body {
font-family: $font-primary;
+
+ @include dark-mode {
+ color: $body-color-dark;
+ }
}
// Prevents the page header from blocking view of
@@ -16,6 +29,10 @@ body {
}
h1:target, h2:target, h3:target, h4:target, h5:target, h6:target {
background-color: yellow !important;
+
+ @include dark-mode {
+ color: black;
+ }
}
span.svg-icon {
diff --git a/scss/_header.scss b/scss/_header.scss
index ef64f92..a11553a 100644
--- a/scss/_header.scss
+++ b/scss/_header.scss
@@ -10,6 +10,10 @@
text-decoration: none;
}
}
+
+ @include dark-mode {
+ color: $body-color-dark;
+ }
}
body.inner-page header {
@@ -63,6 +67,12 @@ header {
@media (max-width: 500px) {
font-size: 1.8em;
}
+
+ @include dark-mode {
+ abbr {
+ color: $primary;
+ }
+ }
}
&.active {
@@ -72,13 +82,16 @@ header {
.top-brand {
max-height: 0;
}
+
+ .top-nav.aux-nav {
+ display: none;
+ }
}
}
nav {
flex: 1;
- max-width: 1200px;
display: flex;
justify-content: space-between;
@@ -92,6 +105,36 @@ header {
@media (max-width: 500px) {
font-size: 0.8rem;
}
+
+ @include dark-mode {
+ a {
+ color: inherit;
+
+ &:hover {
+ color: inherit;
+ text-decoration: none;
+ }
+ }
+ }
+ }
+
+ .top-nav {
+ &.main-nav {
+ margin-left: auto;
+ order: 2;
+
+ @media (max-width: 800px) {
+ margin-left: 0;
+ }
+ }
+
+ &.aux-nav {
+ order: 3;
+
+ @media (max-width: 800px) {
+ order: 1;
+ }
+ }
}
.top-nav-inner {
@@ -99,13 +142,9 @@ header {
justify-content: space-between;
align-items: center;
list-style: none;
- margin: 0 0 0 1em;
+ margin: 0;
padding: 0;
- @media (max-width: 800px) {
- margin: 0;
- }
-
.top-nav-item {
transition-property: color, padding, margin;
@@ -144,38 +183,49 @@ header {
}
}
- @media (max-width: 400px) {
- .disposable {
- display: none;
- }
- }
-
.dropdown-menu {
max-height: 90vh;
overflow: auto;
}
- }
- @media (max-width: 500px) {
+ .dark-toggle {
+ display: grid;
- .top-nav-inner .disposable {
- transition: max-width 0.5s ease-out;
- max-width: 50px;
- }
+ > span {
+ grid-column: 1;
+ grid-row: 1;
+ transition: all 0.5s;
+ transition-behavior: allow-discrete;
+ }
- &.active .top-nav-inner .disposable {
- max-width: 0;
- overflow: hidden;
+ .dark-toggle-sun {
+ opacity: 1;
+ }
+
+ .dark-toggle-moon {
+ opacity: 0;
+ }
+
+ @include dark-mode {
+ .dark-toggle-sun {
+ opacity: 0;
+ }
+
+ .dark-toggle-moon {
+ opacity: 1;
+ }
+ }
}
}
-
}
-// @media (min-width: 500px) {
- body:not(.front-page) header + * {
- margin-top: $header-full-height;
+body:not(.front-page) header + * {
+ margin-top: $header-mobile-height;
+
+ @media (min-width: 800px) {
+ margin-top: $header-desktop-height;
}
-// }
+}
.disclaimer {
$cwColor: darken($gray-100, 2%);
@@ -193,6 +243,12 @@ header {
background-color: $cwColor;
+ @include dark-mode {
+ background-color: $gray-800;
+ color: white;
+ border-bottom: 1px solid $primary;
+ }
+
font-size: 0.8rem;
font-weight: 300;
diff --git a/scss/_index.scss b/scss/_index.scss
index f65293a..9e36f00 100644
--- a/scss/_index.scss
+++ b/scss/_index.scss
@@ -1,11 +1,25 @@
.front-page {
+ @include dark-mode {
+ background-color: #000;
+ }
+
+ header.active {
+ @include dark-mode {
+ background-color: $gray-900;
+ }
+ }
.top-fold {
min-height: 100vh;
background-color: $header-bg-mid;
background-image: linear-gradient(135deg, $header-bg-1, $header-bg-2);
- padding-top: $header-full-height;
+ padding-top: 150px;
+
+ @include dark-mode {
+ background-color: inherit;
+ background-image: none;
+ }
@media (max-width: 400px) {
padding-top: 100px;
@@ -33,6 +47,13 @@
text-shadow: 0px 1px 3px rgba(black, 0.9);
color: $gray-100;
+ @include dark-mode {
+ background: darken($trans-blue-darkest, 10%);
+ border: 1px solid #0087bb;
+ box-shadow: 0 0 5px 2px rgba($trans-blue, .5);
+ color: $body-color-dark;
+ }
+
max-width: 500px;
width: 50vw;
font-family: $font-secondary;
@@ -60,6 +81,17 @@
box-shadow: inset 0px 1px 5px rgba(#000, 0.2), 0px 1px 5px rgba(#000, 0.9);
text-shadow: 0px 1px 3px rgba(#fff, 0.6);
+ @include dark-mode {
+ background-color: $content-bg-dark;
+ box-shadow: 0 0 1pc 6px $primary;
+ color: $body-color-dark;
+ text-shadow: none;
+
+ @media (max-width: 800px) {
+ box-shadow: none;
+ }
+ }
+
max-width: 850px;
margin-left: 0.5em;
}
@@ -83,6 +115,13 @@
}
}
+ @media (max-width: 500px) {
+ .copy {
+ margin-left: 0;
+ margin-right: 0;
+ }
+ }
+
}
.pager {
diff --git a/scss/_markup.scss b/scss/_markup.scss
index aafc0ae..777c3ae 100644
--- a/scss/_markup.scss
+++ b/scss/_markup.scss
@@ -1,16 +1,19 @@
.markup {
-webkit-font-smoothing: antialiased;
+ transition: background-color 0.5s;
p a {
transition-property: color, padding, margin;
transition-duration: 0.3s;
transition-timing-function: ease;
- color: $primary;
text-decoration: underline;
- &:hover {
- color: #e84992;
+ @include light-mode {
+ color: $primary;
+ &:hover {
+ color: #e84992;
+ }
}
}
@@ -34,6 +37,13 @@
padding: 15px;
color: black;
+ @include dark-mode {
+ background: darken($trans-blue-darkest, 10%);
+ border: 1px solid #0087bb;
+ color: $body-color-dark;
+ box-shadow: 0 0 5px 2px rgba($trans-blue,0.5);
+ }
+
color-adjust: exact;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
@@ -87,6 +97,12 @@
img {
height: 1em;
}
+
+ @include dark-mode {
+ // Convert the black svg icon to the $primary color at runtime using CSS filters
+ // https://stackoverflow.com/a/43960991
+ filter: invert(34%) sepia(87%) saturate(2698%) hue-rotate(313deg) brightness(108%) contrast(98%);
+ }
}
+ {
@@ -152,6 +168,11 @@
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
+ @include dark-mode {
+ background-color: lighten($content-bg-dark, 5%);
+ color: #fff;
+ }
+
font-size: 0.8rem;
font-weight: 300;
diff --git a/scss/_page.scss b/scss/_page.scss
index b8731af..a03564d 100644
--- a/scss/_page.scss
+++ b/scss/_page.scss
@@ -7,6 +7,10 @@ body.page, body.post {
header {
background: $gray-800;
&.active { background: white; }
+
+ @include dark-mode {
+ background: $gray-900;
+ }
}
}
@@ -27,15 +31,32 @@ body.post {
}
body.gdb {
+ transition: background-color 0.5s;
+
+ @include dark-mode {
+ background-color: $body-bg-dark;
+ }
#body {
background-color: $gutter-bg;
+ border-bottom: 1px solid $gutter-border;
+
+ @include dark-mode {
+ background-color: $gutter-bg-dark;
+ border-bottom: 1px solid $gutter-border-dark;
+ color: $body-color-dark;
+ box-shadow: 0px 6px 11px -6px $gutter-border-dark;
+ }
@media (max-width: 500px) {
border-left: 1px solid $gutter-border;
border-right: 1px solid $gutter-border;
+
+ @include dark-mode {
+ border-left: 0;
+ border-right: 0;
+ }
}
- border-bottom: 1px solid $gutter-border;
max-width: 1200px;
margin-left: auto;
@@ -54,6 +75,11 @@ body.gdb {
background: $content-bg;
border-right: 1px solid $gutter-border;
+ @include dark-mode {
+ background: $content-bg-dark;
+ border-right: none;
+ }
+
padding: 1em 1em;
> h1:first-child {
diff --git a/scss/_pager.scss b/scss/_pager.scss
index 78e0260..35f4a6c 100644
--- a/scss/_pager.scss
+++ b/scss/_pager.scss
@@ -33,6 +33,12 @@
overflow: hidden;
text-overflow: ellipsis;
}
+
+ @include dark-mode {
+ &:hover {
+ color: white;
+ }
+ }
}
.btn.left {
diff --git a/scss/_tweet.scss b/scss/_tweet.scss
index 9a40b64..7f3fa62 100644
--- a/scss/_tweet.scss
+++ b/scss/_tweet.scss
@@ -8,6 +8,10 @@
$borderRadius: .35em;
$avatarSize: 36px;
+ $borderColorDark: $trans-blue-dark;
+ $textLightDark: #697882;
+ $textDarkDark: #b4d0dd;
+
font-size: 12px;
body.post & {
font-size: 15px;
@@ -22,6 +26,15 @@
overflow-x: hidden;
overflow-y: auto;
+ @include dark-mode {
+ background-color: $content-bg-dark;
+ border-color: $borderColorDark;
+
+ &:not(.grid-row) {
+ box-shadow: 0 0 5px 2px rgba($trans-blue, 0.5);
+ }
+ }
+
page-break-inside: avoid;
@include media-breakpoint-up(md) {
@@ -47,6 +60,10 @@
border-top: 1px solid $borderColor;
border-top-left-radius: 0;
border-top-right-radius: 0;
+
+ @include dark-mode {
+ border-top: 1px solid $borderColorDark;
+ }
}
.tweet-item:first-child .tweet-logo { display: block; }
@@ -69,6 +86,10 @@
margin-bottom: 1em;
line-height: 1;
+ @include dark-mode {
+ color: $textDarkDark;
+ }
+
&:hover {
color: $textHover;
}
@@ -348,6 +369,10 @@
.tweet-item {
border-top: none;
padding: 0;
+
+ @include dark-mode {
+ border-top: none;
+ }
}
.tweet-item + .tweet-item {
@@ -383,6 +408,13 @@
border: none;
max-height: unset;
+ @include dark-mode {
+ // Box shadow hackery
+ margin-left: -1em;
+ margin-right: -1em;
+ padding: 1em;
+ }
+
.tweet-item {
background-color: white;
border: 1px solid $borderColor;
@@ -391,6 +423,12 @@
border-top-left-radius: $borderRadius;
border-top-right-radius: $borderRadius;
+ @include dark-mode {
+ background-color: $content-bg-dark;
+ border: 1px solid $borderColorDark;
+ box-shadow: 0 0 5px 2px rgba($trans-blue, 0.5);
+ }
+
.tweet-logo { display: block; }
.tweet-text {
@@ -416,6 +454,11 @@
flex-direction: column;
margin: -1px;
+ @include dark-mode {
+ background-color: $content-bg-dark;
+
+ }
+
.tweet-logo { display: block; }
.tweet-text {
diff --git a/scss/print.scss b/scss/print.scss
index c571df1..e0b52ea 100644
--- a/scss/print.scss
+++ b/scss/print.scss
@@ -11,6 +11,8 @@ $font-brand: 'Sriracha', Geneva, monospace;
$font-family-sans-serif: $font-primary;
$font-family-base: $font-primary;
+$disable-dark-mode: true;
+
$grid-breakpoints: (
xs: 0,
sm: 500px,
@@ -94,6 +96,7 @@ $header-full-height: 100px;
@import "bootstrap/scss/utilities";
// @import "bootstrap/scss/print";
+@import "./dark"; // Need to disable for print styles
@import "./global";
// @import "./header";
@import "./footer";
diff --git a/scss/style.scss b/scss/style.scss
index 6ba4d2f..491f81c 100644
--- a/scss/style.scss
+++ b/scss/style.scss
@@ -52,7 +52,18 @@ $primary: #fc0a7e;
$header-bg-1: #E81179;
$header-bg-2: #281362;
$header-bg-mid: mix($header-bg-1, $header-bg-2);
-$header-full-height: 100px;
+$header-desktop-height: 100px;
+$header-mobile-height: 142px;
+
+/* -- Dark Mode -- */
+$body-bg-dark: black;
+$body-color-dark: #e2e2e2;
+$content-bg-dark: #222;
+$gutter-bg-dark: #171717;
+$gutter-border-dark: #fc0a7e;
+
+$primary-light-dark: lighten($primary, 10%);
+$primary-lighter-dark: lighten($primary, 10%);
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@@ -94,8 +105,10 @@ $header-full-height: 100px;
@import "bootstrap/scss/utilities";
// @import "bootstrap/scss/print";
+@import "./dark";
@import "./global";
@import "./header";
+@import "./dropdown";
@import "./footer";
@import "./tweet";
@import "./index";
@@ -108,4 +121,4 @@ $header-full-height: 100px;
@import "./longform";
@import "./font-compatibility";
-|node_modules/magnific-popup/dist/magnific-popup.css|
+//|node_modules/magnific-popup/dist/magnific-popup.css|
diff --git a/svg/moon.svg b/svg/moon.svg
new file mode 100644
index 0000000..4862d8a
--- /dev/null
+++ b/svg/moon.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/svg/sun.svg b/svg/sun.svg
new file mode 100644
index 0000000..aeca207
--- /dev/null
+++ b/svg/sun.svg
@@ -0,0 +1,12 @@
+
+
diff --git a/templates/layout.hbs b/templates/layout.hbs
index 47fd391..3faec1f 100644
--- a/templates/layout.hbs
+++ b/templates/layout.hbs
@@ -61,7 +61,7 @@