Skip to content

Instantly share code, notes, and snippets.

@rodydavis
Created February 10, 2022 21:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rodydavis/3abe1b973563e3d02c7fb8539e6e983e to your computer and use it in GitHub Desktop.
Save rodydavis/3abe1b973563e3d02c7fb8539e6e983e to your computer and use it in GitHub Desktop.
Material You on the Web
import * as utils from "https://cdn.skypack.dev/@guidezpl/material-color-utilities";
function themeFromSeed(seed) {
const palette = utils.CorePalette.of(seed);
return {
seed: seed,
schemes: {
light: utils.Scheme.light(seed),
dark: utils.Scheme.dark(seed),
},
palettes: {
primary: palette.a1,
secondary: palette.a2,
tertiary: palette.a3,
neutral: palette.n1,
neutralVariant: palette.n2,
error: palette.error,
},
customColors: [],
};
}
const target = document.body;
const input = document.querySelector("#seed");
const random = document.querySelector("#random");
const reset = document.querySelector("#reset");
const brightness = document.querySelector("#brightness");
function applyTheme(theme, options) {
const target = options?.target || document.body;
const isDark =
options?.dark ?? window.matchMedia("(prefers-color-scheme: dark)").matches;
const scheme = isDark ? theme.schemes.dark : theme.schemes.light;
const json = Object(scheme)["props"];
for (const [key, value] of Object.entries(json)) {
const token = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
const color = utils.hexFromArgb(value);
target.style.setProperty(`--md-sys-color-${token}`, color);
}
}
function randomColor() {
const letters = "0123456789ABCDEF";
let color = "#";
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function setTheme(color, dark) {
if (color === null) {
return;
}
if (color === "") {
localStorage.removeItem("theme");
localStorage.removeItem("brightness");
brightness.value = window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
target.classList.remove("dark-theme");
target.classList.remove("light-theme");
target.setAttribute("style", "");
reset.setAttribute("disabled", "");
return;
}
reset.removeAttribute("disabled");
localStorage.setItem("theme", color);
const intColor = utils.argbFromHex(color);
const theme = themeFromSeed(intColor);
applyTheme(theme, { target, dark });
}
input.addEventListener("input", (event) => {
const color = event.target.value;
setTheme(color, brightness.value === "dark");
});
random.addEventListener("click", () => {
const color = randomColor();
input.value = color;
setTheme(color, brightness.value === "dark");
});
reset.addEventListener("click", () => {
input.value = "";
setTheme("", brightness.value === "dark");
});
brightness.addEventListener("change", (e) => {
const value = e.target.value;
const isDark = value === "dark";
if (isDark) {
target.classList.remove("light-theme");
target.classList.add("dark-theme");
} else {
target.classList.remove("dark-theme");
target.classList.add("light-theme");
}
const color = localStorage.getItem("theme");
if (color) {
setTheme(color, isDark);
}
localStorage.setItem("brightness", value);
});
window
.matchMedia("(prefers-color-scheme: dark)")
.addEventListener("change", (event) => {
const isDark = event.matches;
const color = localStorage.getItem("theme");
setTheme(color, isDark);
});
const savedTheme = localStorage.getItem("theme");
const savedBrightness = localStorage.getItem("brightness");
brightness.value =
savedBrightness || window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
if (savedTheme) {
setTheme(savedTheme, savedBrightness === "dark");
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body class="material-theme">
<header><span class="title">Material Theme</span></header>
<main>
<button id="random">Random Color</button>
<div class="divider"></div>
<div>
<input id="seed" type="color" />
<label for="seed">Custom Color</label>
</div>
<div class="divider"></div>
<div>
<select id="brightness">
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
<label for="theme">Theme Brightness</label>
</div>
<div class="divider"></div>
<button id="reset" disabled>Reset Theme</button>
</main>
<script type="module" src="app.js"></script>
</body>
</html>
@import url(https://material-foundation.github.io/material-tokens/css/baseline.css);
body {
background-color: var(--md-sys-color-background);
color: var(--md-sys-color-on-background);
margin: 0;
padding: 0;
width: 100%;
height: 100vh;
font: normal 16px/1.5 "Roboto", "Helvetica", "Arial", sans-serif;
}
header {
background-color: var(--md-sys-color-primary);
color: var(--md-sys-color-on-primary);
padding: 1rem;
display: flex;
align-items: center;
justify-content: space-between;
}
header .title {
font-size: 1.1rem;
font-weight: 500;
}
button {
background-color: var(--md-sys-color-tertiary);
color: var(--md-sys-color-on-tertiary);
text-transform: uppercase;
font-weight: 500;
border: none;
border-radius: 0.25rem;
padding: 0.5rem 1rem;
cursor: pointer;
}
button[disabled] {
opacity: 0.5;
cursor: not-allowed;
}
main {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.divider {
height: 20px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment