Skip to content

Commit 1181d53

Browse files
committed
Add dark mode support for toolbar icons
Toolbar icons now switch between light (black) and dark (white) variants based on system appearance. Safari extension background scripts don't have access to window.matchMedia, so color scheme detection happens in the popup which has proper DOM access. The popup sends the color scheme to the background script on open. Also adds colored pixels to icons to prevent Safari's accent color tinting which affects uniform grayscale/solid-color icons. Icon sets: - icon-light-*.png: Black cloud for light mode - icon-dark-*.png: White cloud for dark mode - icon-pending-light-*.png: Black cloud with ? for light mode - icon-pending-dark-*.png: White cloud with ? for dark mode Known limitation: Icons update when popup is opened, not automatically when system appearance changes (documented in KNOWN_ISSUES.md).
1 parent 12a1f55 commit 1181d53

30 files changed

+108
-22
lines changed

CF Cache Status/CF Cache Status Extension/Resources/background.js

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,47 @@
99
// Icon Paths
1010
// =============================================================================
1111

12-
const DEFAULT_ICON = {
13-
16: 'images/icon-16.png',
14-
32: 'images/icon-32.png',
15-
48: 'images/icon-48.png',
16-
128: 'images/icon-128.png'
12+
const ICONS = {
13+
light: {
14+
16: 'images/icon-light-16.png',
15+
32: 'images/icon-light-32.png',
16+
48: 'images/icon-light-48.png',
17+
128: 'images/icon-light-128.png'
18+
},
19+
dark: {
20+
16: 'images/icon-dark-16.png',
21+
32: 'images/icon-dark-32.png',
22+
48: 'images/icon-dark-48.png',
23+
128: 'images/icon-dark-128.png'
24+
},
25+
pendingLight: {
26+
16: 'images/icon-pending-light-16.png',
27+
32: 'images/icon-pending-light-32.png',
28+
48: 'images/icon-pending-light-48.png',
29+
128: 'images/icon-pending-light-128.png'
30+
},
31+
pendingDark: {
32+
16: 'images/icon-pending-dark-16.png',
33+
32: 'images/icon-pending-dark-32.png',
34+
48: 'images/icon-pending-dark-48.png',
35+
128: 'images/icon-pending-dark-128.png'
36+
}
1737
};
1838

19-
const PENDING_ICON = {
20-
16: 'images/icon-pending-16.png',
21-
32: 'images/icon-pending-32.png',
22-
48: 'images/icon-pending-48.png',
23-
128: 'images/icon-pending-128.png'
24-
};
39+
/** Cached color scheme (updated by popup which has DOM access) */
40+
let cachedIsDark = false;
41+
42+
function isDarkMode() {
43+
return cachedIsDark;
44+
}
45+
46+
function getDefaultIcon() {
47+
return isDarkMode() ? ICONS.dark : ICONS.light;
48+
}
49+
50+
function getPendingIcon() {
51+
return isDarkMode() ? ICONS.pendingDark : ICONS.pendingLight;
52+
}
2553

2654
// =============================================================================
2755
// State Management
@@ -55,13 +83,14 @@ function updateBadge(tabId, status) {
5583
const badgeText = status ? (badgeTextMap[status.toUpperCase()] || status) : '';
5684
const color = status === 'HIT' ? '#34C759' : status === 'MISS' ? '#FF3B30' : '#8E8E93';
5785

58-
// Reset to default icon
59-
browser.action.setIcon({ path: DEFAULT_ICON });
86+
// Reset to default icon (respects dark/light mode)
87+
const icon = getDefaultIcon();
88+
browser.action.setIcon({ path: icon });
6089
browser.action.setBadgeText({ text: badgeText });
6190
browser.action.setBadgeBackgroundColor({ color });
6291

6392
try {
64-
browser.action.setIcon({ path: DEFAULT_ICON, tabId });
93+
browser.action.setIcon({ path: icon, tabId });
6594
browser.action.setBadgeText({ text: badgeText, tabId });
6695
browser.action.setBadgeBackgroundColor({ color, tabId });
6796
} catch (e) {
@@ -70,19 +99,21 @@ function updateBadge(tabId, status) {
7099
}
71100

72101
function clearBadge(tabId) {
73-
browser.action.setIcon({ path: DEFAULT_ICON });
102+
const icon = getDefaultIcon();
103+
browser.action.setIcon({ path: icon });
74104
browser.action.setBadgeText({ text: '' });
75105
try {
76-
browser.action.setIcon({ path: DEFAULT_ICON, tabId });
106+
browser.action.setIcon({ path: icon, tabId });
77107
browser.action.setBadgeText({ text: '', tabId });
78108
} catch (e) {}
79109
}
80110

81111
function showPendingIcon(tabId) {
82-
browser.action.setIcon({ path: PENDING_ICON });
112+
const icon = getPendingIcon();
113+
browser.action.setIcon({ path: icon });
83114
browser.action.setBadgeText({ text: '' });
84115
try {
85-
browser.action.setIcon({ path: PENDING_ICON, tabId });
116+
browser.action.setIcon({ path: icon, tabId });
86117
browser.action.setBadgeText({ text: '', tabId });
87118
} catch (e) {}
88119
}
@@ -273,6 +304,14 @@ browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
273304
sendResponse(tabData.get(message.tabId) || null);
274305
}
275306

307+
if (message.type === 'colorScheme') {
308+
const changed = cachedIsDark !== message.isDark;
309+
cachedIsDark = message.isDark;
310+
if (changed) {
311+
updateAllTabIcons();
312+
}
313+
}
314+
276315
if (message.type === 'performanceData' && sender.tab) {
277316
const existing = tabData.get(sender.tab.id);
278317
if (existing) {
@@ -314,3 +353,28 @@ browser.runtime.onConnect.addListener((port) => {
314353
}
315354
});
316355
});
356+
357+
// --- Color Scheme Handling ---
358+
359+
async function updateAllTabIcons() {
360+
try {
361+
const tabs = await browser.tabs.query({});
362+
for (const tab of tabs) {
363+
const data = tabData.get(tab.id);
364+
if (data) {
365+
if (data.noHeaders) {
366+
showPendingIcon(tab.id);
367+
} else {
368+
updateBadge(tab.id, data.status);
369+
}
370+
}
371+
}
372+
// Also update the default icon for tabs without data
373+
browser.action.setIcon({ path: getDefaultIcon() });
374+
} catch (e) {
375+
// Ignore errors
376+
}
377+
}
378+
379+
// Note: Color scheme detection happens via popup.js which has DOM access.
380+
// The popup sends a 'colorScheme' message when opened, updating cachedIsDark.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2.25 KB
Loading
385 Bytes
Loading
690 Bytes
Loading
961 Bytes
Loading
2.4 KB
Loading

0 commit comments

Comments
 (0)