Skip to content

Instantly share code, notes, and snippets.

@Bouke
Last active May 10, 2025 05:10
Show Gist options
  • Save Bouke/69bdff2dbeb4b417b826ea693c721dce to your computer and use it in GitHub Desktop.
Save Bouke/69bdff2dbeb4b417b826ea693c721dce to your computer and use it in GitHub Desktop.
Detects system theme changes and selects the appropriate theme on Azure DevOps.
// ==UserScript==
// @name Azure Devops System Theme Switcher
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Detects system theme changes and selects the appropriate theme on Azure DevOps.
// @author Bouke / llama3.3
// @match https://dev.azure.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
function clickElement(selector) {
const element = document.querySelector(selector);
if (element) {
element.click();
}
}
async function waitForElement(selector) {
while (!document.querySelector(selector)) {
await new Promise(resolve => setTimeout(resolve, 10));
}
return document.querySelector(selector);
}
async function handleThemeChange(isDarkMode) {
clickElement('button[aria-label="User settings"]');
const themeLink = await waitForElement('#__bolt-changeThemeLink-text');
themeLink.click();
if (isDarkMode) {
const darkThemeButton = await waitForElement('#theme-ms-vss-web-vsts-theme-dark');
darkThemeButton.click();
} else {
const lightThemeButton = await waitForElement('#theme-ms-vss-web-vsts-theme');
lightThemeButton.click();
}
const closeButton = await waitForElement('.theme-panel button[aria-label="Close"]');
closeButton.click();
}
function getCurrentTheme() {
const body = document.body;
if (body.hasAttribute('data-theme')) {
return body.getAttribute('data-theme') === 'ms.vss-web.vsts-theme-dark' ? 'dark' : 'light';
} else {
return body.classList.contains('ms-vss-web-vsts-theme-dark') ? 'dark' : 'light';
}
}
const mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');
const isSystemDark = mediaQueryList.matches;
const currentTheme = getCurrentTheme();
if ((isSystemDark && currentTheme !== 'dark') || (!isSystemDark && currentTheme !== 'light')) {
handleThemeChange(isSystemDark);
}
mediaQueryList.addListener((e) => {
const newCurrentTheme = getCurrentTheme();
if ((e.matches && newCurrentTheme !== 'dark') || (!e.matches && newCurrentTheme !== 'light')) {
handleThemeChange(e.matches);
}
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment