ph-utils
Version:
js 开发工具集,前后端都可以使用(commonjs和es module)
163 lines (162 loc) • 5.39 kB
JavaScript
import { adjust } from "./color.js";
/** 获取当前系统的主题 */
export function getSystemTheme() {
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
return "dark";
}
else if (window.matchMedia("(prefers-color-scheme: light)").matches) {
return "light";
}
return "auto";
}
/**
* 初始化主题, 让网页能够适应系统主题, 同时根据缓存的主题切换主题
* @returns 当前应用的主题
*/
export async function initTheme() {
// 让网页能够适应系统主题
let $themeStyle = document.getElementById("theme-style");
if ($themeStyle == null) {
$themeStyle = document.createElement("style");
$themeStyle.id = "theme-style";
$themeStyle.innerHTML = `
:root{color-scheme:light dark;}
html.light{color-scheme: light;}
html.dark {color-scheme: dark;}
`;
document.head.appendChild($themeStyle);
}
// 获取已经应用的主题设置
const cacheTheme = localStorage.getItem("web-theme-appearance");
return toggleTheme(cacheTheme);
}
/**
* 切换主题, 通常用于预览
* @param theme 切换的主题
* @param transition 是否使用过渡动画, 注意浏览器必须支持 document.startViewTransition, 默认: true
* @returns 切换后的主题
*/
export async function toggleTheme(theme, transition = true) {
return new Promise((resolve) => {
const classList = document.documentElement.classList;
if (theme == null) {
theme = getSystemTheme();
}
function updateThemeClass() {
if (theme === "light") {
classList.add("light");
classList.remove("dark");
}
else if (theme === "dark") {
classList.add("dark");
classList.remove("light");
}
else {
classList.remove("light", "dark");
}
}
// @ts-ignore
if (transition && document.startViewTransition) {
// @ts-ignore
document.startViewTransition(() => {
updateThemeClass();
resolve(theme);
});
}
else {
updateThemeClass();
resolve(theme);
}
});
}
/** 获取当前主题 */
export function getTheme() {
// 1. 从根节点获取
let theme = document.documentElement.className.match(/light|dark/);
if (theme != null) {
theme = theme[0];
}
if (theme == null) {
theme = localStorage.getItem("web-theme-appearance");
}
if (theme == null) {
theme = getSystemTheme();
}
return theme;
}
/**
* 应用主题
* @param theme 待应用的主题
* @param cache 是否缓存应用的主题, 让应用下一次启动的时候, 可以应用主题, 默认: true
* @param transition 是否使用过渡动画, 注意浏览器必须支持 document.startViewTransition, 默认: true
* @returns 应用的主题
*/
export async function applyTheme(theme, cache = true, transition = true) {
if (cache === true) {
localStorage.setItem("web-theme-appearance", theme == null ? "auto" : theme);
}
return toggleTheme(theme, transition);
}
/** 获取当前主题色 */
export function getColorTheme(defaultValue) {
const root = document.documentElement;
const match = root.className.match(/color-([0-9a-fA-F]{6})/);
if (match == null) {
// 获取 --nt-primary-color 的值
let color = getComputedStyle(root).getPropertyValue("--nt-primary-color");
if (color === "") {
color = localStorage.getItem("web-theme-color");
}
return color ? color : defaultValue;
}
return `#${match[1]}`;
}
/**
* 初始化主题色, 让网页能够适应系统主题色, 同时根据缓存的主题色切换主题色
* @returns 当前应用的主题色
*/
export function initColorTheme() {
// 获取缓存主题色
const color = localStorage.getItem("web-theme-color");
if (color != null) {
return toggleColorTheme(color);
}
return color;
}
/**
* 切换主题色, 通常用于预览
* @param color 待切换的主题色
* @returns 切换后的主题色
*/
export async function toggleColorTheme(color) {
const vars = [
`--nt-primary-color: ${color};`,
`--l-primary-color: ${color};`,
`--nt-primary-color-dark1: ${adjust(color, 1, false)};`,
`--l-primary-color-dark1: ${adjust(color, 1, false)};`,
];
for (let i = 1; i <= 5; i++) {
vars.push(`--nt-primary-color-light${i}: ${adjust(color, i)};`);
vars.push(`--l-primary-color-light${i}: ${adjust(color, i)};`);
}
let $style = document.getElementById("color-theme-style");
if ($style == null) {
$style = document.createElement("style");
$style.id = "color-theme-style";
document.head.appendChild($style);
}
$style.innerHTML = `:root{${vars.join("")}}`;
return color;
}
/**
* 应用主题色
* @param color 主题色
* @param cache 是否缓存主题色, 让应用下一次启动的时候, 可以应用主题色, 默认: true
* @returns 切换后的主题色
*/
export function applyColorTheme(color, cache = true) {
if (cache === true) {
localStorage.setItem("web-theme-color", color);
}
return toggleColorTheme(color);
}