diff --git a/package.json b/package.json index 020928e..bc7ebe7 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.0.1", "type": "module", "description": "Easy shortcuts for copying tab URL with or without title, with customizable format.", - "packageManager": "pnpm@9.9.0", + "packageManager": "pnpm@9.12.0", "private": true, "scripts": { "dev": "npm run clear && cross-env NODE_ENV=development run-p 'dev:*'", @@ -22,6 +22,7 @@ "pack:xpi": "cross-env WEB_EXT_ARTIFACTS_DIR=./ web-ext build --source-dir ./extension --filename extension.xpi --overwrite-dest", "start:chromium": "web-ext run --source-dir ./extension --target=chromium", "start:firefox": "web-ext run --source-dir ./extension --target=firefox-desktop", + "start:zed": "web-ext run --source-dir ./extension --target=firefox-desktop --firefox='/Applications/Zen Browser.app/Contents/MacOS/zen'", "clear": "rimraf extension/dist extension/manifest.json 'extension.*'", "lint": "eslint --ignore-path .gitignore './**/*.{ts,tsx,js,jsx}'" }, diff --git a/src/background/main.ts b/src/background/main.ts index 6b5bfd5..7b0a8e0 100644 --- a/src/background/main.ts +++ b/src/background/main.ts @@ -11,31 +11,51 @@ if (import.meta.hot) { import('./contentScriptHMR') } -browser.runtime.onInstalled.addListener((): void => { - logger.log('Extension installed') -}) - logger.log('Hello from background script') -async function getCurrentTab() { - return browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => tabs[0]) +function init() { + browser.runtime.onInstalled.addListener((): void => { + logger.log('Extension installed') + }) + + // Commands (keyboard shortcuts) + browser.commands.onCommand.addListener(async (cmd) => { + const tab = await getCurrentTab() + logger.debug('command received', cmd, tab) + const resp = getResponse(cmd, tab) + if (!resp || !tab) return + + logger.debug('sending message', resp, 'to tab', tab.id) + return sendMessage(resp.cmd, resp.payload!, { + context: 'content-script', + tabId: tab.id!, + }) + }) + + // Context menu + browser.contextMenus.create({ + id: 'copy-tab-url', + title: 'Copy Tab URL', + contexts: ['all'], + }) + browser.contextMenus.create({ + id: 'copy-tab-markdown', + title: 'Copy Tab Markdown', + contexts: ['all'], + }) + browser.contextMenus.onClicked.addListener(async (info) => { + const tab = await getCurrentTab() + const resp = getResponse(info.menuItemId as string, tab) + if (!resp || !tab) return + return sendMessage(resp.cmd, resp.payload!, { context: 'content-script', tabId: tab.id! }) + }) + + // Popup listeners + onMessage('copy-tab-url', responder('copy-tab-url')) + onMessage('copy-tab-markdown', responder('copy-tab-markdown')) } -browser.commands.onCommand.addListener(async (cmd) => { - const tab = await getCurrentTab() - logger.debug('command received', cmd, tab) - const resp = getResponse(cmd, tab) - if (!resp || !tab) return - - logger.debug('sending message', resp, 'to tab', tab.id) - return sendMessage(resp.cmd, resp.payload!, { - context: 'content-script', - tabId: tab.id!, - }) -}) - -onMessage('copy-tab-url', responder('copy-tab-url')) -onMessage('copy-tab-markdown', responder('copy-tab-markdown')) +init() function responder(cmd: string) { return async (payload: BridgeMessage) => { @@ -54,13 +74,17 @@ function getResponse(msg: string, tab: Tabs.Tab) { switch (msg) { case 'copy-tab-url': // copy tab url to clipboard - return { cmd: 'copy-text', payload: tab?.url } + return { cmd: msg, payload: tab?.url } case 'copy-tab-markdown': // copy tab url and title in markdown format return { - cmd: 'copy-text', + cmd: msg, payload: `[${tab?.title}](${tab?.url})`, } } return null } + +async function getCurrentTab() { + return browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => tabs[0]) +} diff --git a/src/manifest.ts b/src/manifest.ts index 3167bc3..b1a6451 100644 --- a/src/manifest.ts +++ b/src/manifest.ts @@ -30,7 +30,15 @@ export async function getManifest() { 48: './assets/icon-512.png', 128: './assets/icon-512.png', }, - permissions: ['tabs', 'storage', 'activeTab', 'clipboardWrite', 'http://*/', 'https://*/'], + permissions: [ + 'tabs', + 'storage', + 'activeTab', + 'clipboardWrite', + 'contextMenus', + 'http://*/', + 'https://*/', + ], content_scripts: [ { matches: ['http://*/*', 'https://*/*'], diff --git a/src/popup/Popup.css b/src/popup/Popup.css index f929217..4b76e70 100644 --- a/src/popup/Popup.css +++ b/src/popup/Popup.css @@ -1,13 +1,13 @@ +html, +body { + overflow: hidden; +} + .App { width: 300px; text-align: center; } -.App-logo { - height: 40vmin; - pointer-events: none; -} - @media (prefers-reduced-motion: no-preference) { .App-logo { animation: App-logo-spin infinite 20s linear; @@ -29,15 +29,6 @@ color: #61dafb; } -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - button { font-size: calc(10px + 2vmin); }