Skip to content

Commit 3c6bc13

Browse files
Merge pull request #32 from Monadical-SAS/nikita-progressive-disclosure
feat: move action buttons; implement the delete button
2 parents 7ea27f5 + f9a206c commit 3c6bc13

3 files changed

Lines changed: 184 additions & 43 deletions

File tree

src/argo-archive-list.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,16 @@ export class ArgoArchiveList extends LitElement {
210210
}
211211
}
212212

213-
private buildIndex() {
214-
this.flex = new FlexIndex();
215-
this.pages.forEach((p) => {
216-
const text = p.url + (p.title ? ` ${p.title}` : "");
217-
this.flex.add(p.ts, text); // use ts (timestamp) as a unique id
218-
});
213+
public clearSelection() {
214+
this.selectedPages = new Set();
215+
this.requestUpdate();
216+
this.dispatchEvent(
217+
new CustomEvent("selection-change", {
218+
detail: { count: 0 },
219+
bubbles: true,
220+
composed: true,
221+
}),
222+
);
219223
}
220224

221225
private togglePageSelection(ts: string) {
@@ -226,6 +230,13 @@ export class ArgoArchiveList extends LitElement {
226230
next.add(ts);
227231
}
228232
this.selectedPages = next;
233+
this.dispatchEvent(
234+
new CustomEvent("selection-change", {
235+
detail: { count: this.selectedPages.size },
236+
bubbles: true,
237+
composed: true,
238+
}),
239+
);
229240
}
230241

231242
public getSelectedPages() {
@@ -342,6 +353,7 @@ export class ArgoArchiveList extends LitElement {
342353
<md-checkbox
343354
slot="start"
344355
touch-target="wrapper"
356+
.checked=${this.selectedPages.has(page.ts)}
345357
@click=${(e: Event) => {
346358
e.stopPropagation();
347359
this.togglePageSelection(page.ts);

src/ext/bg.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { BrowserRecorder } from "./browser-recorder";
33
import { CollectionLoader } from "@webrecorder/wabac/swlib";
44

55
import { listAllMsg } from "../utils";
6-
76
import {
87
getLocalOption,
98
removeLocalOption,
@@ -110,6 +109,23 @@ function sidepanelHandler(port) {
110109
break;
111110
}
112111

112+
case "deletePages": {
113+
const defaultCollId = await getLocalOption("defaultCollId");
114+
if (!defaultCollId) {
115+
return;
116+
}
117+
const coll = await collLoader.loadColl(defaultCollId);
118+
119+
for (const id of message.pageIds) {
120+
await coll.store.deletePage(id);
121+
}
122+
123+
// now re-send the new list of pages
124+
const pages = await coll.store.getAllPages();
125+
port.postMessage({ type: "pages", pages });
126+
break;
127+
}
128+
113129
case "startRecording": {
114130
isRecordingEnabled = true;
115131
defaultCollId = message.collId;

src/sidepanel.ts

Lines changed: 149 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import "@material/web/icon/icon.js";
88
import { ArgoArchiveList } from "./argo-archive-list";
99
import { Downloader } from "./sw/downloader";
1010

11-
import wrRec from "./assets/icons/recLogo.svg";
12-
1311
import {
1412
getLocalOption,
1513
// removeLocalOption,
@@ -128,6 +126,35 @@ class ArgoViewer extends LitElement {
128126
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.6));
129127
}
130128
129+
/* Fade overlay styles */
130+
.tabs-wrapper {
131+
position: relative;
132+
}
133+
134+
.tabs-overlay {
135+
transition: opacity 0.3s ease;
136+
}
137+
.tabs-overlay.inactive {
138+
opacity: 0;
139+
pointer-events: none;
140+
}
141+
142+
.actions-overlay {
143+
position: absolute;
144+
top: 0;
145+
left: 0;
146+
width: 100%;
147+
transition: opacity 0.3s ease;
148+
opacity: 0;
149+
pointer-events: none;
150+
background: white;
151+
z-index: 1;
152+
}
153+
.actions-overlay.active {
154+
opacity: 1;
155+
pointer-events: auto;
156+
}
157+
131158
md-icon[filled] {
132159
font-variation-settings: "FILL" 1;
133160
}
@@ -137,6 +164,8 @@ class ArgoViewer extends LitElement {
137164
private archiveList!: ArgoArchiveList;
138165
constructor() {
139166
super();
167+
// @ts-expect-error - TS2339 - Property 'selectedCount' does not exist on type 'ArgoViewer'.
168+
this.selectedCount = 0;
140169
// @ts-expect-error - TS2339 - Property 'searchQuery' does not exist on type 'ArgoViewer'.
141170
this.searchQuery = "";
142171
// @ts-expect-error - TS2339 - Property 'collections' does not exist on type 'ArgoViewer'.
@@ -193,6 +222,7 @@ class ArgoViewer extends LitElement {
193222
static get properties() {
194223
return {
195224
searchQuery: { type: String },
225+
selectedCount: { type: Number },
196226
collections: { type: Array },
197227
collId: { type: String },
198228
collTitle: { type: String },
@@ -250,6 +280,16 @@ class ArgoViewer extends LitElement {
250280
})[0];
251281
}
252282

283+
onDeleteSelected() {
284+
const pages = this.archiveList.getSelectedPages();
285+
const ids = pages.map((p) => p.id);
286+
this.sendMessage({ type: "deletePages", pageIds: ids });
287+
// then clear UI
288+
this.archiveList.clearSelection();
289+
// @ts-expect-error - TS2339 - Property 'selectedCount' does not exist on type 'ArgoViewer'.
290+
this.selectedCount = 0;
291+
}
292+
253293
private async onDownload() {
254294
const selectedPages = this.archiveList?.getSelectedPages?.() || [];
255295
if (!selectedPages.length) {
@@ -389,7 +429,7 @@ class ArgoViewer extends LitElement {
389429
}
390430

391431
firstUpdated() {
392-
this.archiveList = this.shadowRoot?.getElementById(
432+
this.archiveList = this.shadowRoot!.getElementById(
393433
"archive-list",
394434
) as ArgoArchiveList;
395435

@@ -416,29 +456,54 @@ class ArgoViewer extends LitElement {
416456
});
417457
}
418458

419-
registerMessages() {
420-
// @ts-expect-error - TS2339 - Property 'port' does not exist on type 'ArgoViewer'.
459+
private connectPort() {
460+
// if already connected, do nothing
461+
// @ts-expect-error
462+
if (this.port) return;
463+
// @ts-expect-error
421464
this.port = chrome.runtime.connect({ name: "sidepanel-port" });
465+
// @ts-expect-error
466+
this.port.onMessage.addListener((msg) => this.onMessage(msg));
467+
// @ts-expect-error
468+
this.port.onDisconnect.addListener(() => {
469+
// clear so next sendMessage() will reconnect
470+
console.warn("Port disconnected, will reconnect on next send.");
471+
// @ts-expect-error
472+
this.port = null;
473+
});
474+
}
422475

476+
registerMessages() {
477+
this.connectPort();
423478
this.updateTabInfo();
424-
425-
// @ts-expect-error - TS2339 - Property 'port' does not exist on type 'ArgoViewer'.
426-
this.port.onMessage.addListener((message) => {
427-
this.onMessage(message);
428-
});
429479
}
430480

431-
// @ts-expect-error - TS7006 - Parameter 'message' implicitly has an 'any' type.
432-
sendMessage(message) {
433-
// @ts-expect-error - TS2339 - Property 'port' does not exist on type 'ArgoViewer'.
434-
this.port.postMessage(message);
481+
private sendMessage(message: any) {
482+
// reconnect if needed
483+
// @ts-expect-error
484+
if (!this.port) this.connectPort();
485+
try {
486+
// @ts-expect-error
487+
this.port!.postMessage(message);
488+
} catch (e) {
489+
console.warn(
490+
"Port died while sending, retrying via chrome.runtime.sendMessage",
491+
e,
492+
);
493+
chrome.runtime.sendMessage(message);
494+
}
435495
}
436496
// @ts-expect-error - TS7006 - Parameter 'message' implicitly has an 'any' type.
437497
async onMessage(message) {
438498
switch (message.type) {
439499
case "update":
440500
this.updateTabInfo();
441501
break;
502+
503+
case "pages":
504+
// @ts-expect-error — pages is internal to the list
505+
this.archiveList.pages = message.pages;
506+
break;
442507
case "status":
443508
// @ts-expect-error - TS2339 - Property 'tabId' does not exist on type 'ArgoViewer'.
444509
if (this.tabId !== message.tabId) {
@@ -704,7 +769,7 @@ class ArgoViewer extends LitElement {
704769
style="color: white; border-radius: 9999px; align-self: flex-end;"
705770
@click=${this.onShareCurrent}
706771
>
707-
<md-icon slot="icon" style="color:white">share</md-icon>
772+
<md-icon slot="icon" style="color:#444">share</md-icon>
708773
Share Current Page
709774
</md-filled-button> `
710775
: ""
@@ -816,25 +881,86 @@ class ArgoViewer extends LitElement {
816881

817882
renderTabs() {
818883
return html`
819-
<md-tabs id="tabs" aria-label="Archive tabs">
820-
<md-primary-tab class="md-typescale-label-large"
821-
>My Archives</md-primary-tab
884+
<div class="tabs-wrapper">
885+
<!-- Original tabs overlay -->
886+
<div
887+
class="tabs-overlay ${
888+
//@ts-expect-error
889+
this.selectedCount > 0 ? "inactive" : ""
890+
}"
822891
>
823-
<md-primary-tab class="md-typescale-label-large"
824-
>My Shared Archives</md-primary-tab
892+
<md-tabs id="tabs" aria-label="Archive tabs">
893+
<md-primary-tab class="md-typescale-label-large"
894+
>My Archives</md-primary-tab
895+
>
896+
<md-primary-tab class="md-typescale-label-large"
897+
>My Shared Archives</md-primary-tab
898+
>
899+
</md-tabs>
900+
</div>
901+
902+
<!-- Actions overlay on selection -->
903+
<div
904+
class="actions-overlay ${
905+
//@ts-expect-error
906+
this.selectedCount > 0 ? "active" : ""
907+
}"
825908
>
826-
</md-tabs>
909+
<div
910+
style="display:flex; align-items:center; justify-content:space-between; padding: 0.25rem 1rem;"
911+
>
912+
<div style="display:flex; align-items:center; gap: 0.5rem;">
913+
<md-icon-button
914+
aria-label="Deselect All"
915+
@click=${() => {
916+
this.archiveList.clearSelection();
917+
//@ts-expect-error
918+
this.selectedCount = 0;
919+
}}
920+
>
921+
<md-icon style="color: gray">clear</md-icon>
922+
</md-icon-button>
923+
<span class="md-typescale-body-small"
924+
>${
925+
//@ts-expect-error
926+
this.selectedCount
927+
}
928+
selected</span
929+
>
930+
</div>
931+
932+
<div style="display:flex; align-items:center; gap: 0.5rem;">
933+
<md-icon-button aria-label="Download" @click=${this.onDownload}
934+
><md-icon>download</md-icon></md-icon-button
935+
>
936+
<md-icon-button aria-label="Share" @click=${this.onShareSelected}
937+
><md-icon>share</md-icon></md-icon-button
938+
>
939+
<md-icon-button
940+
aria-label="Delete"
941+
@click=${this.onDeleteSelected}
942+
><md-icon>delete</md-icon></md-icon-button
943+
>
944+
</div>
945+
</div>
946+
<md-divider></md-divider>
947+
</div>
948+
</div>
827949
950+
<!-- Panels remain unchanged -->
828951
<div
829952
class="tab-panels"
830-
style="flex: 1; overflow-y: auto; position: relative; flex-grow: 1;"
953+
style="flex:1; overflow-y:auto; position:relative; flex-grow:1;"
954+
@selection-change=${(e: CustomEvent) =>
955+
// @ts-expect-error
956+
(this.selectedCount = e.detail.count)}
831957
>
832958
<div id="my-archives" class="tab-panel" active>
833959
${this.renderStatusCard()}
834960
<argo-archive-list
835961
id="archive-list"
836962
.filterQuery=${
837-
//@ts-expect-error - TS2339 - Property 'searchQuery' does not exist on type 'ArgoViewer'.
963+
// @ts-expect-error
838964
this.searchQuery
839965
}
840966
></argo-archive-list>
@@ -868,19 +994,6 @@ class ArgoViewer extends LitElement {
868994
<md-icon slot="icon" style="color:white">public</md-icon>
869995
Resume Archiving
870996
</md-filled-button>
871-
<md-icon-button
872-
aria-label="Download"
873-
@click=${this.onDownload}
874-
>
875-
<md-icon style="color: gray;">download</md-icon>
876-
</md-icon-button>
877-
878-
<md-icon-button
879-
aria-label="Share"
880-
@click=${this.onShareSelected}
881-
>
882-
<md-icon style="color: gray;">share</md-icon>
883-
</md-icon-button>
884997
`
885998
: html`
886999
<md-outlined-button

0 commit comments

Comments
 (0)