Closes https://github.com/webrecorder/replayweb.page/issues/523, closes
https://github.com/webrecorder/replayweb.page/issues/396, closes
https://github.com/webrecorder/replayweb.page/issues/470, closes
https://github.com/webrecorder/replayweb.page/issues/237

## Changes

https://github.com/webrecorder/replayweb.page/pull/521
- Adds public `navigateReplayTo` method in `<replay-app-main>` that
allows embeds to control replay navigation directly without reloading
entire UI.
- Enables reloading `<wr-coll-replay>` iframe even if source URL hasn't
changed.
- Refactors lifecycle events to prevent unnecessary re-renders.

https://github.com/webrecorder/replayweb.page/pull/524
- Fixes incorrect page count shown
- Enables non-seed pages by default
- Improves UX and accessibility of scrolling to load more by displaying
help text

https://github.com/webrecorder/replayweb.page/pull/525
- Updates general styles and icons throughout to match Browsertrix
styles
- Allows deep customization of components with `part` and `exportparts`

https://github.com/webrecorder/replayweb.page/pull/526
- Enables importing Shoelace (ie Bootstrap) icons as inline SVG
- Updates location bar buttons to use Bootstrap icons
- Replaces deprecated raw-loader with Webpack-native asset rule

https://github.com/webrecorder/replayweb.page/pull/529
- Allows hiding collection metadata in embed.
- Moves non-seed toggle next to search bar to match resources controls
and enable hiding entire column when metadata is hidden.

https://github.com/webrecorder/replayweb.page/pull/533
- Fix non-seed pages toggle

https://github.com/webrecorder/replayweb.page/pull/535,
https://github.com/webrecorder/replayweb.page/pull/534
- Upgrade to Node 22 and Yarn 4

---------

Co-authored-by: Ilya Kreymer <ikreymer@gmail.com>
Co-authored-by: Misty De Méo <hi@mistydemeo.com>
This commit is contained in:
sua yoo
2026-08-07 16:05:09 -07:00
committed by GitHub
co-authored by Ilya Kreymer Misty De Méo
parent 830468e03a
commit 141d35d687
31 changed files with 10637 additions and 7622 deletions
+35 -20
View File
@@ -13,6 +13,7 @@ import { property, query } from "lit/decorators.js";
import type { FavIconEventDetail } from "./types";
import type { EmbedReplayData } from "./item";
import type { RwpPageLoadingEvent, RwpUrlChangeEvent } from "./events";
import type { ReplayWebApp } from "./appmain";
type IframeMessage = MessageEvent<
| RwpUrlChangeEvent["detail"]
@@ -67,6 +68,7 @@ class Embed extends LitElement {
@property({ type: Boolean }) hideOffscreen: boolean | undefined;
@property({ type: Boolean }) noMediaDownload = false;
@property({ type: Boolean }) hideMetadataSidebar = false;
@property({ type: Boolean }) useAdblock = false;
@property({ type: String }) adblockRulesUrl = DEFAULT_ADBLOCK_FILE;
@@ -88,6 +90,8 @@ class Embed extends LitElement {
@query("iframe")
private readonly iframe?: HTMLIFrameElement | null;
mainElement?: ReplayWebApp | null;
replayfile = defaultReplayFile;
mainElementName = "replay-app-main";
appName = "ReplayWeb.page";
@@ -267,20 +271,16 @@ class Embed extends LitElement {
const qs = new URLSearchParams(window.location.hash.slice(1));
if (qs.has("url")) {
// @ts-expect-error - TS2339 - Property 'url' does not exist on type 'Embed'.
this.url = qs.get("url");
this.url = qs.get("url") ?? "";
}
if (qs.has("ts")) {
// @ts-expect-error - TS2339 - Property 'ts' does not exist on type 'Embed'.
this.ts = qs.get("ts");
this.ts = qs.get("ts") ?? "";
}
if (qs.has("query")) {
// @ts-expect-error - TS2339 - Property 'query' does not exist on type 'Embed'.
this.query = qs.get("query");
this.query = qs.get("query") ?? "";
}
if (qs.has("view")) {
// @ts-expect-error - TS2339 - Property 'view' does not exist on type 'Embed'.
this.view = qs.get("view");
this.view = qs.get("view") ?? "";
}
}
@@ -333,6 +333,7 @@ class Embed extends LitElement {
ruffle?: "1";
adblockUrl?: string;
noMediaDownload?: string;
hideMetadataSidebar?: string;
} = {
source,
customColl: this.coll,
@@ -378,6 +379,10 @@ class Embed extends LitElement {
params.noMediaDownload = "1";
}
if (this.hideMetadataSidebar) {
params.hideMetadataSidebar = "1";
}
this.paramString = new URLSearchParams(
// Converting to unknown here so that we can ignore the URL -> string conversion necessary for the types to work out
params as unknown as Record<string, string>,
@@ -452,30 +457,40 @@ class Embed extends LitElement {
`;
}
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'event' implicitly has an 'any' type.
onLoad(event) {
onLoad(event: Event) {
if (this.isCrossOrigin) {
return;
}
const win = event.target.contentWindow;
const doc = event.target.contentDocument;
const target = event.target as HTMLIFrameElement;
const win = target.contentWindow;
const doc = target.contentDocument;
if (
win.navigator.serviceWorker &&
!win.navigator.serviceWorker.controller &&
this.reloadCount <= 2
) {
if (!win) {
console.debug("missing `event.target.contentWindow`");
return;
}
if (!win.navigator.serviceWorker.controller && this.reloadCount <= 2) {
this.reloadCount++;
// TODO: Fix this the next time the file is edited.
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
setTimeout(() => win.location.reload(), 100);
return;
}
this.reloadCount = 0;
if (win.customElements.get(this.mainElementName)) {
if (!doc) {
console.debug("missing `event.target.contentDocument`");
return;
}
if (win?.customElements.get(this.mainElementName)) {
this.mainElement = doc.querySelector(this.mainElementName);
return;
}
if (!scriptSrc) {
console.debug("missing `scriptSrc`");
return;
}