Skip to content

Commit

Permalink
feat: add option to display framework icon (#21)
Browse files Browse the repository at this point in the history
* save tabs data to storage

handle service worker for manifest v3

* refactor background. Split background into modules

* add branded icons

* update tabs manager

* add cache controller

* implement user local settings

* add settings controller UI

* change UI color

* Update src/components/Settings.vue

* use framework icon by default

#21 (comment)

* remove on-click-outside

* remove checkbox icons

* chore: update vta

---------

Co-authored-by: Den <[email protected]>
Co-authored-by: Sébastien Chopin <[email protected]>
Co-authored-by: Den <[email protected]>
Co-authored-by: Sébastien Chopin <[email protected]>
  • Loading branch information
5 people authored Jun 19, 2023
1 parent 742cbc8 commit 1526345
Show file tree
Hide file tree
Showing 15 changed files with 106 additions and 50 deletions.
2 changes: 1 addition & 1 deletion chrome/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"background": {
"service_worker": "background.js"
},
"permissions": ["scripting"],
"permissions": ["scripting", "storage"],
"host_permissions": [
"<all_urls>"
],
Expand Down
2 changes: 1 addition & 1 deletion firefox/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"background": {
"scripts": ["background.js"]
},
"permissions": ["https://*/*"],
"permissions": ["https://*/*", "storage"],
"content_security_policy": "script-src 'self'; object-src 'self'",
"web_accessible_resources": ["injected.js"]
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"postcss-loader": "^3.0.0",
"tailwindcss": "^1.3.5",
"vue": "^2.6.12",
"vue-telescope-analyzer": "^0.9.19",
"vue-telescope-analyzer": "^0.9.21",
"vuex": "^3.1.3",
"webextension-polyfill": "^0.3.1"
},
Expand Down
18 changes: 18 additions & 0 deletions src/background/TabsStateService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import CacheService from '../shared/CacheService'

// persistent state storage
export default class TabsStorage extends CacheService {
get key () {
return 'tabs'
}

async get () {
const cache = await super.get()
return cache || {}
}

async updateData (tabId, state) {
const cache = await this.get()
return this.set({ ...cache, [tabId]: state })
}
}
102 changes: 60 additions & 42 deletions src/background.js → src/background/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { IS_CHROME, IS_FIREFOX, isSupportExecutionVersion } from './utils'
const browser = require('webextension-polyfill')
import { IS_CHROME, IS_FIREFOX, isSupportExecutionVersion } from '../utils'
import browser from 'webextension-polyfill'
import TabsStateService from './TabsStateService'

const tabsStorage = {}
const tabsState = new TabsStateService()

if (IS_CHROME && isSupportExecutionVersion) {
/**
Expand Down Expand Up @@ -30,39 +31,75 @@ if (IS_CHROME && isSupportExecutionVersion) {
)
}

browser.tabs.onActivated.addListener(handleActivated)
browser.tabs.onUpdated.addListener(handleUpdated)
browser.runtime.onStartup.addListener(() => {
// clear state on startup.
// note: chrome allows to use 'browser.storage.session' but it is available in chrome only.
// for firefox a 'window.session' can be considered as alternative.
// TODO: create polyfill for session store.
tabsState.clear()
})

function setIcon (details) {
async function setIcon (details) {
// because manifest version is different
if (IS_FIREFOX) {
browser.browserAction.setIcon(details)
await browser.browserAction.setIcon(details)
} else {
browser.action.setIcon(details)
await browser.action.setIcon(details)
}
}

const setIconForTab = async (tabId) => {
const tabs = await tabsState.get()
const tab = tabs[tabId];
if (tab?.framework?.slug) {
const slug = tab.framework.slug
const iconPath = `icons/${slug}.png`
try {
await setIcon({tabId, path: iconPath});
} catch(e) {
await setIcon({
tabId,
path: 'icons/icon-128.png'
})
}
} else {
await setIcon({
tabId,
path: tab?.hasVue ? 'icons/icon-128.png' : 'icons/icon-grey-128.png'
})
}
}

browser.storage.local.onChanged.addListener(async (payload) => {
if (payload.settings) {
const tabs = await browser.tabs.query({});
tabs.forEach(tab => {
if (tab.id) {
setIconForTab(tab.id)
}
})
}
})

browser.runtime.onMessage.addListener(
async function (message, sender, sendResponse) {
if (message.action === 'analyze') {
// when sending message from popup.js there's no sender.tab, so need to pass tabId
const tabId = (sender.tab && sender.tab.id) || message.payload.tabId
setIcon({
tabId: tabId,
path: message.payload.hasVue ? 'icons/icon-128.png' : 'icons/icon-grey-128.png'
})

if (!tabsStorage[tabId]) {
tabsStorage[tabId] = message.payload
const tabs = await tabsState.get()
if (!tabs[tabId]) {
tabs[tabId] = message.payload
} else {
// temporary fix when hit CSP
if (!message.payload.modules.length) delete message.payload.modules
if (!message.payload.plugins.length) delete message.payload.plugins

tabsStorage[tabId] = { ...tabsStorage[tabId], ...message.payload }
tabs[tabId] = { ...tabs[tabId], ...message.payload }
}

const showcase = tabsStorage[tabId]
const showcase = tabs[tabId]
if (showcase.hasVue && !showcase.slug) {
try {
if (typeof EventSource === 'undefined') {
Expand All @@ -72,7 +109,7 @@ browser.runtime.onMessage.addListener(
const sse = new EventSource(
`https://service.vuetelescope.com?url=${message.payload.url}`
)
sse.addEventListener('message', (event) => {
sse.addEventListener('message', async (event) => {
try {
const res = JSON.parse(event.data)
if (!res.error && !res.isAdultContent) {
Expand All @@ -87,6 +124,7 @@ browser.runtime.onMessage.addListener(
if (!showcase.plugins.length && res.plugins.length) {
showcase.plugins = res.plugins
}
await tabsState.updateData(tabId, tabs[tabId])
} else {
throw new Error('API call to VT failed')
}
Expand All @@ -96,48 +134,28 @@ browser.runtime.onMessage.addListener(
})
} catch (err) {}
}
// tabsStorage[tabId] = message.payload
await tabsState.updateData(tabId, tabs[tabId])
await setIconForTab(tabId);
} else if (!sender.tab) {
if (message.action === 'getShowcase') {
// this is likely popup requesting
// sendResponse doesn't work in Firefox 👀
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage#Sending_a_synchronous_response
return Promise.resolve({ payload: tabsStorage[message.payload.tabId] })
// sendResponse({ payload: tabsStorage[message.payload.tabId] })
const tabs = await tabsState.get()
return { payload: tabs[message.payload.tabId] }
}
}
}
)

// when tab clicked
async function handleActivated ({ tabId, windowId }) {
setIcon({
tabId,
path: tabsStorage[tabId] && tabsStorage[tabId] && tabsStorage[tabId].hasVue ? 'icons/icon-128.png' : 'icons/icon-grey-128.png'
})
// chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
// const { id, url, status } = tabs[0]
// if (status === 'complete') {
// // tabsStorage[id].url = url
// }
// })
}

// when tab updated
async function handleUpdated (tabId, changeInfo, tabInfo) {
if (changeInfo.status === 'complete') {
if (!tabsStorage[tabId]) return
const tabs = await tabsState.get()
if (!tabs[tabId]) return
// tabsStorage[tabId].url = tabInfo.url
browser.tabs.sendMessage(tabId, {
from: 'background',
to: 'injected',
action: 'analyze',
payload: {}
})
// chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
// // send message to content script
// chrome.tabs.sendMessage(tabs[0].id, { from: 'background', to: 'injected', payload: { message: 'hello from background with sendMessage' } })
// })
// console.log('tabsStorage', tabsStorage)
}
}
Binary file added src/icons/gridsome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/icons/iles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/icons/nuxtjs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/icons/quasar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/icons/vitepress.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/icons/vuepress.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/icons/vuestorefront.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions src/shared/CacheService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import browser from 'webextension-polyfill'

export default class AbstractCacheService {
get key () {
throw new Error('key must be set')
}

async get () {
const cache = await browser.storage.local.get([this.key])
return cache[this.key]
}

async set (updatedState) {
return browser.storage.local.set({ [this.key]: updatedState })
}

async clear () {
return browser.storage.local.remove([this.key])
}
}
2 changes: 1 addition & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const config = {
entry: {
'popup/popup': './popup/popup.js',
injected: './injected.js',
background: './background.js',
background: './background/index.js',
content: './content.js'
},
output: {
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7317,10 +7317,10 @@ vue-svg-loader@^0.16.0:
loader-utils "^1.2.3"
svg-to-vue "^0.7.0"

vue-telescope-analyzer@^0.9.19:
version "0.9.19"
resolved "https://registry.yarnpkg.com/vue-telescope-analyzer/-/vue-telescope-analyzer-0.9.19.tgz#29d1586b76a1f5cc84cc722965b652529117369b"
integrity sha512-F0ZsDwtb3BJhv9QvlXUEP+TWFIlYgdhuwk7hoh+YsIptufY5SQRI9HqDhl2wLE+FIYGfyhJpop/wHDLDCw4X5w==
vue-telescope-analyzer@^0.9.21:
version "0.9.21"
resolved "https://registry.yarnpkg.com/vue-telescope-analyzer/-/vue-telescope-analyzer-0.9.21.tgz#647cd6fbf18e01500e1e5dd806b9ef9d190b6de8"
integrity sha512-7DvqJvH+jhtJKK/PxHpPP6ewKQ1v7BxPNiKPx+7x8MBnaWQG+8AVgTwdOy6sYAALxjqeAb0DypvRvSsJwoqEtA==
dependencies:
consola "^2.15.3"
make-dir "^3.1.0"
Expand Down

0 comments on commit 1526345

Please sign in to comment.