- utils.js: 950行→180行,移除30+未使用函数 - styles.js: 1800行→650行,移除未使用组件样式和重复规则 - animations.js: 850行→120行,移除Web Animations API dead code - 全项目版本号升级到 2.0.1 - 测试同步清理,134/134通过
617 lines
19 KiB
JavaScript
617 lines
19 KiB
JavaScript
/**
|
||
* MetonaToast Styles - 样式管理(精简版 v2.0.1)
|
||
* @module styles
|
||
* @description 样式注入与主题管理,移除未使用的组件样式
|
||
*/
|
||
|
||
import { THEMES } from './constants.js';
|
||
|
||
// 样式缓存
|
||
let styleElement = null;
|
||
|
||
/**
|
||
* 生成CSS样式
|
||
*/
|
||
const generateCSS = (theme) => {
|
||
return `
|
||
/* MetonaToast 基础样式 */
|
||
.met-container {
|
||
pointer-events: none;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
box-sizing: border-box;
|
||
padding: 24px;
|
||
max-width: 100vw;
|
||
position: fixed;
|
||
z-index: 9999;
|
||
}
|
||
|
||
/* 位置样式 */
|
||
.met-container.top-left { top: 0; left: 0; align-items: flex-start; }
|
||
.met-container.top-center { top: 0; left: 0; right: 0; align-items: center; }
|
||
.met-container.top-right { top: 0; right: 0; align-items: flex-end; }
|
||
.met-container.bottom-left { bottom: 0; left: 0; align-items: flex-start; }
|
||
.met-container.bottom-center{ bottom: 0; left: 0; right: 0; align-items: center; }
|
||
.met-container.bottom-right { bottom: 0; right: 0; align-items: flex-end; }
|
||
|
||
/* Toast基础样式 */
|
||
.met-toast {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 12px;
|
||
padding: 14px 16px;
|
||
border-radius: 12px;
|
||
box-sizing: border-box;
|
||
backdrop-filter: blur(14px) saturate(180%);
|
||
-webkit-backdrop-filter: blur(14px) saturate(180%);
|
||
font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
|
||
user-select: none;
|
||
-webkit-user-select: none;
|
||
transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1),
|
||
box-shadow 0.25s ease,
|
||
opacity 0.25s ease;
|
||
will-change: transform, opacity;
|
||
flex-shrink: 0;
|
||
pointer-events: auto;
|
||
min-width: 240px;
|
||
max-width: calc(100vw - 48px);
|
||
width: 360px;
|
||
border: 1px solid var(--met-border, rgba(0,0,0,0.06));
|
||
background: var(--met-bg, rgba(255,255,255,0.96));
|
||
color: var(--met-text, #1f2937);
|
||
box-shadow: var(--met-shadow, 0 10px 36px -10px rgba(0,0,0,0.18), 0 4px 14px -4px rgba(0,0,0,0.08));
|
||
transform: translateZ(0);
|
||
-webkit-transform: translateZ(0);
|
||
backface-visibility: hidden;
|
||
-webkit-backface-visibility: hidden;
|
||
perspective: 1000;
|
||
}
|
||
|
||
/* 悬停效果 */
|
||
.met-toast:hover {
|
||
box-shadow: var(--met-hover-shadow, 0 14px 48px -10px rgba(0,0,0,0.22), 0 6px 18px -4px rgba(0,0,0,0.10)) !important;
|
||
}
|
||
|
||
/* 可点击状态 */
|
||
.met-toast.met-clickable {
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* 图标样式 */
|
||
.met-icon {
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 24px;
|
||
height: 24px;
|
||
margin-top: 1px;
|
||
}
|
||
|
||
/* 内容样式 */
|
||
.met-content {
|
||
flex: 1;
|
||
min-width: 0;
|
||
word-wrap: break-word;
|
||
overflow-wrap: break-word;
|
||
}
|
||
|
||
/* 标题样式 */
|
||
.met-title {
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
letter-spacing: 0.1px;
|
||
}
|
||
|
||
/* 消息样式 */
|
||
.met-message {
|
||
font-size: 13px;
|
||
opacity: 0.85;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
/* 关闭按钮样式 */
|
||
.met-close {
|
||
flex-shrink: 0;
|
||
background: transparent;
|
||
border: 0;
|
||
padding: 4px;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 6px;
|
||
transition: background 0.2s, color 0.2s;
|
||
line-height: 0;
|
||
color: inherit;
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.met-close:hover {
|
||
opacity: 1;
|
||
background: var(--met-close-hover-bg, rgba(0,0,0,0.06));
|
||
}
|
||
|
||
/* 进度条样式 - 水平 */
|
||
.met-progress {
|
||
position: absolute;
|
||
left: 0; right: 0; bottom: 0;
|
||
height: 3px;
|
||
overflow: hidden;
|
||
background: var(--met-progress-bg, rgba(0,0,0,0.06));
|
||
border-radius: 0 0 12px 12px;
|
||
}
|
||
|
||
/* 进度条样式 - 垂直 */
|
||
.met-progress-v {
|
||
position: absolute;
|
||
left: 0; top: 0; bottom: 0;
|
||
width: 3px;
|
||
overflow: hidden;
|
||
background: var(--met-progress-bg, rgba(0,0,0,0.06));
|
||
border-radius: 12px 0 0 12px;
|
||
}
|
||
|
||
/* 进度条指示器 - 水平 */
|
||
.met-bar {
|
||
position: absolute;
|
||
left: 0; top: 0;
|
||
height: 100%; width: 100%;
|
||
transform-origin: left;
|
||
transform: scaleX(1);
|
||
}
|
||
|
||
/* 进度条指示器 - 垂直 */
|
||
.met-bar-v {
|
||
position: absolute;
|
||
left: 0; bottom: 0;
|
||
width: 100%; height: 100%;
|
||
transform-origin: bottom;
|
||
transform: scaleY(1);
|
||
}
|
||
|
||
/* 侧边指示器 */
|
||
.met-side {
|
||
position: absolute;
|
||
left: 0; top: 0; bottom: 0;
|
||
width: 4px;
|
||
border-radius: 12px 0 0 12px;
|
||
}
|
||
|
||
/* 加载动画 */
|
||
.met-spin {
|
||
animation: met-rot 1s linear infinite;
|
||
transform-origin: 50% 50%;
|
||
}
|
||
|
||
/* 离开状态 */
|
||
.met-toast.met-leaving {
|
||
pointer-events: none;
|
||
z-index: 1;
|
||
}
|
||
|
||
@keyframes met-rot {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
|
||
/* === 进入动画:初始隐藏态 === */
|
||
.met-anim-slide.met-toast,
|
||
.met-anim-fade.met-toast,
|
||
.met-anim-scale.met-toast,
|
||
.met-anim-bounce.met-toast,
|
||
.met-anim-flip.met-toast,
|
||
.met-anim-rotate.met-toast,
|
||
.met-anim-zoom.met-toast,
|
||
.met-anim-slideUp.met-toast,
|
||
.met-anim-slideDown.met-toast,
|
||
.met-anim-slideLeft.met-toast,
|
||
.met-anim-slideRight.met-toast {
|
||
opacity: 0;
|
||
}
|
||
|
||
/* === 进入动画:@keyframes 定义 === */
|
||
@keyframes met-slide-in {
|
||
0% { transform: translateX(80px); opacity: 0; }
|
||
65% { transform: translateX(-6px); opacity: 1; }
|
||
100% { transform: translateX(0); opacity: 1; }
|
||
}
|
||
@keyframes met-fade-in {
|
||
0% { opacity: 0; filter: blur(3px); }
|
||
100% { opacity: 1; filter: blur(0); }
|
||
}
|
||
@keyframes met-scale-in {
|
||
0% { transform: scale(0.55); opacity: 0; }
|
||
65% { transform: scale(1.07); opacity: 1; }
|
||
100% { transform: scale(1); opacity: 1; }
|
||
}
|
||
@keyframes met-bounce-in {
|
||
0% { transform: translateY(-80px); opacity: 0; animation-timing-function: ease-in; }
|
||
45% { transform: translateY(14px); opacity: 1; animation-timing-function: ease-out; }
|
||
65% { transform: translateY(-12px); animation-timing-function: ease-in; }
|
||
82% { transform: translateY(4px); animation-timing-function: ease-out; }
|
||
100% { transform: translateY(0); opacity: 1; }
|
||
}
|
||
@keyframes met-flip-in {
|
||
0% { transform: perspective(500px) rotateX(-90deg); opacity: 0; }
|
||
60% { transform: perspective(500px) rotateX(8deg); opacity: 1; }
|
||
85% { transform: perspective(500px) rotateX(-2deg); }
|
||
100% { transform: perspective(500px) rotateX(0); opacity: 1; }
|
||
}
|
||
@keyframes met-rotate-in {
|
||
0% { transform: rotate(-25deg) scale(0.6); opacity: 0; }
|
||
60% { transform: rotate(4deg) scale(1.05); opacity: 1; }
|
||
85% { transform: rotate(-1deg) scale(0.98); }
|
||
100% { transform: rotate(0) scale(1); opacity: 1; }
|
||
}
|
||
@keyframes met-zoom-in {
|
||
0% { transform: scale(0.1); opacity: 0; }
|
||
50% { transform: scale(1.12); opacity: 1; }
|
||
75% { transform: scale(0.94); }
|
||
100% { transform: scale(1); opacity: 1; }
|
||
}
|
||
@keyframes met-slideUp-in {
|
||
0% { transform: translateY(60px); opacity: 0; }
|
||
70% { transform: translateY(-6px); opacity: 1; }
|
||
100% { transform: translateY(0); opacity: 1; }
|
||
}
|
||
@keyframes met-slideDown-in {
|
||
0% { transform: translateY(-60px); opacity: 0; }
|
||
70% { transform: translateY(6px); opacity: 1; }
|
||
100% { transform: translateY(0); opacity: 1; }
|
||
}
|
||
@keyframes met-slideLeft-in {
|
||
0% { transform: translateX(-90px); opacity: 0; }
|
||
65% { transform: translateX(6px); opacity: 1; }
|
||
100% { transform: translateX(0); opacity: 1; }
|
||
}
|
||
@keyframes met-slideRight-in {
|
||
0% { transform: translateX(90px); opacity: 0; }
|
||
65% { transform: translateX(-6px); opacity: 1; }
|
||
100% { transform: translateX(0); opacity: 1; }
|
||
}
|
||
|
||
/* === 进入动画:绑定到 .met-show === */
|
||
.met-anim-slide.met-toast.met-show { animation: met-slide-in 0.40s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; }
|
||
.met-anim-fade.met-toast.met-show { animation: met-fade-in 0.50s ease forwards; }
|
||
.met-anim-scale.met-toast.met-show { animation: met-scale-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; }
|
||
.met-anim-bounce.met-toast.met-show { animation: met-bounce-in 0.65s ease forwards; }
|
||
.met-anim-flip.met-toast.met-show { animation: met-flip-in 0.50s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; }
|
||
.met-anim-rotate.met-toast.met-show { animation: met-rotate-in 0.50s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; }
|
||
.met-anim-zoom.met-toast.met-show { animation: met-zoom-in 0.50s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; }
|
||
.met-anim-slideUp.met-toast.met-show { animation: met-slideUp-in 0.40s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; }
|
||
.met-anim-slideDown.met-toast.met-show { animation: met-slideDown-in 0.40s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; }
|
||
.met-anim-slideLeft.met-toast.met-show { animation: met-slideLeft-in 0.40s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; }
|
||
.met-anim-slideRight.met-toast.met-show { animation: met-slideRight-in 0.40s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; }
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 480px) {
|
||
.met-container { padding: 12px !important; }
|
||
.met-toast { width: 100% !important; min-width: 0 !important; }
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.met-toast { font-size: 13px; }
|
||
.met-title { font-size: 13px; }
|
||
.met-message { font-size: 12px; }
|
||
}
|
||
|
||
@media (min-width: 1200px) {
|
||
.met-toast { width: 400px; }
|
||
}
|
||
|
||
@media (min-width: 1920px) {
|
||
.met-toast { width: 440px; }
|
||
}
|
||
|
||
@media (max-width: 320px) {
|
||
.met-toast { width: 100%; min-width: 0; padding: 12px 14px; }
|
||
.met-container { padding: 8px; }
|
||
}
|
||
|
||
@media (orientation: landscape) and (max-height: 500px) {
|
||
.met-container { padding: 12px 24px; }
|
||
.met-toast { min-height: 44px; padding: 10px 14px; }
|
||
}
|
||
|
||
@media (orientation: portrait) and (max-width: 500px) {
|
||
.met-container { padding: 12px; }
|
||
.met-toast { width: 100%; min-width: 0; }
|
||
}
|
||
|
||
/* 无障碍支持 */
|
||
.met-toast[role="alert"] { }
|
||
.met-toast[role="status"] { }
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.met-toast { transition: opacity 0.15s !important; }
|
||
.met-toast.met-show { animation: none !important; opacity: 1 !important; }
|
||
.met-spin { animation-duration: 2.5s !important; }
|
||
}
|
||
|
||
@media (forced-colors: active) {
|
||
.met-toast { border: 2px solid ButtonText; }
|
||
.met-close { border: 1px solid ButtonText; }
|
||
}
|
||
|
||
@media (prefers-contrast: high) {
|
||
.met-toast { border-width: 3px; border-style: solid; }
|
||
.met-close { border: 2px solid currentColor; border-radius: 4px; }
|
||
}
|
||
|
||
/* 焦点样式 */
|
||
.met-toast:focus-visible {
|
||
outline: 2px solid #3b82f6;
|
||
outline-offset: 2px;
|
||
}
|
||
.met-close:focus-visible {
|
||
outline: 2px solid #3b82f6;
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
/* 触摸设备优化 */
|
||
@media (hover: none) and (pointer: coarse) {
|
||
.met-toast:hover { box-shadow: inherit; }
|
||
.met-toast { min-height: 48px; }
|
||
.met-close { min-width: 48px; min-height: 48px; }
|
||
}
|
||
|
||
@media (hover: none) and (pointer: coarse) {
|
||
.met-toast { min-height: 52px; padding: 16px 18px; }
|
||
.met-close { min-width: 52px; min-height: 52px; padding: 8px; }
|
||
.met-icon { width: 28px; height: 28px; }
|
||
}
|
||
|
||
/* 打印样式 */
|
||
@media print {
|
||
.met-container { display: none !important; }
|
||
.met-toast { display: none !important; }
|
||
}
|
||
|
||
/* 全屏/画中画模式 */
|
||
:fullscreen .met-container,
|
||
:picture-in-picture .met-container {
|
||
z-index: 2147483647;
|
||
}
|
||
|
||
/* 安全区域适配 */
|
||
@supports (padding: max(0px)) {
|
||
.met-container {
|
||
padding: max(24px, env(safe-area-inset-top))
|
||
max(24px, env(safe-area-inset-right))
|
||
max(24px, env(safe-area-inset-bottom))
|
||
max(24px, env(safe-area-inset-left));
|
||
}
|
||
}
|
||
|
||
/* 按下状态 */
|
||
.met-toast:active {
|
||
transform: scale(0.98);
|
||
}
|
||
|
||
/* 类型左侧边框 */
|
||
.met-toast.met-success { border-left: 4px solid #10b981; }
|
||
.met-toast.met-error { border-left: 4px solid #ef4444; }
|
||
.met-toast.met-warning { border-left: 4px solid #f59e0b; }
|
||
.met-toast.met-info { border-left: 4px solid #3b82f6; }
|
||
.met-toast.met-loading { border-left: 4px solid #6366f1; }
|
||
|
||
/* 进度条过渡 */
|
||
.met-bar, .met-bar-v {
|
||
transition: transform 0.1s linear;
|
||
}
|
||
|
||
/* 滚动条样式 */
|
||
.met-container::-webkit-scrollbar { width: 6px; height: 6px; }
|
||
.met-container::-webkit-scrollbar-track { background: transparent; }
|
||
.met-container::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.2); border-radius: 3px; }
|
||
.met-container::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); }
|
||
|
||
/* 暗色主题特定样式 */
|
||
.met-toast.met-theme-dark {
|
||
background: rgba(28, 32, 40, 0.94);
|
||
color: #e6e8eb;
|
||
border-color: rgba(255, 255, 255, 0.08);
|
||
box-shadow: 0 10px 36px -10px rgba(0, 0, 0, 0.6), 0 4px 14px -4px rgba(0, 0, 0, 0.4);
|
||
}
|
||
.met-toast.met-theme-dark:hover {
|
||
box-shadow: 0 14px 48px -8px rgba(0, 0, 0, 0.6), 0 6px 18px -4px rgba(0, 0, 0, 0.4) !important;
|
||
}
|
||
.met-toast.met-theme-dark .met-close:hover {
|
||
background: rgba(255, 255, 255, 0.08);
|
||
}
|
||
.met-toast.met-theme-dark .met-progress,
|
||
.met-toast.met-theme-dark .met-progress-v {
|
||
background: rgba(255, 255, 255, 0.08);
|
||
}
|
||
|
||
/* 亮色主题特定样式 */
|
||
.met-toast.met-theme-light {
|
||
background: rgba(255, 255, 255, 0.96);
|
||
color: #1f2937;
|
||
border-color: rgba(0, 0, 0, 0.06);
|
||
box-shadow: 0 10px 36px -10px rgba(0, 0, 0, 0.18), 0 4px 14px -4px rgba(0, 0, 0, 0.08);
|
||
}
|
||
.met-toast.met-theme-light:hover {
|
||
box-shadow: 0 14px 48px -10px rgba(0, 0, 0, 0.22), 0 6px 18px -4px rgba(0, 0, 0, 0.10) !important;
|
||
}
|
||
.met-toast.met-theme-light .met-close:hover {
|
||
background: rgba(0, 0, 0, 0.06);
|
||
}
|
||
.met-toast.met-theme-light .met-progress,
|
||
.met-toast.met-theme-light .met-progress-v {
|
||
background: rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
/* 自定义主题支持 */
|
||
.met-toast[data-theme] {
|
||
--met-bg: var(--met-theme-bg);
|
||
--met-text: var(--met-theme-text);
|
||
--met-border: var(--met-theme-border);
|
||
--met-shadow: var(--met-theme-shadow);
|
||
}
|
||
|
||
/* 暗色模式自动检测 */
|
||
@media (prefers-color-scheme: dark) {
|
||
.met-theme-auto .met-toast {
|
||
background: rgba(28, 32, 40, 0.94);
|
||
color: #e6e8eb;
|
||
border-color: rgba(255, 255, 255, 0.08);
|
||
box-shadow: 0 10px 36px -10px rgba(0, 0, 0, 0.6), 0 4px 14px -4px rgba(0, 0, 0, 0.4);
|
||
}
|
||
.met-theme-auto .met-toast:hover {
|
||
box-shadow: 0 14px 48px -8px rgba(0, 0, 0, 0.6), 0 6px 18px -4px rgba(0, 0, 0, 0.4) !important;
|
||
}
|
||
.met-theme-auto .met-close:hover { background: rgba(255, 255, 255, 0.08); }
|
||
.met-theme-auto .met-progress,
|
||
.met-theme-auto .met-progress-v { background: rgba(255, 255, 255, 0.08); }
|
||
}
|
||
|
||
@media (prefers-color-scheme: light) {
|
||
.met-theme-auto .met-toast {
|
||
background: rgba(255, 255, 255, 0.96);
|
||
color: #1f2937;
|
||
border-color: rgba(0, 0, 0, 0.06);
|
||
box-shadow: 0 10px 36px -10px rgba(0, 0, 0, 0.18), 0 4px 14px -4px rgba(0, 0, 0, 0.08);
|
||
}
|
||
.met-theme-auto .met-toast:hover {
|
||
box-shadow: 0 14px 48px -10px rgba(0, 0, 0, 0.22), 0 6px 18px -4px rgba(0, 0, 0, 0.10) !important;
|
||
}
|
||
.met-theme-auto .met-close:hover { background: rgba(0, 0, 0, 0.06); }
|
||
.met-theme-auto .met-progress,
|
||
.met-theme-auto .met-progress-v { background: rgba(0, 0, 0, 0.06); }
|
||
}
|
||
`;
|
||
};
|
||
|
||
/**
|
||
* 注入样式
|
||
*/
|
||
export const injectStyles = (theme = THEMES.light) => {
|
||
if (typeof document === 'undefined') return;
|
||
|
||
if (styleElement && document.getElementById('metona-toast-styles')) {
|
||
return;
|
||
}
|
||
|
||
const css = generateCSS(theme);
|
||
|
||
styleElement = document.createElement('style');
|
||
styleElement.id = 'metona-toast-styles';
|
||
styleElement.textContent = css.replace(/\s+/g, ' ');
|
||
|
||
document.head.appendChild(styleElement);
|
||
};
|
||
|
||
/**
|
||
* 更新样式
|
||
*/
|
||
export const updateStyles = (theme) => {
|
||
if (!styleElement) {
|
||
injectStyles(theme);
|
||
return;
|
||
}
|
||
|
||
const css = generateCSS(theme);
|
||
styleElement.textContent = css.replace(/\s+/g, ' ');
|
||
};
|
||
|
||
/**
|
||
* 移除样式
|
||
*/
|
||
export const removeStyles = () => {
|
||
if (styleElement && styleElement.parentNode) {
|
||
styleElement.parentNode.removeChild(styleElement);
|
||
}
|
||
|
||
styleElement = null;
|
||
};
|
||
|
||
/**
|
||
* 生成主题CSS变量
|
||
*/
|
||
export const generateThemeVariables = (theme) => {
|
||
return `
|
||
:root {
|
||
--met-theme-bg: ${theme.bg};
|
||
--met-theme-text: ${theme.text};
|
||
--met-theme-border: ${theme.border};
|
||
--met-theme-shadow: ${theme.shadow};
|
||
--met-theme-hover-shadow: ${theme.hoverShadow};
|
||
--met-theme-progress-bg: ${theme.progressBg};
|
||
--met-theme-close-hover-bg: ${theme.closeHoverBg};
|
||
}
|
||
`;
|
||
};
|
||
|
||
/**
|
||
* 应用主题变量
|
||
*/
|
||
export const applyThemeVariables = (theme) => {
|
||
if (typeof document === 'undefined') return;
|
||
|
||
const css = generateThemeVariables(theme);
|
||
const customStyle = document.createElement('style');
|
||
customStyle.id = 'metona-toast-custom-styles';
|
||
customStyle.textContent = css;
|
||
document.head.appendChild(customStyle);
|
||
};
|
||
|
||
/**
|
||
* 清除主题变量
|
||
*/
|
||
export const clearThemeVariables = () => {
|
||
const customStyle = document.getElementById('metona-toast-custom-styles');
|
||
if (customStyle && customStyle.parentNode) {
|
||
customStyle.parentNode.removeChild(customStyle);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 获取系统主题
|
||
*/
|
||
export const getSystemTheme = () => {
|
||
if (typeof window === 'undefined') return 'light';
|
||
|
||
return window.matchMedia &&
|
||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||
? 'dark'
|
||
: 'light';
|
||
};
|
||
|
||
/**
|
||
* 监听系统主题变化
|
||
*/
|
||
export const watchSystemTheme = (callback) => {
|
||
if (typeof window === 'undefined' || !window.matchMedia) {
|
||
return () => {};
|
||
}
|
||
|
||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||
|
||
const handler = (e) => {
|
||
callback(e.matches ? 'dark' : 'light');
|
||
};
|
||
|
||
mediaQuery.addEventListener('change', handler);
|
||
|
||
return () => {
|
||
mediaQuery.removeEventListener('change', handler);
|
||
};
|
||
};
|
||
|
||
/**
|
||
* 自动应用系统主题
|
||
*/
|
||
export const autoApplySystemTheme = () => {
|
||
const applyTheme = (theme) => {
|
||
updateStyles(THEMES[theme]);
|
||
applyThemeVariables(THEMES[theme]);
|
||
};
|
||
|
||
applyTheme(getSystemTheme());
|
||
|
||
return watchSystemTheme(applyTheme);
|
||
};
|