Skip to content

Commit

Permalink
Merge pull request #7 from keiya01/feat/use-spindle-theme-switch
Browse files Browse the repository at this point in the history
feat: use spindle-theme-switch
  • Loading branch information
keiya01 committed Sep 13, 2022
2 parents e94b5bc + a1e07da commit 1c0a4de
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 276 deletions.
1 change: 1 addition & 0 deletions blog.keiya01.dev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"devDependencies": {
"@11ty/eleventy": "^0.12.1",
"@11ty/eleventy-plugin-syntaxhighlight": "^3.1.3",
"@openameba/spindle-theme-switch": "^0.2.2",
"@squoosh/lib": "^0.4.0",
"@textlint/textlint-plugin-markdown": "^12.0.2",
"@types/common-tags": "^1.8.1",
Expand Down
5 changes: 2 additions & 3 deletions blog.keiya01.dev/src/layouts/components/global/Header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,8 @@ export const Header = ({
</li>
<li class="${style.item} ${style.schemeButton}">
<color-scheme-button
aria-disabled="true"
icon-size="24"
label="テーマを変更する"
appearance="switch"
legend="テーマを切り替える"
></color-scheme-button>
</li>
</ul>
Expand Down
50 changes: 10 additions & 40 deletions blog.keiya01.dev/src/lib/components/global/color-scheme-button.css
Original file line number Diff line number Diff line change
@@ -1,42 +1,12 @@
:root {
--color-scheme-button-icon-size: 24px;
--color-scheme-button-icon-color--dark: #edcd00;
--color-scheme-button-icon-color--light: #ed4f00;
--color-scheme-button-color--on: #a770d4;
--color-scheme-button-color--off: #fff;
--color-scheme-button-outline-color: #870144;
}

color-scheme-button[aria-disabled="true"] {
display: inline-block;
opacity: 0.3;
border-radius: var(--color-scheme-button-icon-size);
padding: 3px;
background: var(--color-scheme-button-color--on);
position: relative;
width: calc(var(--color-scheme-button-icon-size) * 2 + 10px);
height: var(--color-scheme-button-icon-size);
}

color-scheme-button[aria-disabled="true"]::before {
content: "";
display: inline-flex;
border-radius: 50%;
width: calc(var(--color-scheme-button-icon-size) + 5px);
height: var(--color-scheme-button-icon-size);
background: var(--color-scheme-button-color--off);
position: absolute;
top: 3px;
transform: translateX(100%);
transition: transform ease-in 0.1s, background ease-in 0.1s;
}
color-scheme-button {
--light-mode-switch-background: #9b92a2;
--dark-mode-switch-background: #53485b;
--light-mode-focus-outline-color: #870144;
--dark-mode-focus-outline-color: #870144;
--light-mode-checked-background: #dcd1e6;
--dark-mode-checked-background: rgba(255, 255, 255, 0.26);

@media (prefers-color-scheme: light) {
color-scheme-button[aria-disabled="true"] {
background: var(--color-scheme-button-color--off);
}
color-scheme-button[aria-disabled="true"]::before {
transform: translateX(0);
background: var(--color-scheme-button-color--on);
}
display: block;
height: 34px;
width: 84px;
}
235 changes: 2 additions & 233 deletions blog.keiya01.dev/src/lib/components/global/color-scheme-button.ts
Original file line number Diff line number Diff line change
@@ -1,236 +1,5 @@
import {
getDataFromLocalStorage,
setDataToLocalStorage,
} from "../../fundamentals/localstrage";
import { SpindleThemeSwitch } from "@openameba/spindle-theme-switch";

const DataColorScheme = "data-color-scheme";

type ColorSchemeUnion = "dark" | "light";

const ColorScheme: { [K in ColorSchemeUnion]: ColorSchemeUnion } = {
dark: "dark",
light: "light",
};

const getCurrentColorScheme = (name: string): ColorSchemeUnion =>
ColorScheme[name as ColorSchemeUnion] || ColorScheme.dark;

const getNextColorScheme = (isDark: boolean): ColorSchemeUnion =>
isDark ? ColorScheme.light : ColorScheme.dark;

const toggleColorScheme = (event: Event) => {
const target = event.target as ColorSchemeButton | null;
if (!target) {
return;
}

const isChecked = target.checked === true;
target.checked = !isChecked;

const html = document.documentElement;
const currentColor = getCurrentColorScheme(
html.getAttribute(DataColorScheme) || ""
);
const nextColor = getNextColorScheme(currentColor === ColorScheme.dark);
html.setAttribute(DataColorScheme, nextColor);

setDataToLocalStorage("theme", nextColor);
};

const setInitialColorScheme = async (matchDark: boolean) => {
const currentColor = await getDataFromLocalStorage("theme");

const isDark = currentColor ? currentColor === ColorScheme.dark : matchDark;

if (currentColor) {
document.documentElement.setAttribute(DataColorScheme, currentColor);
} else {
document.documentElement.setAttribute(
DataColorScheme,
isDark ? ColorScheme.dark : ColorScheme.light
);
}

return isDark;
};

class ColorSchemeButton extends HTMLElement {
constructor() {
super();

this.addEventListener("click", toggleColorScheme);

this.attachShadow({ mode: "open" });

this.render();
}

async connectedCallback(): Promise<void> {
const mql = window.matchMedia(
`(prefers-color-scheme: ${ColorScheme.dark})`
);
this.checked = await setInitialColorScheme(mql.matches);
mql.addEventListener("change", async (e) => {
this.checked = await setInitialColorScheme(e.matches);
});

if (!this.disabled) {
throw new Error(
"<color-scheme-button> should has `aria-disabled` attribute at initial rendering"
);
}
this.disabled = false;
}

set disabled(disabled: boolean) {
this.setAttribute("aria-disabled", `${disabled}`);
}

get disabled(): boolean {
return this.getAttribute("aria-disabled") === "true";
}

set checked(checked: boolean) {
this.setAttribute("aria-checked", `${checked}`);
}

get checked(): boolean {
return this.getAttribute("aria-checked") === "true";
}

set colorScheme(colorScheme: ColorSchemeUnion) {
this.setAttribute(DataColorScheme, colorScheme);
}

get colorScheme(): ColorSchemeUnion {
return getCurrentColorScheme(this.getAttribute(DataColorScheme) || "");
}

get label(): string {
return this.getAttribute("label") || "";
}

get iconSize(): string {
return this.getAttribute("icon-size") || "100%";
}

darkIcon = (label: string): string =>
`<svg aira-label="${label}" fill="currentColor" height="${this.iconSize}" viewBox="0 0 20 20" width="${this.iconSize}" xmlns="http://www.w3.org/2000/svg"><path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path></svg>`;

lightIcon = (label: string): string =>
`<svg aira-label="${label}" fill="currentColor" height="${this.iconSize}" viewBox="0 0 20 20" width="${this.iconSize}" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd"></path></svg>`;

getStyle(): string {
return `
:host {
display: inline-flex;
}
button {
display: flex;
justify-content: space-between;
border-radius: var(--color-scheme-button-icon-size);
padding: 3px;
position: relative;
box-sizing: content-box;
background: var(--color-scheme-button-color--on);
width: calc(var(--color-scheme-button-icon-size) * 2 + 10px);
height: var(--color-scheme-button-icon-size);
transition: background ease-in 0.1s;
outline: none;
border: none;
}
button:focus {
box-shadow: 0 0 0 3px var(--color-scheme-button-outline-color);
}
button:focus:not(:focus-visible) {
box-shadow: none;
}
button::before {
content: "";
display: inline-block;
border-radius: var(--color-scheme-button-icon-size);
width: calc(var(--color-scheme-button-icon-size) + 5px);
height: var(--color-scheme-button-icon-size);
background: var(--color-scheme-button-color--off);
position: absolute;
top: 3px;
transform: translateX(100%);
transition: transform ease-in 0.1s, background ease-in 0.1s;
}
@media(prefers-reduced-motion: reduce) {
button {
transition: none;
}
button::before {
transition: none;
}
}
:host(color-scheme-button[aria-checked="false"]) > label > button {
background: var(--color-scheme-button-color--off);
}
:host(color-scheme-button[aria-checked="false"]) > label > button::before {
transform: translateX(0);
background: var(--color-scheme-button-color--on);
}
label {
display: inline-block;
}
img {
width: calc(var(--color-scheme-button-icon-size));
height: var(--color-scheme-button-icon-size);
padding: 0 3px;
}
.dark-icon {
color: var(--color-scheme-button-icon-color--dark);
}
.light-icon {
color: var(--color-scheme-button-icon-color--light);
}
`;
}

render(): void {
const shadow = this.shadowRoot;
if (!shadow) {
return;
}

shadow.innerHTML = `
<style>${this.getStyle()}</style>
<label for="switch">
<button aria-label="${this.label}" aria-checked="${
this.checked
}" type="button" id="switch" role="switch">
<span class="dark-icon">${this.darkIcon("ダークテーマ")}</span>
<span class="light-icon">${this.lightIcon("ライトテーマ")}</span>
</button>
</label>
`;
}
}
class ColorSchemeButton extends SpindleThemeSwitch {}

customElements.define("color-scheme-button", ColorSchemeButton);

declare global {
interface Window {
ColorSchemeButton: typeof ColorSchemeButton;
}

interface HTMLElementTagNameMap {
"color-scheme-button": ColorSchemeButton;
}
}

export default ColorSchemeButton;
12 changes: 12 additions & 0 deletions blog.keiya01.dev/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,13 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"

"@openameba/spindle-theme-switch@^0.2.2":
version "0.2.2"
resolved "https://registry.yarnpkg.com/@openameba/spindle-theme-switch/-/spindle-theme-switch-0.2.2.tgz#e99e2d0f8e8af3d46b3574c4825c31dc5c88c9c3"
integrity sha512-GB5EgQBnOveSY5K8skmLH+FW0bGmaNQdFfTvajecnQBkKYaDfvHVSCIrMMBCQGnwHpWp7+U3jDaS1onJz2Pq5g==
dependencies:
dark-mode-toggle "^0.14.0"

"@squoosh/lib@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@squoosh/lib/-/lib-0.4.0.tgz#31d18cb082c69e404589e2e281414d10f91e1668"
Expand Down Expand Up @@ -1473,6 +1480,11 @@ csstype@^3.0.7:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340"
integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==

dark-mode-toggle@^0.14.0:
version "0.14.2"
resolved "https://registry.yarnpkg.com/dark-mode-toggle/-/dark-mode-toggle-0.14.2.tgz#77ab6d8e8b7e1505d8d06192f0d1d5cb187e7787"
integrity sha512-VsFLzTO9lA7Pfbylrd6JjRlJkFHTOz6LwoXSeJQKmc3xkLffkyUOzB/R8tDDxXTj3duyaBeLLzqARjiOmV3LNA==

date-time@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/date-time/-/date-time-0.1.1.tgz#ed2f6d93d9790ce2fd66d5b5ff3edd5bbcbf3b07"
Expand Down

0 comments on commit 1c0a4de

Please sign in to comment.