0% found this document useful (0 votes)
4 views

code.js

This document outlines a user script for a dark mode toggle button that includes SVG icons and customizable UI settings. It allows users to switch between light and dark modes on any webpage, with options to adjust the button's position and offsets. The script utilizes the DarkReader library for dark mode functionality and stores user preferences using GM storage methods.

Uploaded by

cerwlum
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

code.js

This document outlines a user script for a dark mode toggle button that includes SVG icons and customizable UI settings. It allows users to switch between light and dark modes on any webpage, with options to adjust the button's position and offsets. The script utilizes the DarkReader library for dark mode functionality and stores user preferences using GM storage methods.

Uploaded by

cerwlum
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 6

// ==UserScript==

// @name ☀️Dark Mode Toggle


// @author Cervantes Wu
// @description Dark mode toggle button with SVG icons and UI for customization.
// @namespace darkmode.toggle
// @version 1.4.3
// @match *://*/*
// @exclude devtools://*
// @grant GM.getValue
// @grant GM.setValue
// @grant GM.addStyle
// @require https://unpkg.com/[email protected]/darkreader.js
// ==/UserScript==

(function() {
'use strict';

// Constants
const BUTTON_ID = 'darkModeToggle';
const UI_ID = 'darkModeToggleUI';
const TOGGLE_UI_BUTTON_ID = 'toggleDarkModeUIButton';

// 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>`;

// Default Settings
const defaultSettings = {
position: 'bottom-right',
offsetX: 30,
offsetY: 30,
};

let settings = { ...defaultSettings };


let uiVisible = false; // Track UI visibility

// Load settings from GM storage


async function loadSettings() {
const storedSettings = await GM.getValue('settings', defaultSettings);
settings = { ...defaultSettings, ...storedSettings }; // Merge with
defaults
updateButtonPosition();
}

// Save settings to GM storage


async function saveSettings() {
await GM.setValue('settings', settings);
updateButtonPosition();
}
// Styles (Injected via GM.addStyle for better compatibility)
GM.addStyle(`
#${BUTTON_ID} {
width: 80px;
height: 40px;
background-color: #fff;
border-radius: 20px;
border: none;
cursor: pointer;
z-index: 1000;
opacity: 0.8;
transition-property: transform, opacity, box-shadow, background-color;
transition-duration: 0.3s;
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1), ease,
ease, ease;
display: flex;
align-items: center;
padding: 0 4px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
position: fixed; /* Make sure it's fixed */
}

#${BUTTON_ID}:hover {
opacity: 1;
transform: scale(1.1);
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275),
box-shadow 0.2s;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
}

#${BUTTON_ID}::before {
content: '';
width: 32px;
height: 32px;
border-radius: 50%;
transition-property: transform, background-color, -webkit-mask-image,
mask-image;
transition-duration: 0.3s;
transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55),
ease, ease, ease;
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;
-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;
}

#${BUTTON_ID}.dark {
background-color: #000;
}
#${BUTTON_ID}.dark::before {
transform: translateX(40px);
color: #ffeb3b;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
background: none;
-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;
}

/* UI Styles */
#${UI_ID} {
position: fixed;
top: 20px;
left: 20px;
background-color: #f7f7f7; /* Lighter background */
border: 1px solid #ddd; /* Lighter border */
padding: 15px; /* Slightly larger padding */
z-index: 1001;
border-radius: 8px; /* Rounded corners */
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* Softer shadow */
display: none; /* Initially hidden */
color: #444; /* Darker, more readable text */
font-family: sans-serif; /* Modern font */
}

#${UI_ID}.visible {
display: block; /* Show when visible class is added */
}

#${UI_ID} label {
display: block;
margin-bottom: 8px; /* More space below labels */
font-weight: 500; /* Slightly bolder labels */
}

#${UI_ID} select, #${UI_ID} input[type="number"] {


margin-bottom: 12px; /* More space below inputs */
padding: 8px; /* Padding inside inputs */
border: 1px solid #ccc;
border-radius: 4px;
color: #555; /* Darker text in inputs */
width: 150px; /* Set a fixed width for inputs/selects */
}

/* Toggle UI Button Styles */


#${TOGGLE_UI_BUTTON_ID} {
position: fixed;
top: 50%; /* Vertical centering */
right: 0; /* Distance from right edge */
transform: translateY(-50%) rotate(-90deg); /* Rotate and center */
background-color: #ddd;
border: 1px solid #ccc;
padding: 8px 12px; /* Adjusted padding */
z-index: 1002;
border-radius: 5px;
cursor: pointer;
color: #444; /* More readable color */
font-size: 14px; /* Slightly smaller font */
white-space: nowrap; /* Prevent text wrapping */
}

#${TOGGLE_UI_BUTTON_ID}:hover {
background-color: #eee;
}
`);

// Create toggle button


function createToggleButton() {
const button = document.createElement('button');
button.id = BUTTON_ID;
document.body.appendChild(button);
button.addEventListener('click', toggleDarkMode);
updateButtonPosition(); // Initial position update
}

// Update Button Position based on settings


function updateButtonPosition() {
const button = document.getElementById(BUTTON_ID);
if (!button) return; // Button might not be created yet.

const { position, offsetX, offsetY } = settings;

button.style.bottom = '';
button.style.top = '';
button.style.left = '';
button.style.right = '';

switch (position) {
case 'top-left':
button.style.top = `${offsetY}px`;
button.style.left = `${offsetX}px`;
break;
case 'top-right':
button.style.top = `${offsetY}px`;
button.style.right = `${offsetX}px`;
break;
case 'bottom-left':
button.style.bottom = `${offsetY}px`;
button.style.left = `${offsetX}px`;
break;
case 'bottom-right':
default:
button.style.bottom = `${offsetY}px`;
button.style.right = `${offsetX}px`;
break;
}
}

// 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');
}
}

// Create UI
function createUI() {
const ui = document.createElement('div');
ui.id = UI_ID;

// Position Selector
const positionLabel = document.createElement('label');
positionLabel.textContent = 'Position:';
const positionSelect = document.createElement('select');
const positions = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
positions.forEach(pos => {
const option = document.createElement('option');
option.value = pos;
option.textContent = pos;
option.selected = settings.position === pos;
positionSelect.appendChild(option);
});
positionSelect.addEventListener('change', (e) => {
settings.position = e.target.value;
saveSettings();
});
ui.appendChild(positionLabel);
ui.appendChild(positionSelect);

// Offset X
const offsetXLabel = document.createElement('label');
offsetXLabel.textContent = 'Offset X:';
const offsetXInput = document.createElement('input');
offsetXInput.type = 'number';
offsetXInput.value = settings.offsetX;
offsetXInput.addEventListener('change', (e) => {
settings.offsetX = parseInt(e.target.value);
saveSettings();
});
ui.appendChild(offsetXLabel);
ui.appendChild(offsetXInput);

// Offset Y
const offsetYLabel = document.createElement('label');
offsetYLabel.textContent = 'Offset Y:';
const offsetYInput = document.createElement('input');
offsetYInput.type = 'number';
offsetYInput.value = settings.offsetY;
offsetYInput.addEventListener('change', (e) => {
settings.offsetY = parseInt(e.target.value);
saveSettings();
});
ui.appendChild(offsetYLabel);
ui.appendChild(offsetYInput);

document.body.appendChild(ui);
}

// Create a button to toggle the UI


function createToggleUIButton() {
const toggleUIButton = document.createElement('button');
toggleUIButton.id = TOGGLE_UI_BUTTON_ID;
toggleUIButton.textContent = 'Settings'; // Shorter, more appropriate text
toggleUIButton.addEventListener('click', toggleUI);
document.body.appendChild(toggleUIButton);
}

// Toggle the visibility of the settings UI


function toggleUI() {
const ui = document.getElementById(UI_ID);
uiVisible = !uiVisible;
if (uiVisible) {
ui.classList.add('visible');
} else {
ui.classList.remove('visible');
}
}

// Initialize dark mode based on stored preference


async function init() {
await loadSettings(); // Load settings first!
createToggleButton(); // Then create the button
createUI(); // Create the UI
createToggleUIButton(); // Button to toggle UI

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