0% found this document useful (0 votes)
9 views3 pages

Dark Mode Toggle - Js

The document is a user script for a dark mode toggle button that enhances user experience with animated SVG icons. It includes functionality to switch between dark and light modes, stores user preferences, and allows for hotkey support. The script utilizes the DarkReader library to apply dark mode styles and provides a visually appealing button interface.

Uploaded by

cerwlum
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views3 pages

Dark Mode Toggle - Js

The document is a user script for a dark mode toggle button that enhances user experience with animated SVG icons. It includes functionality to switch between dark and light modes, stores user preferences, and allows for hotkey support. The script utilizes the DarkReader library to apply dark mode styles and provides a visually appealing button interface.

Uploaded by

cerwlum
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 3

// ==UserScript==

// @name Dark Mode Toggle


// @author Cervantes Wu
// @description Enhanced animated dark mode toggle button with SVG icons.
// @namespace enhanced.animated.darkmode.toggle
// @version 1.3.0
// @match *://*/*
// @exclude devtools://*
// @grant GM.getValue
// @grant GM.setValue
// @require https://unpkg.com/[email protected]/darkreader.js
// ==/UserScript==

(function() {
'use strict';

// Constants
const BUTTON_ID = 'darkModeToggle';

// SVG Icons
const moonIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-
linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21
12.79z"></path></svg>`;
const sunIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-
linejoin="round"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1"
x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22"
y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78"
y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12"
x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line
x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>`;

// Styles
const style = document.createElement('style');
style.textContent = `
#${BUTTON_ID} {
position: fixed;
bottom: 30px;
right: 30px;
width: 80px;
height: 40px;
background-color: #fff;
border-radius: 20px;
border: none;
cursor: pointer;
z-index: 1000;
opacity: 0.8;
/* 明確指定要動畫的屬性,並調整 easing */
transition-property: transform, opacity, box-shadow, background-color;
transition-duration: 0.3s; /* Reduced duration for snappier feel */
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1), ease,
ease, ease; /* More bouncy cubic-bezier */
display: flex;
align-items: center;
padding: 0 4px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
}
#${BUTTON_ID}:hover {
opacity: 1;
/* 使用 translate, 並調整 scale 的 easing */
transform: scale(1.1);
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275),
box-shadow 0.2s; /* 調整 hover transition */
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
}

#${BUTTON_ID}::before {
content: ''; /* Remove text content */
width: 32px;
height: 32px;
border-radius: 50%;
/* 明確指定要動畫的屬性,並調整 easing */
transition-property: transform, background-color, -webkit-mask-image,
mask-image;
transition-duration: 0.3s; /* Reduced duration for snappier feel */
transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55),
ease, ease, ease; /* "Overshoot" cubic-bezier */
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
color: #333;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
background: none;
/* Add SVG as background */
-webkit-mask-image: url('data:image/svg+xml;utf8,${moonIcon}');
mask-image: url('data:image/svg+xml;utf8,${moonIcon}');
-webkit-mask-size: cover;
mask-size: cover;
background-color: #333; /* Set moon color */
}

#${BUTTON_ID}.dark {
background-color: #000;
}

#${BUTTON_ID}.dark::before {
/* 使用 translate,而非 left/right */
transform: translateX(40px);
/* content: '☀️'; Remove text content */
color: #ffeb3b;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
background: none;
/* Add SVG as background */
-webkit-mask-image: url('data:image/svg+xml;utf8,${sunIcon}');
mask-image: url('data:image/svg+xml;utf8,${sunIcon}');
-webkit-mask-size: cover;
mask-size: cover;
background-color: #fff; /* Set sun color */
}
`;
document.head.appendChild(style);

// Create toggle button


function createToggleButton() {
const button = document.createElement('button');
button.id = BUTTON_ID;
document.body.appendChild(button);

button.addEventListener('click', toggleDarkMode);
}

// Toggle dark mode function


async function toggleDarkMode() {
const isDark = await GM.getValue('darkMode', false);
const button = document.getElementById(BUTTON_ID);

if (isDark) {
DarkReader.disable();
await GM.setValue('darkMode', false);
button.classList.remove('dark');
} else {
DarkReader.enable({
brightness: 100,
contrast: 90,
sepia: 10
});
await GM.setValue('darkMode', true);
button.classList.add('dark');
}
}

// Initialize dark mode based on stored preference


async function init() {
createToggleButton();

const isDark = await GM.getValue('darkMode', false);


const button = document.getElementById(BUTTON_ID);

if (isDark) {
DarkReader.enable({
brightness: 100,
contrast: 90,
sepia: 10
});
button.classList.add('dark');
}
}

// Add hotkey support (Command + Shift + B)


document.addEventListener('keyup', function(e) {
if (e.metaKey && e.shiftKey && e.which === 66) {
toggleDarkMode();
}
});

init();
})();

You might also like