diff --git a/frontend/src/index.ejs b/frontend/src/index.ejs index dc4d3aa1..d3e21b6b 100644 --- a/frontend/src/index.ejs +++ b/frontend/src/index.ejs @@ -1,5 +1,5 @@ - - + + - - - - - + + + + + { if (!reg) { @@ -184,15 +192,33 @@ export class ArchivedItemQA extends TailwindElement { }); window.addEventListener("message", this.onWindowMessage); + window.addEventListener("scroll", this.onWindowScroll); } disconnectedCallback(): void { super.disconnectedCallback(); + if (this.crawlData?.blobUrl) URL.revokeObjectURL(this.crawlData.blobUrl); if (this.qaData?.blobUrl) URL.revokeObjectURL(this.qaData.blobUrl); + window.removeEventListener("message", this.onWindowMessage); + window.addEventListener("scroll", this.onWindowScroll); } + private scrollY = 0; + private readonly onWindowScroll = throttle(100)(() => { + // Set scroll snap only when scrolling down + if (window.scrollY > this.scrollY) { + if (!document.documentElement.classList.contains(tw`snap-y`)) { + document.documentElement.classList.add(tw`snap-y`); + } + } else { + document.documentElement.classList.remove(tw`snap-y`); + } + + this.scrollY = window.scrollY; + }); + private readonly onWindowMessage = (event: MessageEvent) => { const sourceLoc = (event.source as Window | null)?.location.href; @@ -255,10 +281,14 @@ export class ArchivedItemQA extends TailwindElement { URL.revokeObjectURL(this.crawlData.blobUrl); if (this.qaData?.blobUrl) URL.revokeObjectURL(this.qaData.blobUrl); - // FIXME Set to null to render loading state, should be refactored - // to handle loading state separately in https://github.com/webrecorder/browsertrix/issues/1716 - this.crawlData = null; - this.qaData = null; + if (this.tab === "replay") { + this.showReplayPageLoadingDialog(); + } else { + // FIXME Set to null to render loading state, should be refactored + // to handle loading state separately in https://github.com/webrecorder/browsertrix/issues/1716 + this.crawlData = null; + this.qaData = null; + } } // TODO prefetch content for other tabs? void this.fetchContentForTab(); @@ -364,7 +394,7 @@ export class ArchivedItemQA extends TailwindElement { -
+
@@ -699,7 +729,7 @@ export class ArchivedItemQA extends TailwindElement { return html` @@ -801,14 +831,36 @@ export class ArchivedItemQA extends TailwindElement { private renderPanelToolbar() { const buttons = html` ${choose(this.tab, [ - // [ - // "replay", - // () => html` - //
- // - //
- // `, - // ], + [ + "replay", + () => html` +
+ + { + if ( + this.interactiveReplayFrame?.contentDocument + ?.readyState === "complete" + ) { + this.isReloadingReplay = true; + this.showReplayPageLoadingDialog(); + this.interactiveReplayFrame.contentWindow?.location.reload(); + } + }} + > + + + +
+ `, + ], [ "screenshots", () => html` @@ -875,18 +927,118 @@ export class ArchivedItemQA extends TailwindElement { case "resources": return renderResources(this.crawlData, this.qaData); case "replay": - return renderReplay(this.crawlData); + return this.renderReplay(); default: break; } }; return html` -
+
${cache(choosePanel())}
`; } + private renderReplay() { + return html` +
+
+ ${when( + this.crawlData?.replayUrl, + (replayUrl) => + html``, + )} +
+ e.preventDefault()} + > +
${msg("Loading page")}
+ +
+ + ${msg("Following links during review is disabled.")} + +
+ `; + } + private readonly renderRWP = (rwpId: string, { qa }: { qa: boolean }) => { if (!rwpId) return; @@ -956,6 +1108,14 @@ export class ArchivedItemQA extends TailwindElement { } } + private showReplayPageLoadingDialog() { + if (!this.interactiveReplayFrame) return; + void this.interactiveReplayFrame + .closest(".replayContainer") + ?.querySelector("btrix-dialog.loadingPageDialog") + ?.show(); + } + private async onSubmitComment(e: SubmitEvent) { e.preventDefault(); const value = this.commentTextarea?.value; @@ -1141,7 +1301,7 @@ export class ArchivedItemQA extends TailwindElement { const page = this.page; const tab = this.tab; const sourceId = qa ? this.qaRunId : this.itemId; - const frameWindow = this.replayFrame?.contentWindow; + const frameWindow = this.hiddenReplayFrame?.contentWindow; if (!page || !sourceId || !frameWindow) { console.debug( @@ -1166,8 +1326,6 @@ export class ArchivedItemQA extends TailwindElement { const url = `/replay/w/${sourceId}/${urlPart}`; // TODO check status code - console.log("replay?"); - const resp = await frameWindow.fetch(url); //console.log("resp:", resp); diff --git a/frontend/src/pages/org/archived-item-qa/ui/replay.ts b/frontend/src/pages/org/archived-item-qa/ui/replay.ts deleted file mode 100644 index d3343a0f..00000000 --- a/frontend/src/pages/org/archived-item-qa/ui/replay.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { html } from "lit"; -import { guard } from "lit/directives/guard.js"; -import { when } from "lit/directives/when.js"; - -import type { ReplayData } from "../types"; - -import { renderSpinner } from "./spinner"; - -import { tw } from "@/utils/tailwind"; - -export function renderReplay(crawlData: ReplayData) { - return html` -
- ${guard([crawlData], () => - when( - crawlData?.replayUrl, - (replayUrl) => - html``, - renderSpinner, - ), - )} -
- `; -} diff --git a/frontend/src/theme.stylesheet.css b/frontend/src/theme.stylesheet.css index 1efd27ce..b421f37d 100644 --- a/frontend/src/theme.stylesheet.css +++ b/frontend/src/theme.stylesheet.css @@ -345,3 +345,17 @@ [class*=" hover\:text-"]::part(base):hover { color: inherit; } + +/* Fix scrollbar gutter not actually */ +html { + overflow: auto; + scrollbar-gutter: stable; +} + +body.sl-scroll-lock { + scrollbar-gutter: auto !important; +} +/* Leave document scrollable now for replay.ts embedded dialogs */ +/* html:has(body.sl-scroll-lock) { + overflow: hidden; +} */