From 49afa0df622d4c2491320fa5f3e817f060fac169 Mon Sep 17 00:00:00 2001 From: trickypr <23250792+trickypr@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:26:11 +1100 Subject: [PATCH 01/14] =?UTF-8?q?=E2=9C=A8=20New=20window=20button?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../menus/HamburgerMenu/HamburgerMenu.svelte | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/content/browser/components/menus/HamburgerMenu/HamburgerMenu.svelte b/src/content/browser/components/menus/HamburgerMenu/HamburgerMenu.svelte index 1c89bf7..394caa3 100644 --- a/src/content/browser/components/menus/HamburgerMenu/HamburgerMenu.svelte +++ b/src/content/browser/components/menus/HamburgerMenu/HamburgerMenu.svelte @@ -11,10 +11,21 @@ const openDialogWindowAction = (url: string) => () => Services.ww.openWindow(window, url, '_blank', 'chrome,dialog=yes,all', null) + + const openChromeWindowAction = (url: string) => () => + Services.ww.openWindow(null, url, '_blank', 'chrome,dialog=no,all', null)
+ + New Window + + Date: Fri, 8 Dec 2023 12:52:35 +1100 Subject: [PATCH 02/14] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Split=20window=20api?= =?UTF-8?q?=20up=20into=20multiple=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + scripts/lib/artifacts.ts | 4 +- scripts/lib/logging.ts | 2 + src/content/browser/Browser.svelte | 3 +- src/content/browser/browser.ts | 2 +- .../customizableUI/BrowserView.svelte | 2 +- .../components/customizableUI/Tabs.svelte | 2 +- .../components/keybindings/Keybindings.svelte | 10 ++-- .../menus/BrowserContextMenu.svelte | 10 +++- .../menus/HamburgerMenu/HamburgerMenu.svelte | 2 +- .../browser/components/tabs/Tab.svelte | 12 ++++- src/content/browser/lib/shortcuts.ts | 2 +- src/content/browser/lib/window/api.ts | 46 ++++++++++++++++ src/content/browser/lib/window/contextMenu.ts | 20 +++++++ src/content/browser/lib/window/index.ts | 3 ++ src/content/browser/lib/window/initialize.ts | 3 ++ .../lib/{globalApi.ts => window/tabs.ts} | 53 ++----------------- src/content/shared/contextMenus/MenuItem.ts | 1 + src/content/shared/contextMenus/menuItems.ts | 24 +++++++-- src/content/shared/xul/PlacesModel.ts | 1 - src/content/tests/shared/ExtHistoryAPI.ts | 2 - src/content/types.d.ts | 2 +- 22 files changed, 133 insertions(+), 74 deletions(-) create mode 100644 src/content/browser/lib/window/api.ts create mode 100644 src/content/browser/lib/window/contextMenu.ts create mode 100644 src/content/browser/lib/window/index.ts create mode 100644 src/content/browser/lib/window/initialize.ts rename src/content/browser/lib/{globalApi.ts => window/tabs.ts} (71%) diff --git a/package.json b/package.json index 801c9c5..7bbd0ba 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "importOrder": [ "^resource://(.*)$", "^@shared/(.*)$", + "^@browser/(.*)$", "^[./]" ], "importOrderSeparation": true, diff --git a/scripts/lib/artifacts.ts b/scripts/lib/artifacts.ts index f6dda65..c5d4bef 100644 --- a/scripts/lib/artifacts.ts +++ b/scripts/lib/artifacts.ts @@ -1,6 +1,8 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* eslint-disable no-console */ import { existsSync } from 'fs' import { readFile, rm } from 'fs/promises' @@ -59,7 +61,7 @@ export async function downloadArtifact(artifact: Artifact): Promise { await rm(artifactFile) } - // Write out a new line so that progress doesn't overwrite exising logs + // Write out a new line so that progress doesn't overwrite existing logs console.info(artifact.archive_download_url) // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/scripts/lib/logging.ts b/scripts/lib/logging.ts index 6b18294..c1ee99e 100644 --- a/scripts/lib/logging.ts +++ b/scripts/lib/logging.ts @@ -1,6 +1,8 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* eslint-disable no-console */ import kleur from 'kleur' import { exit } from 'process' diff --git a/src/content/browser/Browser.svelte b/src/content/browser/Browser.svelte index 55bd3bf..6ddcc5e 100644 --- a/src/content/browser/Browser.svelte +++ b/src/content/browser/Browser.svelte @@ -8,8 +8,7 @@ import CustomizableUi from './components/customizableUI/CustomizableUI.svelte' import { BrowserContextMenu, HamburgerMenu } from './components/menus' import Keybindings from './components/keybindings/Keybindings.svelte' - - import { tabs, selectedTab } from './lib/globalApi' + import { tabs, selectedTab } from './lib/window/tabs' let component = customizableUIDynamicPref('browser.uiCustomization.state') $: currentTab = $tabs.find((tab) => tab.getId() == $selectedTab) diff --git a/src/content/browser/browser.ts b/src/content/browser/browser.ts index 72eaa7c..0fbf977 100644 --- a/src/content/browser/browser.ts +++ b/src/content/browser/browser.ts @@ -7,8 +7,8 @@ import 'remixicon/fonts/remixicon.css' import '@shared/styles/window.css' import App from './Browser.svelte' -import './lib/globalApi' import { initializeShortcuts } from './lib/shortcuts' +import './lib/window/api' // TODO: WTF is this and do we care // This needs setting up before we create the first remote browser. diff --git a/src/content/browser/components/customizableUI/BrowserView.svelte b/src/content/browser/components/customizableUI/BrowserView.svelte index 44841f3..f1c29c9 100644 --- a/src/content/browser/components/customizableUI/BrowserView.svelte +++ b/src/content/browser/components/customizableUI/BrowserView.svelte @@ -9,8 +9,8 @@ ComponentId, } from '@shared/customizableUI' import UiItemBase from './UIItemBase.svelte' - import { selectedTab, tabs } from '../../lib/globalApi' import Browser from '../Browser.svelte' + import { selectedTab, tabs } from '@browser/lib/window/tabs' export let component: ComponentId & BrowserComponent export let root: Component diff --git a/src/content/browser/components/customizableUI/Tabs.svelte b/src/content/browser/components/customizableUI/Tabs.svelte index 02eba17..8aae788 100644 --- a/src/content/browser/components/customizableUI/Tabs.svelte +++ b/src/content/browser/components/customizableUI/Tabs.svelte @@ -8,10 +8,10 @@ ComponentId, TabsComponent, } from '@shared/customizableUI' - import { tabs, selectedTab } from '@browser/lib/globalApi' import Tab from '@browser/components/tabs/Tab.svelte' import UiItemBase from './UIItemBase.svelte' + import { selectedTab, tabs } from '@browser/lib/window/tabs' export let component: ComponentId & TabsComponent export let root: Component diff --git a/src/content/browser/components/keybindings/Keybindings.svelte b/src/content/browser/components/keybindings/Keybindings.svelte index 5d3299d..483dc92 100644 --- a/src/content/browser/components/keybindings/Keybindings.svelte +++ b/src/content/browser/components/keybindings/Keybindings.svelte @@ -2,16 +2,16 @@ - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - diff --git a/src/content/browser/components/menus/BrowserContextMenu.svelte b/src/content/browser/components/menus/BrowserContextMenu.svelte index 1e00be5..0793da7 100644 --- a/src/content/browser/components/menus/BrowserContextMenu.svelte +++ b/src/content/browser/components/menus/BrowserContextMenu.svelte @@ -2,11 +2,17 @@ - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +
- + windowApi.window.new()}> New Window diff --git a/src/content/browser/lib/window/api.ts b/src/content/browser/lib/window/api.ts index ffb2085..396b95e 100644 --- a/src/content/browser/lib/window/api.ts +++ b/src/content/browser/lib/window/api.ts @@ -3,12 +3,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import mitt from 'mitt' +import type { WindowArguments } from '.' import type { ContextMenuInfo } from '../../../../actors/ContextMenu.types' import { browserContextMenuInfo, setContextMenuParentActor, } from './contextMenu' -import { closeTab, openTab, tabs } from './tabs' +import { closeTab, openTab, runOnCurrentTab, setCurrentTab, tabs } from './tabs' export type WindowTriggers = { bookmarkCurrentPage: undefined @@ -16,9 +17,22 @@ export type WindowTriggers = { export const windowApi = { windowTriggers: mitt(), + window: { + new: (args?: WindowArguments) => + Services.ww.openWindow( + // @ts-expect-error Incorrect type generation + null, + Services.prefs.getStringPref('app.content'), + '_blank', + 'chrome,dialog=no,all', + args, + ), + }, tabs: { closeTab, openTab, + runOnCurrentTab, + setCurrentTab, get tabs() { return tabs.readOnce() }, diff --git a/src/content/browser/lib/window/initialize.ts b/src/content/browser/lib/window/initialize.ts index a6ce21d..bda29a1 100644 --- a/src/content/browser/lib/window/initialize.ts +++ b/src/content/browser/lib/window/initialize.ts @@ -6,6 +6,16 @@ import { type WindowArguments, getFullWindowConfiguration } from './arguments' import { openTab } from './tabs' export function initializeWindow(args: WindowArguments | undefined) { + // When opened via nsIWindowWatcher.openWindow, the arguments are + // passed through C++, and they arrive to us wrapped as an XPCOM + // object. We use wrappedJSObject to get at the underlying JS + // object. + // @ts-expect-error Incorrect type generation + if (args instanceof Ci.nsISupports) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + args = (args as any).wrappedJSObject as WindowArguments + } + const configuration = getFullWindowConfiguration(args || {}) // Setup tabs diff --git a/src/content/shared/contextMenus/menuItems.ts b/src/content/shared/contextMenus/menuItems.ts index be56e10..3b5054a 100644 --- a/src/content/shared/contextMenus/menuItems.ts +++ b/src/content/shared/contextMenus/menuItems.ts @@ -8,11 +8,6 @@ import { type ContextMenuInfo, contextMenuParentActor, } from '@browser/lib/window/contextMenu' -import { - openTab, - runOnCurrentTab, - setCurrentTab, -} from '@browser/lib/window/tabs' import { getClipboardHelper } from '@browser/lib/xul/ccWrapper' import type { MenuItemAction, VisibilityCheck } from '.' @@ -41,15 +36,17 @@ const copyProp = onStringValue((value) => { }) const openInNewTab = onStringValue((value) => { - const tab = openTab(resource.NetUtil.newURI(value)) + const tab = window.windowApi.tabs.openTab(resource.NetUtil.newURI(value)) if (Services.prefs.getBoolPref('browser.tabs.newTabFocus')) { - queueMicrotask(() => setCurrentTab(tab)) + queueMicrotask(() => window.windowApi.tabs.setCurrentTab(tab)) } }) -const openInNewWindow = onStringValue(() => { - // TODO -}) +const openInNewWindow = onStringValue((initialUrl) => + window.windowApi.window.new({ + initialUrl: initialUrl, + }), +) const saveImageUrl = onStringValue((value, info) => { if (!info.context.principal) @@ -114,21 +111,24 @@ export const MENU_ITEM_ACTIONS: MenuItemAction[] = ( title: 'Back', visible: ALWAYS, - action: () => runOnCurrentTab((tab) => tab.goBack()), + action: () => + window.windowApi.tabs.runOnCurrentTab((tab) => tab.goBack()), }, { id: 'navigation__forward', title: 'Forward', visible: ALWAYS, - action: () => runOnCurrentTab((tab) => tab.goForward()), + action: () => + window.windowApi.tabs.runOnCurrentTab((tab) => tab.goForward()), }, { id: 'navigation__reload', title: 'Reload', visible: ALWAYS, - action: () => runOnCurrentTab((tab) => tab.reload()), + action: () => + window.windowApi.tabs.runOnCurrentTab((tab) => tab.reload()), }, { id: 'navigation__bookmark', diff --git a/src/content/types.d.ts b/src/content/types.d.ts index 38c3e65..fdf1dc8 100644 --- a/src/content/types.d.ts +++ b/src/content/types.d.ts @@ -20,7 +20,7 @@ declare interface Window { * * @see {@link file://./browser/lib/window/arguments.ts} */ - arguments?: import('./browser/lib/window/arguments').WindowArguments + arguments?: [import('./browser/lib/window/arguments').WindowArguments] } declare interface NodeModule { From 2bcfb7aa983a54e130e1717e0d768abec5bac5ea Mon Sep 17 00:00:00 2001 From: trickypr <23250792+trickypr@users.noreply.github.com> Date: Fri, 8 Dec 2023 17:20:49 +1100 Subject: [PATCH 06/14] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20`tab.ts`=20in?= =?UTF-8?q?to=20`lib/window`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/content/browser/components/Browser.svelte | 2 +- .../components/customizableUI/Block.svelte | 2 +- .../customizableUI/CustomizableUI.svelte | 2 +- .../customizableUI/IconButton.svelte | 2 +- .../customizableUI/OmniboxContainer.svelte | 2 +- .../components/omnibox/Bookmarks.svelte | 2 +- .../browser/components/omnibox/Omnibox.svelte | 2 +- .../browser/components/tabs/Tab.svelte | 6 +---- .../{components/tabs => lib/window}/tab.ts | 22 +++++++------------ src/content/browser/lib/window/tabs.ts | 3 +-- src/content/shared/customizableUI/helpers.ts | 3 +-- src/content/shared/customizableUI/types.ts | 3 +-- 12 files changed, 19 insertions(+), 32 deletions(-) rename src/content/browser/{components/tabs => lib/window}/tab.ts (94%) diff --git a/src/content/browser/components/Browser.svelte b/src/content/browser/components/Browser.svelte index 13e5120..7333003 100644 --- a/src/content/browser/components/Browser.svelte +++ b/src/content/browser/components/Browser.svelte @@ -4,7 +4,7 @@ e.preventDefault()}> - {#each $tabs as tab} + {#each $tabs as tab (tab.getId())} {/each} diff --git a/src/content/browser/components/tabs/Tab.svelte b/src/content/browser/components/tabs/Tab.svelte index d9adcaa..60cab0e 100644 --- a/src/content/browser/components/tabs/Tab.svelte +++ b/src/content/browser/components/tabs/Tab.svelte @@ -4,59 +4,41 @@ +
+
(selectedTab = tab.getId())} on:mouseup={(e) => { // When the middle mouse button is clicked, close this tab if (e.button == 1) closeTab(tab) }} - on:dragstart={(e) => - e.dataTransfer?.setData('text/plain', tab.getId().toString())} - on:dragover={dragOver} class="tab" role="tab" tabindex={tab.getId()} - aria-selected={tab.getId() == selectedTab} - draggable="true" + aria-selected={selected} > {#if $loading}
@@ -75,6 +57,8 @@
+
+ diff --git a/src/content/browser/components/tabs/tabDrag.ts b/src/content/browser/components/tabs/tabDrag.ts new file mode 100644 index 0000000..2f49ea6 --- /dev/null +++ b/src/content/browser/components/tabs/tabDrag.ts @@ -0,0 +1,99 @@ +import type { Action } from 'svelte/action' +import { type Readable, type Writable, writable } from 'svelte/store' + +import type { Tab } from '@browser/lib/window/tab' +import { moveTabAfter, moveTabBefore } from '@browser/lib/window/tabs' + +export const TAB_DATA_TYPE = 'experiment/tab' + +const dragOver = ( + tab: Tab, + dropBefore: Writable, + dropAfter: Writable, +) => { + let lastDragIsBefore: boolean | undefined + + return (event: DragEvent) => { + const currentTarget = event.currentTarget as HTMLDivElement + const rawDragRepresentation = event.dataTransfer?.getData(TAB_DATA_TYPE) + + if (!currentTarget.classList.contains('tab')) return + if (!rawDragRepresentation) { + console.warn('No drag representation') + return + } + + const { windowId, tabId } = JSON.parse(rawDragRepresentation) as ReturnType< + Tab['getDragRepresentation'] + > + const sameWindow = windowId === window.windowApi.id + + const boundingRect = currentTarget.getBoundingClientRect() + const xMiddle = boundingRect.x + boundingRect.width / 2 + const isBefore = event.x <= xMiddle + + if ((tabId == tab.getId() && sameWindow) || lastDragIsBefore === isBefore) + return + lastDragIsBefore = isBefore + + if (!sameWindow) { + console.warn('Tab is from a different window') + + dropBefore.set(isBefore) + dropAfter.set(!isBefore) + + return + } + + dropBefore.set(false) + dropAfter.set(false) + + event.preventDefault() + event.stopPropagation() + if (isBefore) moveTabBefore(tabId, tab.getId()) + else moveTabAfter(tabId, tab.getId()) + } +} + +export function createTabDrag(tab: Tab) { + const dropBefore = writable(false) + const dropAfter = writable(false) + + const dragOverEvent = dragOver(tab, dropBefore, dropAfter) + const setDataTransferEvent = (event: DragEvent) => + event.dataTransfer?.setData( + TAB_DATA_TYPE, + JSON.stringify(tab.getDragRepresentation()), + ) + const dragLeaveEvent = () => { + dropBefore.set(false) + dropAfter.set(false) + } + + const tabDrag: Action = (node) => { + const initialDraggable = node.draggable + node.draggable = true + + node.addEventListener('dragstart', setDataTransferEvent) + node.addEventListener('dragover', dragOverEvent) + node.addEventListener('dragleave', dragLeaveEvent) + + return { + destroy() { + node.removeEventListener('dragstart', setDataTransferEvent) + node.removeEventListener('dragover', dragOverEvent) + node.removeEventListener('dragleave', dragLeaveEvent) + + node.draggable = initialDraggable + }, + } + } + + return { + tabDrag, + drop: { + before: dropBefore satisfies Readable, + after: dropAfter satisfies Readable, + }, + } +} diff --git a/src/content/browser/lib/window/api.ts b/src/content/browser/lib/window/api.ts index 396b95e..9d309eb 100644 --- a/src/content/browser/lib/window/api.ts +++ b/src/content/browser/lib/window/api.ts @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import mitt from 'mitt' +import { nanoid } from 'nanoid' import type { WindowArguments } from '.' import type { ContextMenuInfo } from '../../../../actors/ContextMenu.types' @@ -16,6 +17,12 @@ export type WindowTriggers = { } export const windowApi = { + /** + * Identify which window this is. This should be used for actions like tab + * moving that go across windows + */ + id: nanoid(), + windowTriggers: mitt(), window: { new: (args?: WindowArguments) => diff --git a/src/content/browser/lib/window/tab.ts b/src/content/browser/lib/window/tab.ts index ff635fd..d17090c 100644 --- a/src/content/browser/lib/window/tab.ts +++ b/src/content/browser/lib/window/tab.ts @@ -89,6 +89,13 @@ export class Tab { return this.tabId || 0 } + public getDragRepresentation() { + return { + windowId: window.windowApi.id, + tabId: this.getId(), + } + } + protected useProgressListener() { this.progressListener.events.on('locationChange', (event) => { if (!event.aWebProgress.isTopLevel) return diff --git a/src/content/reset.d.ts b/src/content/reset.d.ts new file mode 100644 index 0000000..69fc8bf --- /dev/null +++ b/src/content/reset.d.ts @@ -0,0 +1 @@ +import '@total-typescript/ts-reset' diff --git a/src/content/shared/customizableUI/helpers.ts b/src/content/shared/customizableUI/helpers.ts index bc0c478..7c81aab 100644 --- a/src/content/shared/customizableUI/helpers.ts +++ b/src/content/shared/customizableUI/helpers.ts @@ -290,5 +290,5 @@ export const fromExportTypeStable = (component: ExportComponent) => fromExportTypeStableInternal('root')(component, 0) export const customizableUIDynamicPref = dynamicStringPref((json) => - fromExportTypeStable(JSON.parse(json)), + fromExportTypeStable(JSON.parse(json) as ExportComponent), ) diff --git a/src/content/shared/customizableUI/style.ts b/src/content/shared/customizableUI/style.ts index 0a64359..58d3c5e 100644 --- a/src/content/shared/customizableUI/style.ts +++ b/src/content/shared/customizableUI/style.ts @@ -1,7 +1,6 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - import type { BlockComponent, BlockDirection, @@ -73,7 +72,7 @@ function getOmniboxStyle( function getTabsStyle(): string { return ` display:flex; - gap: 0.25rem; + gap: 0.125rem; ` } diff --git a/src/content/shared/search/providers/EngineProvider.ts b/src/content/shared/search/providers/EngineProvider.ts index baa4a5e..961dcae 100644 --- a/src/content/shared/search/providers/EngineProvider.ts +++ b/src/content/shared/search/providers/EngineProvider.ts @@ -60,7 +60,8 @@ export class EngineProvider extends Provider { } try { - const json = JSON.parse(body) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const json = JSON.parse(body) as any const results = json[1].map((result: string) => { return { title: result, diff --git a/src/content/tests/manager.ts b/src/content/tests/manager.ts index a225664..fd8efa2 100644 --- a/src/content/tests/manager.ts +++ b/src/content/tests/manager.ts @@ -11,9 +11,9 @@ document.body.appendChild(TEST_OUTPUT) export async function manageTests( tests: () => Promise, ): Promise<(tests: () => Promise) => Promise> { - const config = await fetch(`http://localhost:${TEST_PORT}/config`).then((r) => - r.json(), - ) + const config = (await fetch(`http://localhost:${TEST_PORT}/config`).then( + (r) => r.json(), + )) as { shouldWatch: boolean } async function performTests(tests: () => Promise) { hold() From 552b7f3c74df5b8e3ad7d923c176f687b8ee05fe Mon Sep 17 00:00:00 2001 From: trickypr <23250792+trickypr@users.noreply.github.com> Date: Fri, 8 Dec 2023 19:27:47 +1100 Subject: [PATCH 08/14] =?UTF-8?q?=F0=9F=9A=A7=20Window=20Tracker=20&=20hid?= =?UTF-8?q?den=20tabs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .config/webpack.config.js | 20 ++- package.json | 1 + pnpm-lock.yaml | 116 ++++++++++++++++-- .../browser/components/tabs/Tab.svelte | 67 +++++----- .../browser/components/tabs/tabDrag.ts | 31 ++++- src/content/browser/lib/resources.ts | 1 + src/content/browser/lib/window/api.ts | 4 +- src/content/browser/lib/window/initialize.ts | 6 + src/content/browser/lib/window/tab.ts | 2 + src/content/browser/lib/window/window.ts | 9 ++ src/content/reset.d.ts | 4 + src/link.d.ts | 2 + src/modules/BrowserWindowTracker.ts | 20 +++ src/modules/link.json | 2 +- 14 files changed, 230 insertions(+), 55 deletions(-) create mode 100644 src/content/browser/lib/window/window.ts create mode 100644 src/modules/BrowserWindowTracker.ts diff --git a/.config/webpack.config.js b/.config/webpack.config.js index dabda3c..8ff0ecb 100644 --- a/.config/webpack.config.js +++ b/.config/webpack.config.js @@ -6,6 +6,7 @@ import MiniCssExtractPlugin from 'mini-css-extract-plugin' import { join, resolve } from 'node:path' import preprocess from 'svelte-preprocess' import sequence from 'svelte-sequential-preprocessor' +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer' import WebpackLicensePlugin from 'webpack-license-plugin' const HTML_TEMPLATE_FILE = './src/content/index.html' @@ -86,16 +87,12 @@ const sharedSettings = (contentFiles, dev) => { overlay: false, }, }, - optimization: dev - ? { - runtimeChunk: 'single', - } - : { - runtimeChunk: 'single', - splitChunks: { - chunks: 'all', - }, - }, + optimization: { + runtimeChunk: 'single', + splitChunks: { + chunks: 'all', + }, + }, module: { rules: [ @@ -174,7 +171,8 @@ const sharedSettings = (contentFiles, dev) => { }, ], }), - ], + // dev && new BundleAnalyzerPlugin(), + ].filter(Boolean), experiments: { topLevelAwait: true, diff --git a/package.json b/package.json index c43797c..26d8a05 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "ts-loader": "^9.5.0", "typescript": "^5.2.2", "webpack": "^5.89.0", + "webpack-bundle-analyzer": "^4.10.1", "webpack-cli": "^5.1.4", "webpack-dev-server": "^4.15.1", "webpack-license-plugin": "^4.4.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 75cd79a..319699b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -129,9 +129,12 @@ devDependencies: webpack: specifier: ^5.89.0 version: 5.89.0(webpack-cli@5.1.4) + webpack-bundle-analyzer: + specifier: ^4.10.1 + version: 4.10.1 webpack-cli: specifier: ^5.1.4 - version: 5.1.4(webpack-dev-server@4.15.1)(webpack@5.89.0) + version: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack-dev-server@4.15.1)(webpack@5.89.0) webpack-dev-server: specifier: ^4.15.1 version: 4.15.1(webpack-cli@5.1.4)(webpack@5.89.0) @@ -467,6 +470,10 @@ packages: fastq: 1.15.0 dev: true + /@polka/url@1.0.0-next.24: + resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==} + dev: true + /@swc/helpers@0.5.3: resolution: {integrity: sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==} dependencies: @@ -1018,7 +1025,7 @@ packages: webpack-cli: 5.x.x dependencies: webpack: 5.89.0(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-dev-server@4.15.1)(webpack@5.89.0) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack-dev-server@4.15.1)(webpack@5.89.0) dev: true /@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.89.0): @@ -1029,7 +1036,7 @@ packages: webpack-cli: 5.x.x dependencies: webpack: 5.89.0(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-dev-server@4.15.1)(webpack@5.89.0) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack-dev-server@4.15.1)(webpack@5.89.0) dev: true /@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack-dev-server@4.15.1)(webpack@5.89.0): @@ -1044,7 +1051,7 @@ packages: optional: true dependencies: webpack: 5.89.0(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-dev-server@4.15.1)(webpack@5.89.0) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack-dev-server@4.15.1)(webpack@5.89.0) webpack-dev-server: 4.15.1(webpack-cli@5.1.4)(webpack@5.89.0) dev: true @@ -1080,6 +1087,11 @@ packages: acorn: 8.10.0 dev: true + /acorn-walk@8.3.1: + resolution: {integrity: sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==} + engines: {node: '>=0.4.0'} + dev: true + /acorn@8.10.0: resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} engines: {node: '>=0.4.0'} @@ -1430,6 +1442,11 @@ packages: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: true + /commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + dev: true + /commander@8.3.0: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} @@ -1600,6 +1617,10 @@ packages: '@babel/runtime': 7.23.2 dev: true + /debounce@1.2.1: + resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} + dev: true + /debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -1744,6 +1765,10 @@ packages: tslib: 2.6.2 dev: true + /duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + dev: true + /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: true @@ -2269,6 +2294,13 @@ packages: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true + /gzip-size@6.0.0: + resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} + engines: {node: '>=10'} + dependencies: + duplexer: 0.1.2 + dev: true + /handle-thing@2.0.1: resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} dev: true @@ -2321,6 +2353,10 @@ packages: resolution: {integrity: sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==} dev: true + /html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + /html-minifier-terser@6.1.0: resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} engines: {node: '>=12'} @@ -2579,6 +2615,11 @@ packages: isobject: 3.0.1 dev: true + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: true + /is-reference@3.0.2: resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} dependencies: @@ -2894,6 +2935,11 @@ packages: minimist: 1.2.8 dev: true + /mrmime@1.0.1: + resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} + engines: {node: '>=10'} + dev: true + /ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} dev: true @@ -3059,6 +3105,11 @@ packages: is-wsl: 2.2.0 dev: true + /opener@1.5.2: + resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} + hasBin: true + dev: true + /optionator@0.9.3: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} @@ -3687,6 +3738,15 @@ packages: engines: {node: '>=14'} dev: true + /sirv@2.0.3: + resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==} + engines: {node: '>= 10'} + dependencies: + '@polka/url': 1.0.0-next.24 + mrmime: 1.0.1 + totalist: 3.0.1 + dev: true + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -4061,6 +4121,11 @@ packages: engines: {node: '>=0.6'} dev: true + /totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + dev: true + /tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -4193,7 +4258,30 @@ packages: minimalistic-assert: 1.0.1 dev: true - /webpack-cli@5.1.4(webpack-dev-server@4.15.1)(webpack@5.89.0): + /webpack-bundle-analyzer@4.10.1: + resolution: {integrity: sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==} + engines: {node: '>= 10.13.0'} + hasBin: true + dependencies: + '@discoveryjs/json-ext': 0.5.7 + acorn: 8.10.0 + acorn-walk: 8.3.1 + commander: 7.2.0 + debounce: 1.2.1 + escape-string-regexp: 4.0.0 + gzip-size: 6.0.0 + html-escaper: 2.0.2 + is-plain-object: 5.0.0 + opener: 1.5.2 + picocolors: 1.0.0 + sirv: 2.0.3 + ws: 7.5.9 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: true + + /webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack-dev-server@4.15.1)(webpack@5.89.0): resolution: {integrity: sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==} engines: {node: '>=14.15.0'} hasBin: true @@ -4223,6 +4311,7 @@ packages: interpret: 3.1.1 rechoir: 0.8.0 webpack: 5.89.0(webpack-cli@5.1.4) + webpack-bundle-analyzer: 4.10.1 webpack-dev-server: 4.15.1(webpack-cli@5.1.4)(webpack@5.89.0) webpack-merge: 5.9.0 dev: true @@ -4283,7 +4372,7 @@ packages: sockjs: 0.3.24 spdy: 4.0.2 webpack: 5.89.0(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-dev-server@4.15.1)(webpack@5.89.0) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack-dev-server@4.15.1)(webpack@5.89.0) webpack-dev-middleware: 5.3.3(webpack@5.89.0) ws: 8.14.2 transitivePeerDependencies: @@ -4356,7 +4445,7 @@ packages: tapable: 2.2.1 terser-webpack-plugin: 5.3.9(webpack@5.89.0) watchpack: 2.4.0 - webpack-cli: 5.1.4(webpack-dev-server@4.15.1)(webpack@5.89.0) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack-dev-server@4.15.1)(webpack@5.89.0) webpack-sources: 3.2.3 transitivePeerDependencies: - '@swc/core' @@ -4403,6 +4492,19 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true + /ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: true + /ws@8.14.2: resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} engines: {node: '>=10.0.0'} diff --git a/src/content/browser/components/tabs/Tab.svelte b/src/content/browser/components/tabs/Tab.svelte index 60cab0e..1e6b2c4 100644 --- a/src/content/browser/components/tabs/Tab.svelte +++ b/src/content/browser/components/tabs/Tab.svelte @@ -15,6 +15,7 @@ $: icon = tab.icon $: uri = tab.uri $: loading = tab.loading + $: hidden = tab.hidden $: tabDragInfo = createTabDrag(tab) $: tabDrag = tabDragInfo.tabDrag @@ -25,39 +26,41 @@ $: selected && (document.title = $title) -
- - -
(selectedTab = tab.getId())} - on:mouseup={(e) => { - // When the middle mouse button is clicked, close this tab - if (e.button == 1) closeTab(tab) - }} - class="tab" - role="tab" - tabindex={tab.getId()} - aria-selected={selected} -> - {#if $loading} -
- -
- {:else if $icon} - favicon - {/if} - {$title || $uri.asciiSpec} - -
- -
+ {#if $loading} +
+ +
+ {:else if $icon} + favicon + {/if} + {$title || $uri.asciiSpec} + +
+ +
+{/if}