diff --git a/src/argo-archive-list.ts b/src/argo-archive-list.ts index c7f77c9..abc60fe 100644 --- a/src/argo-archive-list.ts +++ b/src/argo-archive-list.ts @@ -210,12 +210,16 @@ export class ArgoArchiveList extends LitElement { } } - private buildIndex() { - this.flex = new FlexIndex(); - this.pages.forEach((p) => { - const text = p.url + (p.title ? ` ${p.title}` : ""); - this.flex.add(p.ts, text); // use ts (timestamp) as a unique id - }); + public clearSelection() { + this.selectedPages = new Set(); + this.requestUpdate(); + this.dispatchEvent( + new CustomEvent("selection-change", { + detail: { count: 0 }, + bubbles: true, + composed: true, + }), + ); } private togglePageSelection(ts: string) { @@ -226,6 +230,13 @@ export class ArgoArchiveList extends LitElement { next.add(ts); } this.selectedPages = next; + this.dispatchEvent( + new CustomEvent("selection-change", { + detail: { count: this.selectedPages.size }, + bubbles: true, + composed: true, + }), + ); } public getSelectedPages() { @@ -342,6 +353,7 @@ export class ArgoArchiveList extends LitElement { { e.stopPropagation(); this.togglePageSelection(page.ts); diff --git a/src/ext/bg.ts b/src/ext/bg.ts index da9e112..631b70b 100644 --- a/src/ext/bg.ts +++ b/src/ext/bg.ts @@ -3,7 +3,6 @@ import { BrowserRecorder } from "./browser-recorder"; import { CollectionLoader } from "@webrecorder/wabac/swlib"; import { listAllMsg } from "../utils"; - import { getLocalOption, removeLocalOption, @@ -110,6 +109,23 @@ function sidepanelHandler(port) { break; } + case "deletePages": { + const defaultCollId = await getLocalOption("defaultCollId"); + if (!defaultCollId) { + return; + } + const coll = await collLoader.loadColl(defaultCollId); + + for (const id of message.pageIds) { + await coll.store.deletePage(id); + } + + // now re-send the new list of pages + const pages = await coll.store.getAllPages(); + port.postMessage({ type: "pages", pages }); + break; + } + case "startRecording": { isRecordingEnabled = true; defaultCollId = message.collId; diff --git a/src/sidepanel.ts b/src/sidepanel.ts index d03664a..66cecc9 100644 --- a/src/sidepanel.ts +++ b/src/sidepanel.ts @@ -8,8 +8,6 @@ import "@material/web/icon/icon.js"; import { ArgoArchiveList } from "./argo-archive-list"; import { Downloader } from "./sw/downloader"; -import wrRec from "./assets/icons/recLogo.svg"; - import { getLocalOption, // removeLocalOption, @@ -128,6 +126,35 @@ class ArgoViewer extends LitElement { filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.6)); } + /* Fade overlay styles */ + .tabs-wrapper { + position: relative; + } + + .tabs-overlay { + transition: opacity 0.3s ease; + } + .tabs-overlay.inactive { + opacity: 0; + pointer-events: none; + } + + .actions-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + transition: opacity 0.3s ease; + opacity: 0; + pointer-events: none; + background: white; + z-index: 1; + } + .actions-overlay.active { + opacity: 1; + pointer-events: auto; + } + md-icon[filled] { font-variation-settings: "FILL" 1; } @@ -137,6 +164,8 @@ class ArgoViewer extends LitElement { private archiveList!: ArgoArchiveList; constructor() { super(); + // @ts-expect-error - TS2339 - Property 'selectedCount' does not exist on type 'ArgoViewer'. + this.selectedCount = 0; // @ts-expect-error - TS2339 - Property 'searchQuery' does not exist on type 'ArgoViewer'. this.searchQuery = ""; // @ts-expect-error - TS2339 - Property 'collections' does not exist on type 'ArgoViewer'. @@ -193,6 +222,7 @@ class ArgoViewer extends LitElement { static get properties() { return { searchQuery: { type: String }, + selectedCount: { type: Number }, collections: { type: Array }, collId: { type: String }, collTitle: { type: String }, @@ -250,6 +280,16 @@ class ArgoViewer extends LitElement { })[0]; } + onDeleteSelected() { + const pages = this.archiveList.getSelectedPages(); + const ids = pages.map((p) => p.id); + this.sendMessage({ type: "deletePages", pageIds: ids }); + // then clear UI + this.archiveList.clearSelection(); + // @ts-expect-error - TS2339 - Property 'selectedCount' does not exist on type 'ArgoViewer'. + this.selectedCount = 0; + } + private async onDownload() { const selectedPages = this.archiveList?.getSelectedPages?.() || []; if (!selectedPages.length) { @@ -389,7 +429,7 @@ class ArgoViewer extends LitElement { } firstUpdated() { - this.archiveList = this.shadowRoot?.getElementById( + this.archiveList = this.shadowRoot!.getElementById( "archive-list", ) as ArgoArchiveList; @@ -416,22 +456,42 @@ class ArgoViewer extends LitElement { }); } - registerMessages() { - // @ts-expect-error - TS2339 - Property 'port' does not exist on type 'ArgoViewer'. + private connectPort() { + // if already connected, do nothing + // @ts-expect-error + if (this.port) return; + // @ts-expect-error this.port = chrome.runtime.connect({ name: "sidepanel-port" }); + // @ts-expect-error + this.port.onMessage.addListener((msg) => this.onMessage(msg)); + // @ts-expect-error + this.port.onDisconnect.addListener(() => { + // clear so next sendMessage() will reconnect + console.warn("Port disconnected, will reconnect on next send."); + // @ts-expect-error + this.port = null; + }); + } + registerMessages() { + this.connectPort(); this.updateTabInfo(); - - // @ts-expect-error - TS2339 - Property 'port' does not exist on type 'ArgoViewer'. - this.port.onMessage.addListener((message) => { - this.onMessage(message); - }); } - // @ts-expect-error - TS7006 - Parameter 'message' implicitly has an 'any' type. - sendMessage(message) { - // @ts-expect-error - TS2339 - Property 'port' does not exist on type 'ArgoViewer'. - this.port.postMessage(message); + private sendMessage(message: any) { + // reconnect if needed + // @ts-expect-error + if (!this.port) this.connectPort(); + try { + // @ts-expect-error + this.port!.postMessage(message); + } catch (e) { + console.warn( + "Port died while sending, retrying via chrome.runtime.sendMessage", + e, + ); + chrome.runtime.sendMessage(message); + } } // @ts-expect-error - TS7006 - Parameter 'message' implicitly has an 'any' type. async onMessage(message) { @@ -439,6 +499,11 @@ class ArgoViewer extends LitElement { case "update": this.updateTabInfo(); break; + + case "pages": + // @ts-expect-error — pages is internal to the list + this.archiveList.pages = message.pages; + break; case "status": // @ts-expect-error - TS2339 - Property 'tabId' does not exist on type 'ArgoViewer'. if (this.tabId !== message.tabId) { @@ -704,7 +769,7 @@ class ArgoViewer extends LitElement { style="color: white; border-radius: 9999px; align-self: flex-end;" @click=${this.onShareCurrent} > - share + share Share Current Page ` : "" @@ -816,25 +881,86 @@ class ArgoViewer extends LitElement { renderTabs() { return html` - - My Archives + +
- My Shared Archives + My Archives + My Shared Archives + +
+ + +
- +
+
+ { + this.archiveList.clearSelection(); + //@ts-expect-error + this.selectedCount = 0; + }} + > + clear + + ${ + //@ts-expect-error + this.selectedCount + } + selected +
+ +
+ download + share + delete +
+
+ +
+ +
+ // @ts-expect-error + (this.selectedCount = e.detail.count)} >
${this.renderStatusCard()} @@ -868,19 +994,6 @@ class ArgoViewer extends LitElement { public Resume Archiving - - download - - - - share - ` : html`