mirror of
https://github.com/jakejarvis/dark-mode.git
synced 2026-08-04 21:45:21 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89a853f4f4
|
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:compat/recommended"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"node": true
|
|
||||||
},
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2015,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"quotes": ["error", "double"],
|
|
||||||
"semi": ["error", "always"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
name: CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14.x'
|
|
||||||
- run: yarn install --frozen-lockfile
|
|
||||||
- run: yarn lint
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
.DS_Store
|
|
||||||
node_modules/
|
|
||||||
dist/
|
|
||||||
.npmrc
|
|
||||||
.vscode/
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
Copyright (c) 2021 Jake Jarvis
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
# 🌓 Dark Mode Switcheroo™
|
|
||||||
|
|
||||||
[](https://github.com/jakejarvis/dark-mode.js/actions/workflows/ci.yml)
|
|
||||||
[](https://www.npmjs.com/package/@jakejarvis/dark-mode)
|
|
||||||
[](LICENSE)
|
|
||||||
|
|
||||||
Very simple CSS dark/light mode toggler with saved preference via local storage & dynamic OS setting detection. Zero dependencies and only ~600 bytes gzipped!
|
|
||||||
|
|
||||||
- [View the example.](https://jakejarvis.github.io/dark-mode-example/)
|
|
||||||
- [Read the blog post.](https://jarv.is/notes/dark-mode/)
|
|
||||||
- [See it in action.](https://jarv.is/)
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
`darkMode.init([...options])`
|
|
||||||
|
|
||||||
- **toggle:** The clickable HTML element used to toggle between the two themes. (optional, default: `null`)
|
|
||||||
- **classes:** An object containing the `<body>` class names for the light and dark themes. (optional, default: `{ light: "light", dark: "dark" }`)
|
|
||||||
- **default:** The initial `<body>` class hard-coded into the HTML template. (optional, default: `"light"`)
|
|
||||||
- **storageKey:** Name of the `localStorage` key holding the user's preference. (optional, default: `"dark_mode_pref"`)
|
|
||||||
|
|
||||||
### Browser
|
|
||||||
|
|
||||||
```html
|
|
||||||
<button class="dark-mode-toggle">💡 Click to see the light... or not.</button>
|
|
||||||
|
|
||||||
<script src="https://unpkg.com/@jakejarvis/dark-mode/dist/dark-mode.min.js"></script>
|
|
||||||
<script>
|
|
||||||
window.darkMode.init({
|
|
||||||
toggle: document.querySelector(".dark-mode-toggle"),
|
|
||||||
classes: {
|
|
||||||
light: "light",
|
|
||||||
dark: "dark",
|
|
||||||
},
|
|
||||||
default: "light",
|
|
||||||
storageKey: "dark_mode_pref",
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Node
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install @jakejarvis/dark-mode
|
|
||||||
# or...
|
|
||||||
yarn add @jakejarvis/dark-mode
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Module via `import`
|
|
||||||
|
|
||||||
```js
|
|
||||||
import { init } from "@jakejarvis/dark-mode";
|
|
||||||
|
|
||||||
init({
|
|
||||||
toggle: document.querySelector(".dark-mode-toggle"),
|
|
||||||
classes: {
|
|
||||||
light: "light",
|
|
||||||
dark: "dark",
|
|
||||||
},
|
|
||||||
default: "light",
|
|
||||||
storageKey: "dark_mode_pref",
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### CommonJS via `require()`
|
|
||||||
|
|
||||||
```js
|
|
||||||
const darkMode = require("@jakejarvis/dark-mode");
|
|
||||||
|
|
||||||
darkMode.init({
|
|
||||||
toggle: document.querySelector(".dark-mode-toggle"),
|
|
||||||
classes: {
|
|
||||||
light: "light",
|
|
||||||
dark: "dark",
|
|
||||||
},
|
|
||||||
default: "light",
|
|
||||||
storageKey: "dark_mode_pref",
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## To-Do
|
|
||||||
|
|
||||||
- [ ] Support more than two themes
|
|
||||||
- [ ] Add callback function `onChange` (or `onToggle` etc.) passed in as an option
|
|
||||||
- [ ] Better readme docs
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT
|
|
||||||
@@ -4,19 +4,66 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Welcome to the dark side 🌓</title>
|
<title>Welcome to the dark side 🌓</title>
|
||||||
<style>/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}body{font-family:system-ui,-apple-system,sans-serif;text-align:center}a{text-decoration:none}h1{font-size:1.8em}.dark-mode-toggle{cursor:pointer;padding:1em;visibility:hidden}body.light{background-color:#fff;color:#222}body.light a{color:#06f}body.dark{background-color:#222;color:#fff}body.dark a{color:#fe0}</style>
|
<style>/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}</style>
|
||||||
|
<style>
|
||||||
|
/* Global styles */
|
||||||
|
body {
|
||||||
|
font-family: system-ui, -apple-system, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Light theme */
|
||||||
|
body.light {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
body.light a {
|
||||||
|
color: #06f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark theme */
|
||||||
|
body.dark {
|
||||||
|
background-color: #222;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
body.dark a {
|
||||||
|
color: #fe0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The Toggle (TM) */
|
||||||
|
.dark-mode-toggle {
|
||||||
|
padding: 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
/* Hide the toggle initially if the user's JS is disabled: */
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="light">
|
<body class="light"> <!-- default to light theme -->
|
||||||
<h1>Welcome to the dark side 🌓</h1>
|
<h1>Welcome to the dark side 🌓</h1>
|
||||||
|
|
||||||
<button class="dark-mode-toggle">💡 Click to see the light... or not.</button>
|
<button class="dark-mode-toggle">💡 Click to see the light... or not.</button>
|
||||||
|
|
||||||
<p><a href="https://github.com/jakejarvis/dark-mode" target="_blank" rel="noopener">View the source code</a> or <a href="https://jarv.is/notes/dark-mode/" target="_blank" rel="noopener">read the post</a>.</p>
|
<p><a href="https://github.com/jakejarvis/dark-mode" target="_blank" rel="noopener">GitHub Repo</a> · <a href="https://github.com/jakejarvis/dark-mode/blob/gh-pages/index.html" target="_blank" rel="noopener">Source Code</a></p>
|
||||||
|
|
||||||
<script src="../dist/dark-mode.js"></script>
|
<script src="https://unpkg.com/@jakejarvis/dark-mode/dist/dark-mode.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
window.darkMode.init({
|
window.darkMode.init({
|
||||||
toggle: document.querySelector(".dark-mode-toggle"),
|
toggle: document.querySelector(".dark-mode-toggle"),
|
||||||
|
classes: {
|
||||||
|
light: "light",
|
||||||
|
dark: "dark",
|
||||||
|
},
|
||||||
|
default: "light",
|
||||||
|
storageKey: "example_dark_mode_pref",
|
||||||
|
onInit: function (e) {
|
||||||
|
e.style.visibility = "visible";
|
||||||
|
console.log("Toggle is visible now that we know user has JS enabled.");
|
||||||
|
},
|
||||||
|
onChange: function (t) {
|
||||||
|
console.log("Set theme to " + t);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@jakejarvis/dark-mode",
|
|
||||||
"version": "0.5.0",
|
|
||||||
"description": "🌓 Simple CSS theme switching with saved preferences and automatic OS setting detection",
|
|
||||||
"license": "MIT",
|
|
||||||
"author": {
|
|
||||||
"name": "Jake Jarvis",
|
|
||||||
"email": "jake@jarv.is",
|
|
||||||
"url": "https://jarv.is/"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/jakejarvis/dark-mode.git"
|
|
||||||
},
|
|
||||||
"main": "dist/dark-mode.cjs.js",
|
|
||||||
"module": "dist/dark-mode.esm.js",
|
|
||||||
"unpkg": "dist/dark-mode.min.js",
|
|
||||||
"types": "dist/dark-mode.d.ts",
|
|
||||||
"scripts": {
|
|
||||||
"build": "rollup -c",
|
|
||||||
"lint": "eslint src/**/*.js",
|
|
||||||
"prepublishOnly": "yarn build"
|
|
||||||
},
|
|
||||||
"dependencies": {},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.15.0",
|
|
||||||
"@babel/preset-env": "^7.15.0",
|
|
||||||
"@rollup/plugin-babel": "^5.3.0",
|
|
||||||
"@rollup/plugin-eslint": "^8.0.1",
|
|
||||||
"@rollup/plugin-node-resolve": "^13.0.4",
|
|
||||||
"eslint": "^7.32.0",
|
|
||||||
"eslint-plugin-compat": "^3.11.1",
|
|
||||||
"rollup": "^2.55.1",
|
|
||||||
"rollup-plugin-copy": "^3.4.0",
|
|
||||||
"rollup-plugin-filesize": "^9.1.1",
|
|
||||||
"rollup-plugin-terser": "^7.0.2"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"dist"
|
|
||||||
],
|
|
||||||
"keywords": [
|
|
||||||
"frontend",
|
|
||||||
"dark mode",
|
|
||||||
"theme",
|
|
||||||
"appearance",
|
|
||||||
"design",
|
|
||||||
"css"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
import resolve from "@rollup/plugin-node-resolve";
|
|
||||||
import { babel } from "@rollup/plugin-babel";
|
|
||||||
import { terser } from "rollup-plugin-terser";
|
|
||||||
import eslint from "@rollup/plugin-eslint";
|
|
||||||
import filesize from "rollup-plugin-filesize";
|
|
||||||
import copy from "rollup-plugin-copy";
|
|
||||||
|
|
||||||
const banner = "/*! Dark Mode Switcheroo | MIT License | jrvs.io/darkmode */";
|
|
||||||
|
|
||||||
export default [
|
|
||||||
{
|
|
||||||
// universal (browser and node)
|
|
||||||
input: "src/index.js",
|
|
||||||
output: [
|
|
||||||
{
|
|
||||||
name: "darkMode",
|
|
||||||
file: "dist/dark-mode.js",
|
|
||||||
format: "umd",
|
|
||||||
exports: "named",
|
|
||||||
esModule: false,
|
|
||||||
banner: banner,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "darkMode",
|
|
||||||
file: "dist/dark-mode.min.js",
|
|
||||||
format: "umd",
|
|
||||||
exports: "named",
|
|
||||||
esModule: false,
|
|
||||||
plugins: [
|
|
||||||
terser({
|
|
||||||
output: {
|
|
||||||
preamble: banner,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
copy({
|
|
||||||
// clearly this isn't really typescript, so we need to manually copy the type definition file
|
|
||||||
targets: [
|
|
||||||
{
|
|
||||||
src: "src/index.d.ts",
|
|
||||||
dest: "dist",
|
|
||||||
rename: "dark-mode.d.ts",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
resolve(),
|
|
||||||
eslint(),
|
|
||||||
babel({
|
|
||||||
babelHelpers: "bundled",
|
|
||||||
presets: [["@babel/preset-env"]],
|
|
||||||
exclude: ["node_modules/**"],
|
|
||||||
}),
|
|
||||||
filesize(),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// modules
|
|
||||||
input: "src/index.js",
|
|
||||||
output: [
|
|
||||||
{
|
|
||||||
// ES6 module (import)
|
|
||||||
file: "dist/dark-mode.esm.js",
|
|
||||||
format: "esm",
|
|
||||||
exports: "named",
|
|
||||||
banner: banner,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// commonjs (require)
|
|
||||||
file: "dist/dark-mode.cjs.js",
|
|
||||||
format: "cjs",
|
|
||||||
exports: "named",
|
|
||||||
banner: banner,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
resolve(),
|
|
||||||
babel({
|
|
||||||
babelHelpers: "bundled",
|
|
||||||
exclude: ["node_modules/**"],
|
|
||||||
}),
|
|
||||||
filesize(),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
Vendored
-8
@@ -1,8 +0,0 @@
|
|||||||
interface DarkModeOptions {
|
|
||||||
toggle?: HTMLElement;
|
|
||||||
classes?: { dark: string, light: string };
|
|
||||||
default?: string;
|
|
||||||
storageKey?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function init(options?: DarkModeOptions): void;
|
|
||||||
-104
@@ -1,104 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
const init = function (options) {
|
|
||||||
// { toggle, classes: { light, dark }, default, storageKey }
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
// use a specified element(s) to trigger swap when clicked
|
|
||||||
const toggle = options.toggle || null;
|
|
||||||
|
|
||||||
// check for preset `dark_mode_pref` preference in local storage
|
|
||||||
const storageKey = options.storageKey || "dark_mode_pref";
|
|
||||||
const storageAvailable = isStorageAvailable();
|
|
||||||
const pref = storageAvailable ? localStorage.getItem(storageKey) : null;
|
|
||||||
|
|
||||||
// change CSS via these <body> classes:
|
|
||||||
const dark = options.classes ? options.classes.dark : "dark";
|
|
||||||
const light = options.classes ? options.classes.light : "light";
|
|
||||||
|
|
||||||
// which class is <body> set to initially?
|
|
||||||
const defaultTheme = options.default || "light";
|
|
||||||
|
|
||||||
// keep track of current state no matter how we got there
|
|
||||||
let active = defaultTheme === dark;
|
|
||||||
|
|
||||||
// receives a class name and switches <body> to it
|
|
||||||
const activateTheme = function (theme, remember) {
|
|
||||||
document.body.classList.remove(dark, light);
|
|
||||||
document.body.classList.add(theme);
|
|
||||||
active = theme === dark;
|
|
||||||
|
|
||||||
if (storageAvailable && !!remember) {
|
|
||||||
localStorage.setItem(storageKey, theme);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// user has never clicked the button, so go by their OS preference until/if they do so
|
|
||||||
if (!pref) {
|
|
||||||
// returns media query selector syntax
|
|
||||||
const prefers = function (colorScheme) {
|
|
||||||
// https://drafts.csswg.org/mediaqueries-5/#prefers-color-scheme
|
|
||||||
return `(prefers-color-scheme: ${colorScheme})`;
|
|
||||||
};
|
|
||||||
|
|
||||||
// check for OS dark/light mode preference and switch accordingly
|
|
||||||
// default to `defaultTheme` set above if unsupported
|
|
||||||
if (window.matchMedia(prefers("dark")).matches) {
|
|
||||||
activateTheme(dark);
|
|
||||||
} else if (window.matchMedia(prefers("light")).matches) {
|
|
||||||
activateTheme(light);
|
|
||||||
} else {
|
|
||||||
activateTheme(defaultTheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
// real-time switching if supported by OS/browser
|
|
||||||
window.matchMedia(prefers("dark")).addEventListener("change", function (e) {
|
|
||||||
if (e.matches) {
|
|
||||||
activateTheme(dark);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.matchMedia(prefers("light")).addEventListener("change", function (e) {
|
|
||||||
if (e.matches) {
|
|
||||||
activateTheme(light);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (pref === dark || pref === light) {
|
|
||||||
// if user already explicitly toggled in the past, restore their preference
|
|
||||||
activateTheme(pref);
|
|
||||||
} else {
|
|
||||||
// fallback to default theme (this shouldn't happen)
|
|
||||||
activateTheme(defaultTheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't freak out if page happens not to have a toggle
|
|
||||||
if (toggle !== null) {
|
|
||||||
// toggle re-appears now that we know user has JS enabled
|
|
||||||
toggle.style.visibility = "visible";
|
|
||||||
|
|
||||||
// handle toggle click
|
|
||||||
toggle.addEventListener("click", function () {
|
|
||||||
// switch to the opposite theme & save preference in local storage
|
|
||||||
if (active) {
|
|
||||||
activateTheme(light, true);
|
|
||||||
} else {
|
|
||||||
activateTheme(dark, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// recommended method (by MDN) to detect localStorage availability:
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API#feature-detecting_localstorage
|
|
||||||
const isStorageAvailable = function () {
|
|
||||||
try {
|
|
||||||
var storage = window["localStorage"];
|
|
||||||
var x = "__storage_test__";
|
|
||||||
storage.setItem(x, x);
|
|
||||||
storage.removeItem(x);
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export { init };
|
|
||||||
Reference in New Issue
Block a user