Bug-2001318 example showing SVG icon reacting to theme (#620)

* Bug-2001318 example showing SVG icon reacting to theme

* Updates for feedback
This commit is contained in:
rebloor
2026-03-12 04:42:31 +13:00
committed by GitHub
parent 7619dac607
commit f4d0193956
7 changed files with 177 additions and 0 deletions

View File

@@ -548,6 +548,11 @@
"javascript_apis": ["management.getAll", "management.setEnabled"],
"name": "theme-switcher"
},
{
"description": "Demonstration of how to use the <code>prefers-color-scheme</code> media query to adapt an SVG icon to dark and light themes.",
"javascript_apis": ["runtime.getURL","tabs.query", "tabs.create", "tabs.update", "management.getAll","management.setEnabled","management.onEnabled", "pageAction.onClicked","action.onClicked"],
"name": "themed-icons"
},
{
"description": "A collection of themes illustrating:<ul><li>weta_fade: a basic theme employing a single image specified in <code>theme_frame:</code>.</li><li>weta_fade_chrome: the weta_fade theme implemented with Chrome compatible manifest keys.</li><li>weta_tiled: a theme using a tiled image.</li><li>weta_mirror: a theme using multiple images and aligning those images in the header.</li><li>animated: use of an animated PNG.</li></ul>",
"javascript_apis": [],

27
themed-icons/README.md Normal file
View File

@@ -0,0 +1,27 @@
# themed-icons
This example demonstrates how to use the prefers-color-scheme media query to adapt an SVG icon to dark and light themes.
## What it does
This extension includes:
* a background script, `background.js`.
* page (address bar) and browser (toolbar) action icons.
The extension displays the [page action](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/pageAction) on any webpage, and the extension test page, which the extension opens when it starts, and the [browser action](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/browserAction) is pinned to the toolbar when the extension is installed.
Clicking either icon opens the test extension page and switches to the next available theme.
When the active theme is enabled, the page and browser action change color based on the dark or light background color used in the UI.
For example:
- When the built-in Firefox Alpenglow or dark themes are active, the icons are black with a white outline.
- When the built-in Firefox light theme is active, the icons are red with a black outline.
## NOTE: Implicit CSS filter applied to pageAction SVG icons in dark themes in Firefox Desktop 151 and earlier
In builds where the `about:config` preference `extensions.webextensions.pageActionIconDarkModeFilter.enabled` is set to `true` or not defined, a greyscale and brightness CSS filter is applied to page action icons for dark themes. This filter can reduce the contrast of icons that use multiple colors, see [Bug 2001318](https://bugzilla.mozilla.org/2001318).
This implicit CSS filter is turned off in Firefox Desktop Nightly in release 149 and later, and on the release channel
as part of [Bug 2016509](https://bugzilla.mozilla.org/2016509)

View File

@@ -0,0 +1,34 @@
async function openOrSelectTab(reloadExistingTab = false) {
const tabUrl = browser.runtime.getURL("/extpage.html");
let [tab] = await browser.tabs.query({ url: tabUrl });
if (!tab) {
await browser.tabs.create({ url: tabUrl, active: true });
} else {
await browser.tabs.update(tab.id, {
active: true,
...(reloadExistingTab ? { url: tabUrl } : {})
});
}
}
async function switchToNextTheme() {
openOrSelectTab();
const themes = await browser.management.getAll().then(extensions => {
return extensions.filter(ext => ext.type === "theme");
});
const activeThemeIndex = themes.findIndex(theme => theme.enabled);
const nextThemeIndex = activeThemeIndex < themes.length - 1
? activeThemeIndex + 1
: 0
const nextTheme = themes[nextThemeIndex];
await browser.management.setEnabled(nextTheme.id, true);
}
// Switch to the next theme available on pageAction or action icons clicks.
browser.pageAction.onClicked.addListener(switchToNextTheme);
browser.action.onClicked.addListener(switchToNextTheme);
// Open the the extension page in a new tab after the add-on is installed.
browser.runtime.onInstalled.addListener(() => {
openOrSelectTab(true);
});

32
themed-icons/extpage.html Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<title>SVG themed icon using prefer-color-scheme media query</title>
<script defer="true" src="extpage.js"></script>
<style>
dt { font-weight: bold; }
body {
background-color: white;
color: black;
}
@media (prefers-color-scheme: dark) {
body {
background-color: black;
color: white;
}
}
</style>
</head>
<body>
<h1>SVG themed icon using prefer-color-scheme media query</h1>
<dl>
<dt>Active theme:</dt>
<dd id="active-theme">ACTIVE THEME INFO</dd>
</dl>
<h2>README.md</h2>
<pre id="read-me">README.md content</pre>
</body>
</html>

29
themed-icons/extpage.js Normal file
View File

@@ -0,0 +1,29 @@
let activeThemeEl = document.querySelector("#active-theme");
let readmeEl = document.querySelector("#read-me");
function updateThemeInfo(info) {
activeThemeEl.textContent = `${info.name} (${info.id})`;
}
// Include the README.md file content into the test page.
fetch("/README.md").then(r => r.text()).then(text => {
readmeEl.textContent = text;
});
// Set active theme info element content on page load.
browser.management.getAll().then(addons => {
updateThemeInfo(addons.find(addon => addon.type == "theme" && addon.enabled));
});
// Show pageAction icon on the extension page.
browser.tabs.getCurrent().then(tabInfo => {
browser.pageAction.show(tabInfo.id);
});
// Update active theme info when a theme is enabled.
browser.management.onEnabled.addListener(info => {
if (info.type !== "theme") {
return;
}
updateThemeInfo(info);
});

View File

@@ -0,0 +1,37 @@
{
"description": "Adds page action and action SVG icons that adapt to dark and light themes using prefers-color-scheme media query.",
"manifest_version": 3,
"name": "themed-icons",
"version": "1.0",
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/themed-icons",
"browser_specific_settings": {
"gecko": {
"id": "themed-icons@mozilla.org",
"data_collection_permissions": {
"required": ["none"]
}
}
},
"icons": { "32": "prefers-color-scheme-icon.svg" },
"background": {
"scripts": ["background.js"],
"type": "module"
},
"page_action": {
"default_icon": "prefers-color-scheme-icon.svg",
"show_matches": ["<all_urls>"]
},
"action": {
"default_icon": "prefers-color-scheme-icon.svg",
"default_area": "navbar"
},
"permissions": [
"management"
]
}

View File

@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<style>
#outside { fill: black; }
#inside { fill: red; }
@media (prefers-color-scheme: dark) {
#outside { fill: white; }
#inside { fill: black; }
}
</style>
<rect id="outside" width="16" height="16" />
<rect id="inside" x="4" y="4" width="8" height="8" />
</svg>

After

Width:  |  Height:  |  Size: 384 B