dark mode + .... some form of toggle :)

This commit is contained in:
Rick van Lieshout 2022-09-11 00:00:31 +02:00
parent c22687de6d
commit 31c106c58e
20 changed files with 291 additions and 20 deletions

View File

@ -4,12 +4,23 @@ This is the repository for my personal blog/website [rickvanlieshout.com](https:
## Todo ## Todo
- Add a dark mode - Add a better dark mode toggle
- show in posts view
- print view
- hide mode toggler
- hide "all articles" link in posts
- Change theme of prism.js
- "time to read" (https://www.gatsbyjs.com/plugins/gatsby-remark-reading-time/)
<!-- migrations -->
- migrate resume - migrate resume
- migrate projects - migrate projects
- migrate some example blogs - migrate some example blogs
<!-- optional stuff -->
- release to sftp or gh-pages - release to sftp or gh-pages
- "time to read" - lighthouse doesn't like the blue... :)
- Maybe improve the cookie page with actual cookie data?

View File

@ -4,10 +4,13 @@ template: "page"
--- ---
A cookie is a small text file that a website saves on the client A cookie is a small text file that a website saves on the client
computer (your computer) to make the website function better. Some computer (your computer) to make the website function better.
examples of what cookies are used for: Note that these files can be stored as actual "cookies" or as "local/session storage".<br />
I will be using Cookie to refer to both in the rest of this article
- Remembering what language the website should be in Some examples of what cookies are used for:
- Remembering what language/theme the website should be in
- Storing your cart when shopping online - Storing your cart when shopping online
- Keeping you logged in - Keeping you logged in

30
gatsby-ssr.ts Normal file
View File

@ -0,0 +1,30 @@
import { RenderBodyArgs } from "gatsby";
import React from "react";
const setColorTheme = `
(function() {
const mode = localStorage.getItem('theme');
if (mode !== null && ['light', 'dark'].includes(mode)) {
document.documentElement.dataset.theme = mode;
return;
}
const preferredColorScheme = window.matchMedia('(prefers-color-scheme: dark)');
const hasMediaQueryPreference = typeof preferredColorScheme.matches === 'boolean';
if (hasMediaQueryPreference && preferredColorScheme.matches === true) {
document.documentElement.dataset.theme = 'dark';
} else {
document.documentElement.dataset.theme = 'light'
}
})();
`;
export const onRenderBody = ({ setPreBodyComponents }: RenderBodyArgs) => {
setPreBodyComponents([
React.createElement("script", {
key: "theme",
dangerouslySetInnerHTML: {
__html: setColorTheme,
},
}),
]);
};

113
package-lock.json generated
View File

@ -84,6 +84,7 @@
"jest-svg-transformer": "^1.0.0", "jest-svg-transformer": "^1.0.0",
"lint-staged": "^13.0.3", "lint-staged": "^13.0.3",
"lost": "9.0.1", "lost": "9.0.1",
"markdownlint": "^0.26.2",
"postcss": "^8.4.16", "postcss": "^8.4.16",
"postcss-scss": "^4.0.4", "postcss-scss": "^4.0.4",
"prettier": "^2.7.1", "prettier": "^2.7.1",
@ -21170,6 +21171,15 @@
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
}, },
"node_modules/linkify-it": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"dev": true,
"dependencies": {
"uc.micro": "^1.0.1"
}
},
"node_modules/lint-staged": { "node_modules/lint-staged": {
"version": "13.0.3", "version": "13.0.3",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.3.tgz", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.3.tgz",
@ -21899,6 +21909,40 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/markdown-it": {
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1",
"entities": "~3.0.1",
"linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"bin": {
"markdown-it": "bin/markdown-it.js"
}
},
"node_modules/markdown-it/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
"node_modules/markdown-it/node_modules/entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
"dev": true,
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/markdown-table": { "node_modules/markdown-table": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
@ -21911,6 +21955,18 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/markdownlint": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.26.2.tgz",
"integrity": "sha512-2Am42YX2Ex5SQhRq35HxYWDfz1NLEOZWWN25nqd2h3AHRKsGRE+Qg1gt1++exW792eXTrR4jCNHfShfWk9Nz8w==",
"dev": true,
"dependencies": {
"markdown-it": "13.0.1"
},
"engines": {
"node": ">=14"
}
},
"node_modules/marked": { "node_modules/marked": {
"version": "4.0.19", "version": "4.0.19",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.0.19.tgz", "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.19.tgz",
@ -32347,6 +32403,12 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
"dev": true
},
"node_modules/uglify-js": { "node_modules/uglify-js": {
"version": "3.17.0", "version": "3.17.0",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz",
@ -49604,6 +49666,15 @@
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
}, },
"linkify-it": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"dev": true,
"requires": {
"uc.micro": "^1.0.1"
}
},
"lint-staged": { "lint-staged": {
"version": "13.0.3", "version": "13.0.3",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.3.tgz", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.3.tgz",
@ -50168,6 +50239,33 @@
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
"dev": true "dev": true
}, },
"markdown-it": {
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"dev": true,
"requires": {
"argparse": "^2.0.1",
"entities": "~3.0.1",
"linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"dependencies": {
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
"entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
"dev": true
}
}
},
"markdown-table": { "markdown-table": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
@ -50176,6 +50274,15 @@
"repeat-string": "^1.0.0" "repeat-string": "^1.0.0"
} }
}, },
"markdownlint": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.26.2.tgz",
"integrity": "sha512-2Am42YX2Ex5SQhRq35HxYWDfz1NLEOZWWN25nqd2h3AHRKsGRE+Qg1gt1++exW792eXTrR4jCNHfShfWk9Nz8w==",
"dev": true,
"requires": {
"markdown-it": "13.0.1"
}
},
"marked": { "marked": {
"version": "4.0.19", "version": "4.0.19",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.0.19.tgz", "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.19.tgz",
@ -57849,6 +57956,12 @@
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
"integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==" "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ=="
}, },
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
"dev": true
},
"uglify-js": { "uglify-js": {
"version": "3.17.0", "version": "3.17.0",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz",

View File

@ -119,6 +119,7 @@
"jest-svg-transformer": "^1.0.0", "jest-svg-transformer": "^1.0.0",
"lint-staged": "^13.0.3", "lint-staged": "^13.0.3",
"lost": "9.0.1", "lost": "9.0.1",
"markdownlint": "^0.26.2",
"postcss": "^8.4.16", "postcss": "^8.4.16",
"postcss-scss": "^4.0.4", "postcss-scss": "^4.0.4",
"prettier": "^2.7.1", "prettier": "^2.7.1",

View File

@ -1,14 +1,33 @@
@use "sass:math"; @use "sass:math";
@use "sass:color"; @use "sass:color";
$color-base: hsl(0, 0%, 13%); :root {
$color-primary: hsl(220, 100%, 68%); --bg-color: #fff;
$color-secondary: hsl(220, 100%, 68%); --base: hsl(0, 0%, 13%);
--primary: hsl(220, 100%, 68%);
--secondary: hsl(220, 100%, 68%);
--gray: hsl(230, 23%, 23%);
--gray-border: hsl(230, 77%, 13%);
}
[data-theme="dark"] {
--bg-color: hsl(210, 3.7%, 10.6%);
--base: hsl(219, 14%, 71%);
--primary: hsl(220, 100%, 68%);
--secondary: hsl(220, 100%, 68%);
--gray-border: hsl(220, 10%, 40%);
--gray: hsl(0, 0%, 100%);
}
$color-bg: var(--bg-color);
$color-base: var(--base);
$color-primary: var(--primary);
$color-secondary: var(--secondary);
$color-white: hsl(0, 0%, 100%); $color-white: hsl(0, 0%, 100%);
$color-gray: color.adjust($color-base, $lightness: 40%);
$color-gray-border: color.adjust($color-base, $lightness: 77%); $color-gray: color.adjust(hsl(0, 0%, 13%), $lightness: 30%);
$color-gray-bg: color.adjust($color-base, $lightness: 79%); $color-gray-border: var(--gray-border);
$color-gray-bg: var(--gray-border);
$typographic-font-family: -apple-system, "BlinkMacSystemFont", "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", sans-serif; $typographic-font-family: -apple-system, "BlinkMacSystemFont", "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", sans-serif;

View File

@ -6,6 +6,7 @@ html {
} }
body { body {
background-color: $color-bg;
color: $typographic-base-font-color; color: $typographic-base-font-color;
font-family: $typographic-font-family; font-family: $typographic-font-family;
font-size: $typographic-base-font-size; font-size: $typographic-base-font-size;

View File

@ -0,0 +1,29 @@
import React, { useState, useEffect } from "react";
enum themes {
dark = "dark",
light = "light",
}
function ThemeSwitcher() {
const initTheme = document.documentElement.dataset.theme;
const [theme, setTheme] = useState(initTheme);
useEffect(() => {
localStorage.setItem("theme", theme ?? themes.light);
document.documentElement.dataset.theme = theme;
}, [theme]);
const getOppositeTheme = () => {
return theme === themes.light ? themes.dark : themes.light;
};
function toggleTheme() {
const newTheme = theme === themes.dark ? themes.light : themes.dark;
setTheme(newTheme);
}
return <a href="#" onClick={toggleTheme}>{`Switch to ${getOppositeTheme()} mode`}</a>;
}
export default ThemeSwitcher;

View File

@ -3,9 +3,9 @@
.header { .header {
align-items: baseline; align-items: baseline;
background: #fff; background: $color-bg;
border-bottom: 1px solid #808080; border-bottom: 1px solid #808080;
color: #000; color: $color-base;
display: flex; display: flex;
height: 50px; height: 50px;
justify-content: space-between; justify-content: space-between;
@ -33,7 +33,7 @@
} }
.name { .name {
color: #000; color: $color-base;
} }
} }

View File

@ -4,6 +4,6 @@
@import "../../../assets/scss/mixins"; @import "../../../assets/scss/mixins";
.copyright { .copyright {
color: color.adjust($color-gray, $whiteness: 18%); color: $color-gray;
font-size: $typographic-small-font-size; font-size: $typographic-small-font-size;
} }

View File

@ -7,6 +7,7 @@ import { Menu } from "./Menu";
import * as styles from "./Sidebar.module.scss"; import * as styles from "./Sidebar.module.scss";
import { useSiteMetadata } from "@/hooks"; import { useSiteMetadata } from "@/hooks";
import ThemeSwitcher from "../DarkmodeSwitch/ThemeSwitcher";
type Props = { type Props = {
isIndex?: boolean; isIndex?: boolean;
@ -23,6 +24,7 @@ const Sidebar = ({ isIndex }: Props) => {
<Contacts contacts={author.contacts} /> <Contacts contacts={author.contacts} />
<Copyright copyright={copyright} /> <Copyright copyright={copyright} />
<Menu menu={legalMenu} /> <Menu menu={legalMenu} />
<ThemeSwitcher />
</div> </div>
</div> </div>
); );

View File

@ -141,6 +141,12 @@ exports[`Sidebar renders correctly 1`] = `
<nav> <nav>
<ul /> <ul />
</nav> </nav>
<a
href="#"
onClick={[Function]}
>
Switch to light mode
</a>
</div> </div>
</div> </div>
`; `;

View File

@ -142,6 +142,12 @@ exports[`CategoriesTemplate renders correctly 1`] = `
<nav> <nav>
<ul /> <ul />
</nav> </nav>
<a
href="#"
onClick={[Function]}
>
Switch to light mode
</a>
</div> </div>
</div> </div>
<div> <div>

View File

@ -142,6 +142,12 @@ exports[`CategoryTemplate renders correctly 1`] = `
<nav> <nav>
<ul /> <ul />
</nav> </nav>
<a
href="#"
onClick={[Function]}
>
Switch to light mode
</a>
</div> </div>
</div> </div>
<div> <div>

View File

@ -142,6 +142,12 @@ exports[`IndexTemplate renders correctly 1`] = `
<nav> <nav>
<ul /> <ul />
</nav> </nav>
<a
href="#"
onClick={[Function]}
>
Switch to light mode
</a>
</div> </div>
</div> </div>
<div> <div>

View File

@ -4,6 +4,7 @@ import { Layout } from "@/components/Layout";
import { Page } from "@/components/Page"; import { Page } from "@/components/Page";
import { Sidebar } from "@/components/Sidebar"; import { Sidebar } from "@/components/Sidebar";
import { useSiteMetadata } from "@/hooks"; import { useSiteMetadata } from "@/hooks";
import { Link } from "gatsby";
const NotFoundTemplate: React.FC = () => { const NotFoundTemplate: React.FC = () => {
const { title, subtitle } = useSiteMetadata(); const { title, subtitle } = useSiteMetadata();
@ -11,8 +12,12 @@ const NotFoundTemplate: React.FC = () => {
return ( return (
<Layout title={`Not Found - ${title}`} description={subtitle}> <Layout title={`Not Found - ${title}`} description={subtitle}>
<Sidebar /> <Sidebar />
<Page title="NOT FOUND"> <Page title="Oh no! page be lost">
<p>You just hit a route that doesn't exist... the sadness.</p> <p>
You've stumbled upon a link that doesn't work anymore {":("}
<br />
Use the menu to navigate around or click <Link to="/">here</Link> to go to the main page.
</p>
</Page> </Page>
</Layout> </Layout>
); );

View File

@ -142,16 +142,31 @@ exports[`NotFoundTemplate renders correctly 1`] = `
<nav> <nav>
<ul /> <ul />
</nav> </nav>
<a
href="#"
onClick={[Function]}
>
Switch to light mode
</a>
</div> </div>
</div> </div>
<div> <div>
<div> <div>
<h1> <h1>
NOT FOUND Oh no! page be lost
</h1> </h1>
<div> <div>
<p> <p>
You just hit a route that doesn't exist... the sadness. You've stumbled upon a link that doesn't work anymore
:(
<br />
Use the menu to navigate around or click
<a
href="/"
>
here
</a>
to go to the main page.
</p> </p>
</div> </div>
</div> </div>

View File

@ -142,6 +142,12 @@ exports[`PageTemplate renders correctly 1`] = `
<nav> <nav>
<ul /> <ul />
</nav> </nav>
<a
href="#"
onClick={[Function]}
>
Switch to light mode
</a>
</div> </div>
</div> </div>
<div> <div>

View File

@ -142,6 +142,12 @@ exports[`TagTemplate renders correctly 1`] = `
<nav> <nav>
<ul /> <ul />
</nav> </nav>
<a
href="#"
onClick={[Function]}
>
Switch to light mode
</a>
</div> </div>
</div> </div>
<div> <div>

View File

@ -142,6 +142,12 @@ exports[`TagsTemplate renders correctly 1`] = `
<nav> <nav>
<ul /> <ul />
</nav> </nav>
<a
href="#"
onClick={[Function]}
>
Switch to light mode
</a>
</div> </div>
</div> </div>
<div> <div>