├── .gitignore ├── assets └── screenshot.png ├── README.md ├── web-ext-config.js ├── src ├── manifest.json ├── img │ └── containers.svg └── background.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonathanKingston/containers-theme/HEAD/assets/screenshot.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Containers theme 2 | 3 | Changes the current browser window theme to match the colour of the active tab. 4 | 5 | ![Screnshot showing different themes](assets/screenshot.png) 6 | 7 | Yes the theme is too bright for most, there is a [Firefox bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1401924) preventing this shipping. 8 | -------------------------------------------------------------------------------- /web-ext-config.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const defaultConfig = { 4 | // Global options: 5 | sourceDir: "./src/", 6 | artifactsDir: "./dist/", 7 | ignoreFiles: [".DS_Store"], 8 | // Command options: 9 | build: { 10 | overwriteDest: true, 11 | }, 12 | run: { 13 | firefox: "nightly", 14 | browserConsole: true, 15 | startUrl: ["about:debugging"], 16 | pref: [], 17 | }, 18 | }; 19 | 20 | module.exports = defaultConfig; 21 | 22 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "background": { 3 | "scripts": ["background.js"] 4 | }, 5 | "permissions": [ 6 | "cookies", 7 | "storage", 8 | "theme", 9 | "contextualIdentities", 10 | "", 11 | "tabs" 12 | ], 13 | "applications": { 14 | "gecko": { 15 | "strict_min_version": "57.0a1" 16 | } 17 | }, 18 | "icons": { 19 | "96": "img/containers.svg" 20 | }, 21 | "description": "Change theme colour based on your container color", 22 | "manifest_version": 2, 23 | "name": "Containers theme", 24 | "version": "1.0.4" 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "containers-theme", 3 | "version": "1.0.4", 4 | "description": "Changes the current browser window theme to match the colour of the active tab.", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "build": "web-ext build" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/jonathanKingston/containers-theme.git" 12 | }, 13 | "author": "Jonathan Kingston", 14 | "license": "MPL-2.0", 15 | "bugs": { 16 | "url": "https://github.com/jonathanKingston/containers-theme/issues" 17 | }, 18 | "homepage": "https://github.com/jonathanKingston/containers-theme#readme" 19 | } 20 | -------------------------------------------------------------------------------- /src/img/containers.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/background.js: -------------------------------------------------------------------------------- 1 | class containersTheme { 2 | constructor() { 3 | browser.runtime.getBrowserInfo().then(info => { 4 | const version = info.version.match(/^(\d+)/); 5 | this.useThemePropertiesWhenOlderThanFirefox65 = (version < 65); 6 | 7 | browser.tabs.onActivated.addListener(() => { 8 | this.getCurrentContainer(); 9 | }); 10 | browser.windows.onFocusChanged.addListener(() => { 11 | this.getCurrentContainer(); 12 | }); 13 | 14 | this.getCurrentContainer(); 15 | }); 16 | } 17 | 18 | async getCurrentContainer() { 19 | const activeTabs = await browser.tabs.query({ 20 | active: true 21 | }); 22 | 23 | const containers = await this.getContainers(); 24 | 25 | activeTabs.forEach((tab) => { 26 | const cookieStoreId = tab.cookieStoreId; 27 | if (!this.isUnpaintedTheme(cookieStoreId)) { 28 | this.changeTheme(cookieStoreId, 29 | tab.windowId, 30 | containers.get(cookieStoreId)); 31 | } 32 | else { 33 | this.resetTheme(tab.windowId); 34 | } 35 | }); 36 | } 37 | 38 | async getContainers() { 39 | const containersMap = new Map(); 40 | const containers = await browser.contextualIdentities.query({}); 41 | containers.forEach((container) => { 42 | containersMap.set(container.cookieStoreId, container); 43 | }); 44 | return containersMap; 45 | } 46 | 47 | isUnpaintedTheme(currentCookieStore) { 48 | return (currentCookieStore == "firefox-default" || 49 | currentCookieStore == "firefox-private"); 50 | } 51 | 52 | resetTheme(windowId) { 53 | browser.theme.reset(windowId); 54 | } 55 | 56 | async changeTheme(currentCookieStore, windowId, container) { 57 | this.cachedCookieStore = currentCookieStore; 58 | 59 | const theme = { 60 | images: { 61 | theme_frame: "", 62 | }, 63 | colors: { 64 | frame: container.colorCode, 65 | tab_background_text: "#111", 66 | } 67 | }; 68 | 69 | if (this.useThemePropertiesWhenOlderThanFirefox65) { 70 | this.transformThemeForOlderThanFirefox65(theme); 71 | } 72 | 73 | return browser.theme.update(windowId, theme); 74 | } 75 | 76 | transformThemeForOlderThanFirefox65(theme) { 77 | // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/theme#Aliases 78 | 79 | theme.images.headerUrl = theme.images.theme_frame; 80 | theme.colors.accentcolor = theme.colors.frame; 81 | theme.colors.textcolor = theme.colors.tab_background_text; 82 | 83 | delete theme.images.theme_frame; 84 | delete theme.colors.frame; 85 | delete theme.colors.tab_background_text; 86 | } 87 | 88 | } 89 | 90 | new containersTheme(); 91 | --------------------------------------------------------------------------------