1
mirror of https://github.com/jakejarvis/dark-mode.git synced 2026-06-05 19:25:28 -04:00

Compare commits

..

1 Commits

Author SHA1 Message Date
jake 89a853f4f4 publish example to GH pages 2021-08-05 12:01:25 -04:00
13 changed files with 8 additions and 4107 deletions
-17
View File
@@ -1,17 +0,0 @@
# http://editorconfig.org
# this file is the top-most editorconfig file
root = true
# all files
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
# site content
[*.md]
trim_trailing_whitespace = false
-16
View File
@@ -1,16 +0,0 @@
{
"extends": [
"@jakejarvis/eslint-config",
"plugin:@typescript-eslint/recommended"
],
"plugins": [
"@typescript-eslint"
],
"parser": "@typescript-eslint/parser",
"env": {
"browser": true
},
"ignorePatterns": [
"dist/**"
]
}
-2
View File
@@ -1,2 +0,0 @@
# Set default behavior to automatically normalize line endings.
* text=auto eol=lf
-10
View File
@@ -1,10 +0,0 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
versioning-strategy: increase
schedule:
interval: "daily"
commit-message:
prefix: "📦 npm:"
-19
View File
@@ -1,19 +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: 16.x
- run: yarn install --frozen-lockfile
- run: yarn lint
- run: yarn build
-20
View File
@@ -1,20 +0,0 @@
name: Release
on:
push:
tags:
- 'v*'
jobs:
npm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16.x
registry-url: https://registry.npmjs.org/
- run: yarn install --frozen-lockfile
- run: yarn publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
-5
View File
@@ -1,5 +0,0 @@
.DS_Store
node_modules/
dist/
.npmrc
.vscode/
-19
View File
@@ -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.
-87
View File
@@ -1,87 +0,0 @@
# 🌓 Dark Mode Switcheroo™
[![CI](https://github.com/jakejarvis/dark-mode/actions/workflows/ci.yml/badge.svg)](https://github.com/jakejarvis/dark-mode/actions/workflows/ci.yml)
[![npm](https://img.shields.io/npm/v/dark-mode-switcheroo)](https://www.npmjs.com/package/dark-mode-switcheroo)
Very simple CSS dark/light mode toggler with saved preference via local storage & dynamic OS setting detection. Zero dependencies and [only ~500 bytes gzipped!](https://bundlephobia.com/package/dark-mode-switcheroo)
- [View the example.](https://jakejarvis.github.io/dark-mode/)
- [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 [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement) 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"`)
- **`onInit([toggle])`**: Callback function executed at the end of initialization. The toggle above is passed in if set. (optional, default: `null`)
- **`onUserToggle([toggle])`**: Callback function executed when a user manually interacts with the toggle button. The toggle above (if set) is passed in. (optional, default: `null`)
- **`onChange([theme, toggle])`**: Callback function executed when theme is switched. The new theme and the toggle above (if set) are passed in. (optional, default: `null`)
### Browser
```html
<button class="dark-mode-toggle" style="visibility: hidden;">💡 Click to see the light... or not.</button>
<script src="https://unpkg.com/dark-mode-switcheroo/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",
onInit: function (toggle) {
toggle.style.visibility = "visible"; // toggle appears now that we know JS is enabled
},
onChange: function (theme, toggle) {
console.log("Theme is now " + theme);
},
});
</script>
```
### Node
```bash
npm install dark-mode-switcheroo
# or...
yarn add dark-mode-switcheroo
```
#### Module via `import`
```js
import { init } from "dark-mode-switcheroo";
init({
// ...same as browser.
});
```
#### CommonJS via `require()`
```js
const darkMode = require("dark-mode-switcheroo");
darkMode.init({
// ...same as browser.
});
```
## To-Do
- [ ] Support more than two themes
- [ ] Better readme docs
- [x] Add callback function `onChange` (or `onToggle` etc.) passed in as an option
## License
MIT
+8 -2
View File
@@ -45,12 +45,18 @@
<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> &middot; <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.min.js"></script> <!-- or use CDN: https://unpkg.com/dark-mode-switcheroo/dist/dark-mode.min.js -->
<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: "example_dark_mode_pref",
onInit: function (e) {
e.style.visibility = "visible";
console.log("Toggle is visible now that we know user has JS enabled.");
-52
View File
@@ -1,52 +0,0 @@
{
"name": "dark-mode-switcheroo",
"version": "0.10.0",
"description": "🌓 Simple CSS theme switching with saved preferences and automatic OS setting detection",
"license": "MIT",
"homepage": "https://jrvs.io/darkmode",
"author": {
"name": "Jake Jarvis",
"email": "jake@jarv.is",
"url": "https://jarv.is/"
},
"repository": {
"type": "git",
"url": "https://github.com/jakejarvis/dark-mode.git"
},
"type": "module",
"files": [
"dist"
],
"source": "./src/dark-mode.ts",
"main": "./dist/dark-mode.cjs",
"module": "./dist/dark-mode.esm.js",
"unpkg": "./dist/dark-mode.min.js",
"exports": {
"require": "./dist/dark-mode.cjs",
"import": "./dist/dark-mode.esm.js",
"browser": "./dist/dark-mode.min.js"
},
"types": "./dist/dark-mode.d.ts",
"scripts": {
"build": "microbundle --format cjs,esm,umd --name 'darkMode'",
"lint": "eslint .",
"prepublishOnly": "yarn build"
},
"dependencies": {},
"devDependencies": {
"@jakejarvis/eslint-config": "*",
"@typescript-eslint/eslint-plugin": "^5.3.1",
"@typescript-eslint/parser": "^5.3.1",
"eslint": "^8.2.0",
"microbundle": "^0.14.1",
"typescript": "^4.4.4"
},
"keywords": [
"front-end",
"dark mode",
"theme",
"appearance",
"design",
"css"
]
}
-104
View File
@@ -1,104 +0,0 @@
export function init(options: {
toggle?: Element | null;
classes?: { dark: string, light: string };
default?: string;
storageKey?: string;
onInit?: (toggle?: Element | null) => unknown;
onUserToggle?: (toggle?: Element | null) => unknown;
onChange?: (theme: string, toggle?: Element | null) => unknown;
}): void {
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 pref = localStorage.getItem(storageKey);
// 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: string, remember?: boolean) {
// optional onChange callback function passed as option
if (typeof options.onChange === "function") {
options.onChange(theme, toggle);
}
document.body.classList.remove(dark, light);
document.body.classList.add(theme);
active = theme === dark;
if (remember) {
localStorage.setItem(storageKey, theme);
}
};
// optional onInit callback function passed as option
if (typeof options.onInit === "function") {
options.onInit(toggle);
}
// 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: "dark" | "light") {
// 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) {
// handle toggle click
toggle.addEventListener("click", function () {
// optional onUserToggle callback function passed as option
if (typeof options.onUserToggle === "function") {
options.onUserToggle(toggle);
}
// switch to the opposite theme & save preference in local storage
if (active) {
activateTheme(light, true);
} else {
activateTheme(dark, true);
}
});
}
}
-3754
View File
File diff suppressed because it is too large Load Diff