v2.5.0 (#527)
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:
co-authored by
Ilya Kreymer
Misty De Méo
parent
830468e03a
commit
141d35d687
@@ -18,11 +18,13 @@ jobs:
|
|||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up corepack
|
||||||
|
run: corepack enable yarn
|
||||||
|
|
||||||
- name: Install Node.js, NPM and Yarn
|
- name: Install Node.js, NPM and Yarn
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: 22
|
||||||
cache: 'yarn'
|
|
||||||
|
|
||||||
- name: Cache Dirs
|
- name: Cache Dirs
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@@ -36,7 +38,7 @@ jobs:
|
|||||||
- name: Update Ruffle
|
- name: Update Ruffle
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: yarn run update-ruffle
|
run: node --run update-ruffle
|
||||||
|
|
||||||
- name: Run Build
|
- name: Run Build
|
||||||
env:
|
env:
|
||||||
@@ -58,9 +60,9 @@ jobs:
|
|||||||
#fi
|
#fi
|
||||||
|
|
||||||
if [ "$GITHUB_REF" == "refs/heads/main" ] || [ -f ./force_release ]; then
|
if [ "$GITHUB_REF" == "refs/heads/main" ] || [ -f ./force_release ]; then
|
||||||
export YARN_BUILD_CMD="release"
|
export BUILD_CMD="release"
|
||||||
else
|
else
|
||||||
export YARN_BUILD_CMD="dist"
|
export BUILD_CMD="dist"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||||
@@ -73,12 +75,12 @@ jobs:
|
|||||||
docker run --rm \
|
docker run --rm \
|
||||||
-e CI=${CI} \
|
-e CI=${CI} \
|
||||||
-e GH_TOKEN=${GH_TOKEN} \
|
-e GH_TOKEN=${GH_TOKEN} \
|
||||||
-e YARN_BUILD_CMD=${YARN_BUILD_CMD} \
|
-e BUILD_CMD=${BUILD_CMD} \
|
||||||
-v ${PWD}:/project \
|
-v ${PWD}:/project \
|
||||||
-v ~/.cache/electron:/root/.cache/electron \
|
-v ~/.cache/electron:/root/.cache/electron \
|
||||||
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
|
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
|
||||||
electronuserland/builder:14-wine-05.22 \
|
electronuserland/builder:22-wine \
|
||||||
/bin/bash -c "yarn --link-duplicates --pure-lockfile --ignore-engines install && yarn run $YARN_BUILD_CMD --linux --x64"
|
/bin/bash -c "corepack enable yarn && yarn install --immutable && yarn run $BUILD_CMD --linux --x64"
|
||||||
else
|
else
|
||||||
#mkdir -p plugins-win;
|
#mkdir -p plugins-win;
|
||||||
#pushd plugins-win;
|
#pushd plugins-win;
|
||||||
@@ -91,12 +93,12 @@ jobs:
|
|||||||
-e GH_TOKEN=${GH_TOKEN} \
|
-e GH_TOKEN=${GH_TOKEN} \
|
||||||
-e WIN_CSC_LINK=${WIN_CSC_LINK} \
|
-e WIN_CSC_LINK=${WIN_CSC_LINK} \
|
||||||
-e WIN_CSC_KEY_PASSWORD=${WIN_CSC_KEY_PASSWORD} \
|
-e WIN_CSC_KEY_PASSWORD=${WIN_CSC_KEY_PASSWORD} \
|
||||||
-e YARN_BUILD_CMD=${YARN_BUILD_CMD} \
|
-e BUILD_CMD=${BUILD_CMD} \
|
||||||
-v ${PWD}:/project \
|
-v ${PWD}:/project \
|
||||||
-v ~/.cache/electron:/root/.cache/electron \
|
-v ~/.cache/electron:/root/.cache/electron \
|
||||||
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
|
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
|
||||||
electronuserland/builder:14-wine-05.22 \
|
electronuserland/builder:22-wine \
|
||||||
/bin/bash -c "yarn --link-duplicates --pure-lockfile --ignore-engines install && yarn run $YARN_BUILD_CMD --win --x64 --ia32"
|
/bin/bash -c "corepack enable yarn && yarn install --immutable && yarn run $BUILD_CMD --win --x64 --ia32"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
#mkdir -p plugins-mac;
|
#mkdir -p plugins-mac;
|
||||||
@@ -105,7 +107,7 @@ jobs:
|
|||||||
#unzip PepperFlashPlayer.plugin.zip;
|
#unzip PepperFlashPlayer.plugin.zip;
|
||||||
#rm PepperFlashPlayer.plugin.zip;
|
#rm PepperFlashPlayer.plugin.zip;
|
||||||
#popd;
|
#popd;
|
||||||
yarn --link-duplicates --pure-lockfile --ignore-engines install
|
yarn install --immutable
|
||||||
yarn run $YARN_BUILD_CMD
|
yarn run $BUILD_CMD
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,13 @@ jobs:
|
|||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up corepack
|
||||||
|
run: corepack enable yarn
|
||||||
|
|
||||||
- name: Install Node.js, NPM and Yarn
|
- name: Install Node.js, NPM and Yarn
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 22
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|
||||||
- name: Yarn Install
|
- name: Yarn Install
|
||||||
|
|||||||
@@ -10,14 +10,17 @@ jobs:
|
|||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up corepack
|
||||||
|
run: corepack enable yarn
|
||||||
|
|
||||||
- name: Install Node.js, NPM and Yarn
|
- name: Install Node.js, NPM and Yarn
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 22
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|
||||||
- name: Yarn Install
|
- name: Yarn Install
|
||||||
run: yarn install --frozen-lockfile --ignore-optional
|
run: yarn install --immutable
|
||||||
|
|
||||||
- name: Yarn Lint
|
- name: Yarn Lint
|
||||||
run: yarn lint
|
run: yarn lint
|
||||||
|
|||||||
@@ -12,14 +12,18 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
|
- name: Set up corepack
|
||||||
|
run: corepack enable yarn
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: "24.x"
|
node-version: "24.x"
|
||||||
registry-url: "https://registry.npmjs.org"
|
registry-url: "https://registry.npmjs.org"
|
||||||
cache: "yarn"
|
cache: "yarn"
|
||||||
|
|
||||||
- name: Yarn Install
|
- name: Yarn Install
|
||||||
run: yarn install --frozen-lockfile
|
run: yarn install --immutable
|
||||||
|
|
||||||
- name: Yarn Run Build
|
- name: Yarn Run Build
|
||||||
run: yarn run build
|
run: yarn run build
|
||||||
|
|||||||
@@ -20,14 +20,17 @@ jobs:
|
|||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up corepack
|
||||||
|
run: corepack enable yarn
|
||||||
|
|
||||||
- name: Install Node.js, NPM and Yarn
|
- name: Install Node.js, NPM and Yarn
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 22
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|
||||||
- name: Yarn Install
|
- name: Yarn Install
|
||||||
run: yarn install --frozen-lockfile
|
run: yarn install --immutable
|
||||||
|
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*.warc.gz
|
*.warc.gz
|
||||||
**/node_modules
|
**/node_modules
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
/.yarn/install-state.gz
|
||||||
coverage/
|
coverage/
|
||||||
**/local-examples/
|
**/local-examples/
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,8 @@
|
|||||||
|
approvedGitRepositories:
|
||||||
|
- "**"
|
||||||
|
|
||||||
|
enableScripts: true
|
||||||
|
|
||||||
|
nodeLinker: node-modules
|
||||||
|
|
||||||
|
npmMinimalAgeGate: 0
|
||||||
@@ -147,6 +147,7 @@ The `#!html <replay-web-page>` tag is a web component that supports a number of
|
|||||||
| `noWebWorker`| If set, will not use Web Worker for loading, only Service Worker. May be useful for certain loading edge cases. |
|
| `noWebWorker`| If set, will not use Web Worker for loading, only Service Worker. May be useful for certain loading edge cases. |
|
||||||
| `noCache` | If set, will not cache any loaded content HTTP responses locally, always loading from original source. |
|
| `noCache` | If set, will not cache any loaded content HTTP responses locally, always loading from original source. |
|
||||||
| `hideOffscreen` | If set, will unload the embed when it is not visible and reload when scrolled into view. Useful if multiple embeds per-page to avoid loading all at once. |
|
| `hideOffscreen` | If set, will unload the embed when it is not visible and reload when scrolled into view. Useful if multiple embeds per-page to avoid loading all at once. |
|
||||||
|
| `hideMetadataSidebar` | If set, will hide the sidebar shown on the page list. May be useful for embeds that show metadata elsewhere |
|
||||||
| `newWindowBase` | set base replay URL loaded when a page opens a new window, defaults to `https://replayweb.page/` if `deepLink` not enabled, otherwise, to current page with new link. |
|
| `newWindowBase` | set base replay URL loaded when a page opens a new window, defaults to `https://replayweb.page/` if `deepLink` not enabled, otherwise, to current page with new link. |
|
||||||
| `requireSubdomainIframe` | If set, will only load embed in an iframe loaded from a subdomain, for increased origin isolation. |
|
| `requireSubdomainIframe` | If set, will only load embed in an iframe loaded from a subdomain, for increased origin isolation. |
|
||||||
| `loading="eager"` | If set, will load the entire WACZ file at once (regardless of size), and not attempt on-demand range request loading. |
|
| `loading="eager"` | If set, will load the entire WACZ file at once (regardless of size), and not attempt on-demand range request loading. |
|
||||||
|
|||||||
+8
-5
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "replaywebpage",
|
"name": "replaywebpage",
|
||||||
"productName": "ReplayWeb.page",
|
"productName": "ReplayWeb.page",
|
||||||
"version": "2.4.7",
|
"version": "2.5.0-rc.2",
|
||||||
"description": "Serverless Web Archive Replay",
|
"description": "Serverless Web Archive Replay",
|
||||||
"repository": "https://github.com/webrecorder/replayweb.page",
|
"repository": "https://github.com/webrecorder/replayweb.page",
|
||||||
"homepage": "https://replayweb.page/",
|
"homepage": "https://replayweb.page/",
|
||||||
@@ -64,7 +64,6 @@
|
|||||||
"lint-staged": "^14.0.0",
|
"lint-staged": "^14.0.0",
|
||||||
"mini-css-extract-plugin": "^2.3.0",
|
"mini-css-extract-plugin": "^2.3.0",
|
||||||
"prettier": "^3.0.1",
|
"prettier": "^3.0.1",
|
||||||
"raw-loader": "^4.0.2",
|
|
||||||
"sass-embedded": "^1.70.0",
|
"sass-embedded": "^1.70.0",
|
||||||
"sass-loader": "^13.3.2",
|
"sass-loader": "^13.3.2",
|
||||||
"serve": "^14.2.4",
|
"serve": "^14.2.4",
|
||||||
@@ -78,7 +77,7 @@
|
|||||||
"webpack-merge": "^5.10.0"
|
"webpack-merge": "^5.10.0"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"**/lit": "3.1.1"
|
"lit": "3.1.1"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"/dist",
|
"/dist",
|
||||||
@@ -109,7 +108,7 @@
|
|||||||
"release": "yarn run build && electron-builder",
|
"release": "yarn run build && electron-builder",
|
||||||
"lint": "eslint ./",
|
"lint": "eslint ./",
|
||||||
"format": "prettier --write ./",
|
"format": "prettier --write ./",
|
||||||
"prepare": "husky install; node scripts/build-if-not-git-repo.js"
|
"prepare": "husky install; yarn node scripts/build-if-not-git-repo.js"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"afterSign": "build/notarize.js",
|
"afterSign": "build/notarize.js",
|
||||||
@@ -205,10 +204,14 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=22 <25"
|
||||||
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.ts": "prettier --write"
|
"*.ts": "prettier --write"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"trailingComma": "all"
|
"trailingComma": "all"
|
||||||
}
|
},
|
||||||
|
"packageManager": "yarn@4.17.1"
|
||||||
}
|
}
|
||||||
|
|||||||
+162
-84
@@ -6,7 +6,7 @@ import {
|
|||||||
type TemplateResult,
|
type TemplateResult,
|
||||||
type PropertyValues,
|
type PropertyValues,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property } from "lit/decorators.js";
|
import { customElement, property, query } from "lit/decorators.js";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
import {
|
import {
|
||||||
wrapCss,
|
wrapCss,
|
||||||
@@ -26,7 +26,13 @@ import { SWManager } from "./swmanager";
|
|||||||
import "./item";
|
import "./item";
|
||||||
import "./item-index";
|
import "./item-index";
|
||||||
import "./chooser";
|
import "./chooser";
|
||||||
import { type EmbedOpts, type LoadInfo } from "./item";
|
import {
|
||||||
|
type Item,
|
||||||
|
type EmbedOpts,
|
||||||
|
type LoadInfo,
|
||||||
|
RWP_SCHEME,
|
||||||
|
EmbedReplayDataView,
|
||||||
|
} from "./item";
|
||||||
import type { FavIconEventDetail } from "./types";
|
import type { FavIconEventDetail } from "./types";
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -47,6 +53,9 @@ export class ReplayWebApp extends LitElement {
|
|||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
showAbout = false;
|
showAbout = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
showAllPages = false;
|
||||||
|
|
||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
showFileDropOverlay = false;
|
showFileDropOverlay = false;
|
||||||
|
|
||||||
@@ -80,7 +89,40 @@ export class ReplayWebApp extends LitElement {
|
|||||||
@property({ type: String })
|
@property({ type: String })
|
||||||
swErrorMsg: TemplateResult<1> | string | null = null;
|
swErrorMsg: TemplateResult<1> | string | null = null;
|
||||||
|
|
||||||
protected swName?: string;
|
@query("wr-item")
|
||||||
|
private readonly item?: Item | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to a view in replay.
|
||||||
|
*
|
||||||
|
* @param {string} urlOrView - The page URL or view to navigate to.
|
||||||
|
* @param {Object|undefined} data - Optional view data.
|
||||||
|
*/
|
||||||
|
public navigateReplayTo(
|
||||||
|
urlOrView: EmbedReplayDataView | string,
|
||||||
|
data?: { ts: string },
|
||||||
|
) {
|
||||||
|
if (!this.item) {
|
||||||
|
console.debug("missing `this.item`");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = urlOrView;
|
||||||
|
|
||||||
|
if (
|
||||||
|
Object.values(EmbedReplayDataView).some(
|
||||||
|
(view) => (view as string) === urlOrView,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
value = `${RWP_SCHEME}view=${value}${
|
||||||
|
data ? `?${new URLSearchParams(data).toString()}` : ""
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.item.navigateTo(value, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
swName?: string;
|
||||||
protected swmanager: SWManager | null;
|
protected swmanager: SWManager | null;
|
||||||
private useRuffle = false;
|
private useRuffle = false;
|
||||||
|
|
||||||
@@ -219,6 +261,24 @@ export class ReplayWebApp extends LitElement {
|
|||||||
margin: 15px;
|
margin: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.about-dialog-header {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-dialog h3,
|
||||||
|
h4 {
|
||||||
|
font-weight: var(--sl-font-weight-bold);
|
||||||
|
margin-bottom: var(--sl-spacing-x-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-dialog p + p {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-dialog details p {
|
||||||
|
font-size: var(--sl-font-size-x-small);
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 840px) {
|
@media screen and (min-width: 840px) {
|
||||||
.menu-only {
|
.menu-only {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -404,11 +464,21 @@ export class ReplayWebApp extends LitElement {
|
|||||||
.embedOpts="${this.embedOpts}"
|
.embedOpts="${this.embedOpts}"
|
||||||
appName="${this.appName}"
|
appName="${this.appName}"
|
||||||
swName="${ifDefined(this.swName)}"
|
swName="${ifDefined(this.swName)}"
|
||||||
|
?showAllPages=${this.showAllPages}
|
||||||
@replay-favicons=${this.onFavIcons}
|
@replay-favicons=${this.onFavIcons}
|
||||||
@update-title=${this.onTitle}
|
@update-title=${this.onTitle}
|
||||||
@coll-loaded=${this.onCollLoaded}
|
@coll-loaded=${this.onCollLoaded}
|
||||||
@coll-load-cancel=${this.onCollLoadCancel}
|
@coll-load-cancel=${this.onCollLoadCancel}
|
||||||
@about-show=${() => (this.showAbout = true)}
|
@about-show=${() => (this.showAbout = true)}
|
||||||
|
exportparts="
|
||||||
|
replay-bar:wr-item__replay-bar,
|
||||||
|
replay-bar-container:wr-item__replay-bar-container,
|
||||||
|
replay-bar-input:wr-item__replay-bar-input,
|
||||||
|
replay-content:wr-item__replay-content,
|
||||||
|
replay-tabs-nav:wr-item__replay-tabs-nav,
|
||||||
|
replay-tabs-panel:wr-item__replay-tabs-panel,
|
||||||
|
replay-main:wr-item__replay-main,
|
||||||
|
"
|
||||||
></wr-item>`;
|
></wr-item>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,7 +520,7 @@ export class ReplayWebApp extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
${!this.embed || this.embed === "full" ? this.renderNavBar() : ""}
|
${!this.embed || this.embed === "full" ? this.renderNavBar() : ""}
|
||||||
${this.sourceUrl ? this.renderColl() : this.renderHomeIndex()}
|
${this.sourceUrl ? this.renderColl() : this.renderHomeIndex()}
|
||||||
${this.showAbout ? this.renderAbout() : ""}
|
${this.renderAbout()}
|
||||||
${this.showFileDropOverlay ? this.renderDropFileOverlay() : ""}
|
${this.showFileDropOverlay ? this.renderDropFileOverlay() : ""}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -595,6 +665,10 @@ export class ReplayWebApp extends LitElement {
|
|||||||
if (this.pageParams.has("noMediaDownload")) {
|
if (this.pageParams.has("noMediaDownload")) {
|
||||||
this.embedOpts = { ...this.embedOpts, noMediaDownloadUI: true };
|
this.embedOpts = { ...this.embedOpts, noMediaDownloadUI: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.pageParams.has("hideMetadataSidebar")) {
|
||||||
|
this.embedOpts = { ...this.embedOpts, hideMetadataSidebar: true };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.pageParams.get("config")) {
|
if (this.pageParams.get("config")) {
|
||||||
@@ -733,91 +807,95 @@ export class ReplayWebApp extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderAbout() {
|
renderAbout() {
|
||||||
return html`
|
return html` <sl-dialog
|
||||||
<div class="modal is-active">
|
class="about-dialog"
|
||||||
<div class="modal-background" @click="${this.onAboutClose}"></div>
|
label=${`About ReplayWeb.page ${IS_APP ? "App" : ""}`}
|
||||||
<div class="modal-card">
|
?open=${this.showAbout}
|
||||||
<header class="modal-card-head">
|
@sl-after-hide=${this.onAboutClose}
|
||||||
<p class="modal-card-title">About ReplayWeb.page ${
|
>
|
||||||
IS_APP ? "App" : ""
|
<div class="about-dialog-header">
|
||||||
}</p>
|
<div class="has-text-centered" style="width: 220px">
|
||||||
<button class="delete" aria-label="close" @click="${
|
<fa-icon
|
||||||
this.onAboutClose
|
size="3rem"
|
||||||
}"></button>
|
.svg=${rwpLogo}
|
||||||
</header>
|
aria-label="ReplayWeb.page Logo"
|
||||||
<section class="modal-card-body">
|
role="img"
|
||||||
<div class="container">
|
></fa-icon>
|
||||||
<div class="content">
|
<div style="font-size: smaller; margin-bottom: 1em">
|
||||||
<div style="display: flex">
|
${IS_APP ? "App" : ""} v${VERSION}
|
||||||
<div class="has-text-centered" style="width: 220px">
|
|
||||||
<fa-icon
|
|
||||||
size="3rem"
|
|
||||||
.svg=${rwpLogo}
|
|
||||||
aria-label="ReplayWeb.page Logo"
|
|
||||||
role="img"
|
|
||||||
></fa-icon>
|
|
||||||
<div style="font-size: smaller; margin-bottom: 1em">${
|
|
||||||
IS_APP ? "App" : ""
|
|
||||||
} v${VERSION}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
${
|
|
||||||
IS_APP
|
|
||||||
? html`
|
|
||||||
<p>
|
|
||||||
ReplayWeb.page App is a standalone app for Mac,
|
|
||||||
Windows and Linux that loads web archive files
|
|
||||||
provided by the user and renders them for replay.
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
: html` <p>
|
|
||||||
<a href="https://replayweb.page" target="_blank"
|
|
||||||
>ReplayWeb.page</a
|
|
||||||
>
|
|
||||||
is a browser-based viewer that loads web archive
|
|
||||||
files provided by the user and renders them for
|
|
||||||
replay in the browser.
|
|
||||||
</p>`
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>Full source code is available
|
|
||||||
<a href="https://github.com/webrecorder/replayweb.page" target="_blank">on GitHub</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>See the <a target="_blank" href="./docs">documentation</a> for more info on how it works.</p>
|
|
||||||
|
|
||||||
<p>ReplayWeb.page is developed by <a href="https://webrecorder.net/" target="_blank">Webrecorder</a>.</p>
|
|
||||||
|
|
||||||
<h3>Privacy</h3>
|
|
||||||
<p><b>No data is uploaded anywhere and no information is collected.</b></p>
|
|
||||||
<p>All content rendered stays directly in your browser.<br/>When loading an archive from Google Drive,
|
|
||||||
the site may ask for account authorization to download the specified file only.</p>
|
|
||||||
|
|
||||||
<h4>Disclaimer of Warranties</h4>
|
|
||||||
<p>The application is provided "as is" without any guarantees.</p>
|
|
||||||
<details>
|
|
||||||
<summary>Legalese:</summary>
|
|
||||||
<p style="font-size: 0.8rem">DISCLAIMER OF SOFTWARE WARRANTY. WEBRECORDER SOFTWARE PROVIDES THIS SOFTWARE TO YOU "AS AVAILABLE"
|
|
||||||
AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
|
|
||||||
INCLUDING WITHOUT LIMITATION ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.</p>
|
|
||||||
</details>
|
|
||||||
<div class="has-text-centered">
|
|
||||||
<a class="button is-warning" href="#" @click="${
|
|
||||||
this.onAboutClose
|
|
||||||
}">Close</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
|
||||||
|
${IS_APP
|
||||||
|
? html`
|
||||||
|
<p>
|
||||||
|
ReplayWeb.page App is a standalone app for Mac, Windows and
|
||||||
|
Linux that loads web archive files provided by the user and
|
||||||
|
renders them for replay.
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
: html` <p>
|
||||||
|
<a href="https://replayweb.page" target="_blank"
|
||||||
|
>ReplayWeb.page</a
|
||||||
|
>
|
||||||
|
is a browser-based viewer that loads web archive files provided by
|
||||||
|
the user and renders them for replay in the browser.
|
||||||
|
</p>`}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Full source code is available
|
||||||
|
<a href="https://github.com/webrecorder/replayweb.page" target="_blank"
|
||||||
|
>on GitHub</a
|
||||||
|
>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
See the <a target="_blank" href="./docs">documentation</a> for more info
|
||||||
|
on how it works.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
ReplayWeb.page is developed by
|
||||||
|
<a href="https://webrecorder.net/" target="_blank">Webrecorder</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<sl-divider></sl-divider>
|
||||||
|
<h3>Privacy</h3>
|
||||||
|
<p>No data is uploaded anywhere and no information is collected.</p>
|
||||||
|
<details>
|
||||||
|
<summary>More info</summary>
|
||||||
|
<p>
|
||||||
|
All content rendered stays directly in your browser.<br />When loading
|
||||||
|
an archive from Google Drive, the site may ask for account
|
||||||
|
authorization to download the specified file only.
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
<sl-divider></sl-divider>
|
||||||
|
<h4>Disclaimer of Warranties</h4>
|
||||||
|
<p>The application is provided "as is" without any guarantees.</p>
|
||||||
|
<details>
|
||||||
|
<summary>Legal</summary>
|
||||||
|
<p>
|
||||||
|
DISCLAIMER OF SOFTWARE WARRANTY. WEBRECORDER SOFTWARE PROVIDES THIS
|
||||||
|
SOFTWARE TO YOU "AS AVAILABLE" AND WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION ANY
|
||||||
|
WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
<sl-button
|
||||||
|
slot="footer"
|
||||||
|
variant="primary"
|
||||||
|
size="small"
|
||||||
|
@click="${this.onAboutClose}"
|
||||||
|
>Close</sl-button
|
||||||
|
>
|
||||||
|
</sl-dialog>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
onAboutClose() {
|
readonly onAboutClose = () => {
|
||||||
this.showAbout = false;
|
this.showAbout = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
renderDropFileOverlay() {
|
renderDropFileOverlay() {
|
||||||
return html`
|
return html`
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@charset "utf-8";
|
@charset "utf-8";
|
||||||
|
|
||||||
@import "@shoelace-style/shoelace/dist/themes/light.css";
|
@import "@shoelace-style/shoelace/dist/themes/light.css";
|
||||||
|
@import "./shoelace.scss";
|
||||||
|
|
||||||
/*$wr-green: #64e986;*/
|
/*$wr-green: #64e986;*/
|
||||||
$wr-green: #55be6f;
|
$wr-green: #55be6f;
|
||||||
@@ -151,3 +152,20 @@ a:focus {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update size of small icons in controls
|
||||||
|
.control.has-icons-left .icon.is-small, .control.has-icons-right .icon.is-small {
|
||||||
|
margin-top: 1px;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
font-size: var(--sl-font-size-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control.has-icons-left .icon.is-small {
|
||||||
|
margin-left: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control.has-icons-right .icon.is-small {
|
||||||
|
margin-right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
sl-dialog {
|
||||||
|
--header-spacing: var(--sl-spacing-small);
|
||||||
|
--body-spacing: var(--sl-spacing-small);
|
||||||
|
--footer-spacing: var(--sl-spacing-small);
|
||||||
|
--width: 40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
sl-dialog::part(header) {
|
||||||
|
border-bottom: 1px solid var(--sl-panel-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
sl-dialog::part(title) {
|
||||||
|
font-size: var(--sl-font-size-medium);
|
||||||
|
font-weight: var(--sl-font-weight-bold);
|
||||||
|
}
|
||||||
|
|
||||||
|
sl-dialog::part(body) {
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
sl-dialog::part(footer) {
|
||||||
|
border-top: 1px solid var(--sl-panel-border-color);
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { css, LitElement } from "lit";
|
||||||
|
import { unsafeSVG } from "lit/directives/unsafe-svg.js";
|
||||||
|
import { customElement, property } from "lit/decorators.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based on `<sl-icon>` but uses inline SVG.
|
||||||
|
*/
|
||||||
|
@customElement("wr-icon")
|
||||||
|
export class Icon extends LitElement {
|
||||||
|
static styles = css`
|
||||||
|
:host {
|
||||||
|
display: inline-block;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
box-sizing: content-box !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raw SVG string
|
||||||
|
*/
|
||||||
|
@property({ type: String })
|
||||||
|
svg?: string;
|
||||||
|
|
||||||
|
@property({ type: String, reflect: true })
|
||||||
|
ariaHidden = "true";
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (!this.svg) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return unsafeSVG(this.svg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,21 +6,6 @@ import faClone from "@fortawesome/fontawesome-free/svgs/regular/clone.svg";
|
|||||||
import faCheck from "@fortawesome/fontawesome-free/svgs/solid/check.svg";
|
import faCheck from "@fortawesome/fontawesome-free/svgs/solid/check.svg";
|
||||||
import faX from "@fortawesome/fontawesome-free/svgs/solid/times.svg";
|
import faX from "@fortawesome/fontawesome-free/svgs/solid/times.svg";
|
||||||
|
|
||||||
import { registerIconLibrary } from "@shoelace-style/shoelace/dist/utilities/icon-library.js";
|
|
||||||
|
|
||||||
import systemLibrary from "@shoelace-style/shoelace/dist/components/icon/library.system.js";
|
|
||||||
|
|
||||||
// disable system library to prevent loading of unused data: URLs
|
|
||||||
// allow only "x-lg" as it is needed for sl-dialog
|
|
||||||
registerIconLibrary("system", {
|
|
||||||
resolver: (name) => {
|
|
||||||
if (name === "x-lg") {
|
|
||||||
return systemLibrary.resolver(name);
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
@customElement("wr-labeled-field")
|
@customElement("wr-labeled-field")
|
||||||
class LabeledField extends LitElement {
|
class LabeledField extends LitElement {
|
||||||
@property({ type: String })
|
@property({ type: String })
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import webrecorderLockupColor from "~assets/brand/webrecorder-lockup-color.svg";
|
|||||||
import btAngleDoubleDown from "~assets/icons/chevron-double-down.svg";
|
import btAngleDoubleDown from "~assets/icons/chevron-double-down.svg";
|
||||||
import btAngleDoubleUp from "~assets/icons/chevron-double-up.svg";
|
import btAngleDoubleUp from "~assets/icons/chevron-double-up.svg";
|
||||||
import fabGithub from "@fortawesome/fontawesome-free/svgs/brands/github.svg";
|
import fabGithub from "@fortawesome/fontawesome-free/svgs/brands/github.svg";
|
||||||
import fasDownload from "@fortawesome/fontawesome-free/svgs/solid/download.svg";
|
|
||||||
|
import iconDownload from "~icons/download.svg";
|
||||||
|
|
||||||
import { clickOnSpacebarPress } from "./misc";
|
import { clickOnSpacebarPress } from "./misc";
|
||||||
|
|
||||||
@@ -246,11 +247,7 @@ export class RWPEmbedReceipt extends LitElement {
|
|||||||
@keyup="${clickOnSpacebarPress}"
|
@keyup="${clickOnSpacebarPress}"
|
||||||
>
|
>
|
||||||
<span class="icon is-small">
|
<span class="icon is-small">
|
||||||
<fa-icon
|
<wr-icon .svg="${iconDownload}"></wr-icon>
|
||||||
size="1.0em"
|
|
||||||
aria-hidden="true"
|
|
||||||
.svg="${fasDownload}"
|
|
||||||
></fa-icon>
|
|
||||||
</span>
|
</span>
|
||||||
<span>Download Archive</span>
|
<span>Download Archive</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
+35
-20
@@ -13,6 +13,7 @@ import { property, query } from "lit/decorators.js";
|
|||||||
import type { FavIconEventDetail } from "./types";
|
import type { FavIconEventDetail } from "./types";
|
||||||
import type { EmbedReplayData } from "./item";
|
import type { EmbedReplayData } from "./item";
|
||||||
import type { RwpPageLoadingEvent, RwpUrlChangeEvent } from "./events";
|
import type { RwpPageLoadingEvent, RwpUrlChangeEvent } from "./events";
|
||||||
|
import type { ReplayWebApp } from "./appmain";
|
||||||
|
|
||||||
type IframeMessage = MessageEvent<
|
type IframeMessage = MessageEvent<
|
||||||
| RwpUrlChangeEvent["detail"]
|
| RwpUrlChangeEvent["detail"]
|
||||||
@@ -67,6 +68,7 @@ class Embed extends LitElement {
|
|||||||
@property({ type: Boolean }) hideOffscreen: boolean | undefined;
|
@property({ type: Boolean }) hideOffscreen: boolean | undefined;
|
||||||
|
|
||||||
@property({ type: Boolean }) noMediaDownload = false;
|
@property({ type: Boolean }) noMediaDownload = false;
|
||||||
|
@property({ type: Boolean }) hideMetadataSidebar = false;
|
||||||
|
|
||||||
@property({ type: Boolean }) useAdblock = false;
|
@property({ type: Boolean }) useAdblock = false;
|
||||||
@property({ type: String }) adblockRulesUrl = DEFAULT_ADBLOCK_FILE;
|
@property({ type: String }) adblockRulesUrl = DEFAULT_ADBLOCK_FILE;
|
||||||
@@ -88,6 +90,8 @@ class Embed extends LitElement {
|
|||||||
@query("iframe")
|
@query("iframe")
|
||||||
private readonly iframe?: HTMLIFrameElement | null;
|
private readonly iframe?: HTMLIFrameElement | null;
|
||||||
|
|
||||||
|
mainElement?: ReplayWebApp | null;
|
||||||
|
|
||||||
replayfile = defaultReplayFile;
|
replayfile = defaultReplayFile;
|
||||||
mainElementName = "replay-app-main";
|
mainElementName = "replay-app-main";
|
||||||
appName = "ReplayWeb.page";
|
appName = "ReplayWeb.page";
|
||||||
@@ -267,20 +271,16 @@ class Embed extends LitElement {
|
|||||||
const qs = new URLSearchParams(window.location.hash.slice(1));
|
const qs = new URLSearchParams(window.location.hash.slice(1));
|
||||||
|
|
||||||
if (qs.has("url")) {
|
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")) {
|
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")) {
|
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")) {
|
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";
|
ruffle?: "1";
|
||||||
adblockUrl?: string;
|
adblockUrl?: string;
|
||||||
noMediaDownload?: string;
|
noMediaDownload?: string;
|
||||||
|
hideMetadataSidebar?: string;
|
||||||
} = {
|
} = {
|
||||||
source,
|
source,
|
||||||
customColl: this.coll,
|
customColl: this.coll,
|
||||||
@@ -378,6 +379,10 @@ class Embed extends LitElement {
|
|||||||
params.noMediaDownload = "1";
|
params.noMediaDownload = "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.hideMetadataSidebar) {
|
||||||
|
params.hideMetadataSidebar = "1";
|
||||||
|
}
|
||||||
|
|
||||||
this.paramString = new URLSearchParams(
|
this.paramString = new URLSearchParams(
|
||||||
// Converting to unknown here so that we can ignore the URL -> string conversion necessary for the types to work out
|
// 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>,
|
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: Event) {
|
||||||
onLoad(event) {
|
|
||||||
if (this.isCrossOrigin) {
|
if (this.isCrossOrigin) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const win = event.target.contentWindow;
|
const target = event.target as HTMLIFrameElement;
|
||||||
const doc = event.target.contentDocument;
|
const win = target.contentWindow;
|
||||||
|
const doc = target.contentDocument;
|
||||||
|
|
||||||
if (
|
if (!win) {
|
||||||
win.navigator.serviceWorker &&
|
console.debug("missing `event.target.contentWindow`");
|
||||||
!win.navigator.serviceWorker.controller &&
|
return;
|
||||||
this.reloadCount <= 2
|
}
|
||||||
) {
|
|
||||||
|
if (!win.navigator.serviceWorker.controller && this.reloadCount <= 2) {
|
||||||
this.reloadCount++;
|
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);
|
setTimeout(() => win.location.reload(), 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.reloadCount = 0;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { URLResources } from "./url-resources";
|
|||||||
import { Embed } from "./embed";
|
import { Embed } from "./embed";
|
||||||
import "./coll-description";
|
import "./coll-description";
|
||||||
import "./shoelace";
|
import "./shoelace";
|
||||||
|
import "./components/icon";
|
||||||
|
|
||||||
import rwpIcon from "~assets/icons/replaywebpage.svg";
|
import rwpIcon from "~assets/icons/replaywebpage.svg";
|
||||||
import rwpLogoAnimated from "~assets/brand/replaywebpage-icon-color-animated.svg";
|
import rwpLogoAnimated from "~assets/brand/replaywebpage-icon-color-animated.svg";
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@ import { wrapCss, apiPrefix } from "./misc";
|
|||||||
import fasArrowUp from "@fortawesome/fontawesome-free/svgs/solid/angle-double-up.svg";
|
import fasArrowUp from "@fortawesome/fontawesome-free/svgs/solid/angle-double-up.svg";
|
||||||
import fasArrowDown from "@fortawesome/fontawesome-free/svgs/solid/angle-double-down.svg";
|
import fasArrowDown from "@fortawesome/fontawesome-free/svgs/solid/angle-double-down.svg";
|
||||||
|
|
||||||
import fasSearch from "@fortawesome/fontawesome-free/svgs/solid/search.svg";
|
import iconSearch from "~icons/search.svg";
|
||||||
|
|
||||||
import type { ItemType } from "./types";
|
import type { ItemType } from "./types";
|
||||||
|
|
||||||
@@ -306,7 +306,7 @@ class ItemIndex extends LitElement {
|
|||||||
placeholder="Search by Archive Title or Source"
|
placeholder="Search by Archive Title or Source"
|
||||||
/>
|
/>
|
||||||
<span class="icon is-left is-small">
|
<span class="icon is-left is-small">
|
||||||
<fa-icon .svg="${fasSearch}"></fa-icon>
|
<wr-icon .svg="${iconSearch}"></wr-icon>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<wr-sorter
|
<wr-sorter
|
||||||
|
|||||||
+452
-408
File diff suppressed because it is too large
Load Diff
@@ -57,6 +57,9 @@ export function updateFaviconLinks(data: FavIconEventDetail) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
/**
|
||||||
|
* @deprecated Use `<wr-icon>`
|
||||||
|
*/
|
||||||
class FaIcon extends LitElement {
|
class FaIcon extends LitElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|||||||
+130
-44
@@ -1,10 +1,19 @@
|
|||||||
import prettyBytes from "pretty-bytes";
|
import prettyBytes from "pretty-bytes";
|
||||||
|
|
||||||
import { LitElement, html, css, unsafeCSS, type PropertyValues } from "lit";
|
import {
|
||||||
|
LitElement,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
unsafeCSS,
|
||||||
|
type PropertyValues,
|
||||||
|
nothing,
|
||||||
|
} from "lit";
|
||||||
import { property, state } from "lit/decorators.js";
|
import { property, state } from "lit/decorators.js";
|
||||||
|
|
||||||
import "keyword-mark-element/lib/keyword-mark.js";
|
import "keyword-mark-element/lib/keyword-mark.js";
|
||||||
|
|
||||||
|
import iconImageAlt from "~icons/image-alt.svg";
|
||||||
|
|
||||||
import { getPageDateTS, getReplayLink } from "./pageutils";
|
import { getPageDateTS, getReplayLink } from "./pageutils";
|
||||||
|
|
||||||
import { wrapCss } from "./misc";
|
import { wrapCss } from "./misc";
|
||||||
@@ -15,6 +24,7 @@ import {
|
|||||||
timeFormatter,
|
timeFormatter,
|
||||||
} from "./utils/dateTimeFormatter";
|
} from "./utils/dateTimeFormatter";
|
||||||
import type { TabNavEvent } from "./events";
|
import type { TabNavEvent } from "./events";
|
||||||
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
class PageEntry extends LitElement {
|
class PageEntry extends LitElement {
|
||||||
@@ -48,6 +58,9 @@ class PageEntry extends LitElement {
|
|||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
isSidebar = false;
|
isSidebar = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
useFaviconFallback = false;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
thumbnailValid = true;
|
thumbnailValid = true;
|
||||||
|
|
||||||
@@ -70,6 +83,26 @@ class PageEntry extends LitElement {
|
|||||||
width: unset !important;
|
width: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host(.sidebar) .page-title {
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.sidebar) .page-title,
|
||||||
|
:host(.sidebar) .page-url {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.sidebar) .page-link:not(.current):hover {
|
||||||
|
background-color: var(--sl-color-neutral-50);
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.sidebar) .current {
|
||||||
|
background-color: var(--sl-color-blue-100);
|
||||||
|
}
|
||||||
|
|
||||||
:host(.sidebar) {
|
:host(.sidebar) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@@ -92,23 +125,62 @@ class PageEntry extends LitElement {
|
|||||||
margin-bottom: calc(-0.75rem + 2px);
|
margin-bottom: calc(-0.75rem + 2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.favicon {
|
.thumbnail {
|
||||||
display: inline-block;
|
background-color: var(--sl-color-neutral-100);
|
||||||
vertical-align: text-bottom;
|
border: 1px solid var(--sl-color-neutral-200);
|
||||||
|
border-radius: var(--sl-border-radius-large);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail-placeholder {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail-placeholder-content {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: var(--sl-spacing-2x-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail-placeholder-content .icon {
|
||||||
|
margin: var(--sl-spacing-2x-small) 0;
|
||||||
|
color: var(--sl-color-neutral-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail-placeholder-label {
|
||||||
|
font-size: var(--sl-font-size-2x-small);
|
||||||
|
color: var(--sl-color-neutral-500);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-link {
|
||||||
|
transition: background-color var(--sl-transition-x-fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-link:hover .page-title {
|
||||||
|
color: var(--sl-color-blue-700);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-weight: var(--sl-font-weight-bold);
|
||||||
|
color: var(--sl-color-blue-600);
|
||||||
|
transition: color var(--sl-transition-x-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-left .favicon {
|
.media-left .favicon {
|
||||||
width: 2rem;
|
object-fit: contain;
|
||||||
height: 2rem;
|
|
||||||
}
|
|
||||||
.media-left img.favicon {
|
|
||||||
filter: drop-shadow(1px 1px 2px grey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-content .favicon {
|
.media-content .favicon {
|
||||||
width: 1.15rem;
|
width: 1.15rem;
|
||||||
height: 1.15rem;
|
height: 1.15rem;
|
||||||
margin: 0 0.25rem;
|
margin: 0 0.25rem;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: -0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-left {
|
.media-left {
|
||||||
@@ -141,18 +213,6 @@ class PageEntry extends LitElement {
|
|||||||
|
|
||||||
${PageEntry.sidebarStyles(unsafeCSS`:host(.sidebar)`)}
|
${PageEntry.sidebarStyles(unsafeCSS`:host(.sidebar)`)}
|
||||||
|
|
||||||
.current a {
|
|
||||||
background-color: rgb(207, 243, 255);
|
|
||||||
font-style: italic;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.current .curr-page {
|
|
||||||
font-style: italic;
|
|
||||||
font-size: 9px;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-inline-date {
|
.is-inline-date {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -164,6 +224,16 @@ class PageEntry extends LitElement {
|
|||||||
.col-date {
|
.col-date {
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.date-time,
|
||||||
|
.is-inline-date {
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
|
color: var(--sl-color-neutral-700);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-url {
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
|
}
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,10 +255,6 @@ class PageEntry extends LitElement {
|
|||||||
}
|
}
|
||||||
${prefix} .is-inline-date {
|
${prefix} .is-inline-date {
|
||||||
display: initial !important;
|
display: initial !important;
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
${prefix} .media-left {
|
|
||||||
padding-left: 0.75rem;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -229,12 +295,15 @@ class PageEntry extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
<div class="column col-date is-2">
|
<div class="column col-date is-2">
|
||||||
<div>${date ? dateFormatter.format(date) : ""}</div>
|
<div>${date ? dateFormatter.format(date) : ""}</div>
|
||||||
<div>${date ? timeFormatter.format(date) : ""}</div>
|
<div class="date-time">${date ? timeFormatter.format(date) : ""}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div
|
||||||
|
class="page-link column ${this.isCurrent ? "current" : ""}"
|
||||||
|
aria-current=${ifDefined(this.isCurrent ? "location" : undefined)}
|
||||||
|
>
|
||||||
<div class="media">
|
<div class="media">
|
||||||
<figure class="media-left">${this.renderPageIcon()}</figure>
|
<figure class="media-left">${this.renderPageIcon()}</figure>
|
||||||
<div class="media-content ${this.isCurrent ? "current" : ""}">
|
<div class="media-content">
|
||||||
<div role="heading" aria-level="${this.isSidebar ? "4" : "3"}">
|
<div role="heading" aria-level="${this.isSidebar ? "4" : "3"}">
|
||||||
<a
|
<a
|
||||||
@dblclick="${this.onReload}"
|
@dblclick="${this.onReload}"
|
||||||
@@ -246,17 +315,20 @@ class PageEntry extends LitElement {
|
|||||||
this.page!.waczhash,
|
this.page!.waczhash,
|
||||||
)}"
|
)}"
|
||||||
>
|
>
|
||||||
<p class="is-size-6 has-text-weight-bold has-text-link text">
|
<p class="page-title text">
|
||||||
<keyword-mark keywords="${this.query}"
|
${this.thumbnailValid ? this.renderFavicon() : nothing}
|
||||||
|
<keyword-mark
|
||||||
|
keywords="${this.query}"
|
||||||
|
title="${p.title || p.url}"
|
||||||
>${p.title || p.url}</keyword-mark
|
>${p.title || p.url}</keyword-mark
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
<p class="has-text-dark text">
|
<p class="page-url has-text-dark text">
|
||||||
<keyword-mark keywords="${this.query}"
|
<keyword-mark keywords="${this.query}" title="${p.url}"
|
||||||
>${p.url}</keyword-mark
|
>${p.url}</keyword-mark
|
||||||
>${this.thumbnailValid ? this.renderFavicon() : ""}
|
>
|
||||||
</p>
|
</p>
|
||||||
<p class="has-text-grey-dark text is-inline-date">
|
<p class="text is-inline-date">
|
||||||
${date ? dateTimeFormatter.format(date) : ""}
|
${date ? dateTimeFormatter.format(date) : ""}
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
@@ -269,9 +341,7 @@ class PageEntry extends LitElement {
|
|||||||
: html``}
|
: html``}
|
||||||
</div>
|
</div>
|
||||||
${hasSize
|
${hasSize
|
||||||
? html` <div class="media-right" style="margin-right: 2em">
|
? html` <div class="text">${prettyBytes(p.size)}</div>`
|
||||||
${prettyBytes(p.size)}
|
|
||||||
</div>`
|
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -301,14 +371,30 @@ class PageEntry extends LitElement {
|
|||||||
|
|
||||||
private renderPageIcon() {
|
private renderPageIcon() {
|
||||||
if (!this.thumbnailValid) {
|
if (!this.thumbnailValid) {
|
||||||
return this.renderFavicon();
|
return html`<div
|
||||||
|
class="thumbnail-placeholder image is-16by9 ${this.useFaviconFallback
|
||||||
|
? "favicon-fallback"
|
||||||
|
: "thumbnail"}"
|
||||||
|
>
|
||||||
|
<div class="thumbnail-placeholder-content">
|
||||||
|
${this.useFaviconFallback
|
||||||
|
? this.renderFavicon()
|
||||||
|
: html`<span class="icon is-small">
|
||||||
|
<wr-icon .svg="${iconImageAlt}" aria-hidden="true"></wr-icon>
|
||||||
|
</span>
|
||||||
|
<span class="thumbnail-placeholder-label">No image</span>`}
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
}
|
}
|
||||||
return html`<img
|
|
||||||
class="thumbnail"
|
return html`<div class="image is-16by9">
|
||||||
@error=${() => (this.thumbnailValid = false)}
|
<img
|
||||||
src=${`${this.getReplayPrefix()}/urn:thumbnail:${this.page!.url}`}
|
class="thumbnail"
|
||||||
loading="lazy"
|
@error=${() => (this.thumbnailValid = false)}
|
||||||
/>`;
|
src=${`${this.getReplayPrefix()}/urn:thumbnail:${this.page!.url}`}
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderFavicon() {
|
private renderFavicon() {
|
||||||
|
|||||||
+201
-106
@@ -1,7 +1,14 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { LitElement, html, css, unsafeCSS, type PropertyValues } from "lit";
|
import {
|
||||||
import { property } from "lit/decorators.js";
|
LitElement,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
unsafeCSS,
|
||||||
|
type PropertyValues,
|
||||||
|
nothing,
|
||||||
|
} from "lit";
|
||||||
|
import { property, state } from "lit/decorators.js";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
import { wrapCss, clickOnSpacebarPress } from "./misc";
|
import { wrapCss, clickOnSpacebarPress } from "./misc";
|
||||||
import ndjson from "fetch-ndjson";
|
import ndjson from "fetch-ndjson";
|
||||||
@@ -11,9 +18,10 @@ import prettyBytes from "pretty-bytes";
|
|||||||
|
|
||||||
import { getTS, getPageDateTS } from "./pageutils";
|
import { getTS, getPageDateTS } from "./pageutils";
|
||||||
|
|
||||||
import fasSearch from "@fortawesome/fontawesome-free/svgs/solid/search.svg";
|
import iconArrowDown from "~icons/arrow-down.svg";
|
||||||
import fasAngleDown from "@fortawesome/fontawesome-free/svgs/solid/angle-down.svg";
|
import iconChevronDown from "~icons/chevron-down.svg";
|
||||||
import fasEdit from "@fortawesome/fontawesome-free/svgs/solid/edit.svg";
|
import iconPencil from "~icons/pencil.svg";
|
||||||
|
import iconSearch from "~icons/search.svg";
|
||||||
|
|
||||||
import type { Sorter } from "./sorter";
|
import type { Sorter } from "./sorter";
|
||||||
import type { PageEntry } from "./pageentry";
|
import type { PageEntry } from "./pageentry";
|
||||||
@@ -100,6 +108,9 @@ class Pages extends LitElement {
|
|||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
collInfo: ItemType | Record<string, never> | null = null;
|
collInfo: ItemType | Record<string, never> | null = null;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
hideMetadataSidebar = false;
|
||||||
|
|
||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
allSelected = false;
|
allSelected = false;
|
||||||
|
|
||||||
@@ -109,15 +120,15 @@ class Pages extends LitElement {
|
|||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
dynamicPagesQuery = false;
|
dynamicPagesQuery = false;
|
||||||
|
|
||||||
@property({ type: Number })
|
|
||||||
totalPages = 0;
|
|
||||||
|
|
||||||
@property({ type: Number })
|
@property({ type: Number })
|
||||||
dynamicPageCount = 1;
|
dynamicPageCount = 1;
|
||||||
|
|
||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
skipScrollMore = false;
|
skipScrollMore = false;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private filteredPagesTotal = 0;
|
||||||
|
|
||||||
private _ival: number | undefined;
|
private _ival: number | undefined;
|
||||||
|
|
||||||
static get sortKeys() {
|
static get sortKeys() {
|
||||||
@@ -222,17 +233,20 @@ class Pages extends LitElement {
|
|||||||
}
|
}
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
if (this.flex && this.query && this.textPages) {
|
if (this.flex && this.query && this.textPages) {
|
||||||
const results = await this.flex.searchAsync(this.query, 25);
|
const results = await this.flex.searchAsync(
|
||||||
|
this.query,
|
||||||
|
DYNAMIC_PAGE_SIZE,
|
||||||
|
);
|
||||||
this.filteredPages = results.map(
|
this.filteredPages = results.map(
|
||||||
(inx: Id) => this.textPages![inx as number],
|
(inx: Id) => this.textPages![inx as number],
|
||||||
);
|
);
|
||||||
} else if (this.showAllPages && this.hasExtraPages) {
|
} else if (this.showAllPages && this.hasExtraPages) {
|
||||||
this.filteredPages = [...this.textPages!];
|
this.filteredPages = [...this.textPages!, ...this.collInfo!.pages];
|
||||||
} else if (!this.dynamicPagesQuery) {
|
} else if (!this.dynamicPagesQuery) {
|
||||||
this.filteredPages = [...this.collInfo!.pages];
|
this.filteredPages = [...this.collInfo!.pages];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.totalPages = this.filteredPages.length;
|
this.filteredPagesTotal = this.filteredPages.length;
|
||||||
|
|
||||||
if (this.dynamicPagesQuery) {
|
if (this.dynamicPagesQuery) {
|
||||||
if (!this.query) {
|
if (!this.query) {
|
||||||
@@ -347,7 +361,7 @@ class Pages extends LitElement {
|
|||||||
this.filteredPages = [...this.filteredPages, ...newPages];
|
this.filteredPages = [...this.filteredPages, ...newPages];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.totalPages = this.filteredPages.length;
|
this.filteredPagesTotal = this.filteredPages.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
async filterCurated() {
|
async filterCurated() {
|
||||||
@@ -369,10 +383,7 @@ class Pages extends LitElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'pages' implicitly has an 'any' type.
|
async addPages(pages: Page[]) {
|
||||||
// TODO: Fix this the next time the file is edited.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
||||||
addPages(pages) {
|
|
||||||
const flex = new FlexIndex();
|
const flex = new FlexIndex();
|
||||||
|
|
||||||
this.flex = flex;
|
this.flex = flex;
|
||||||
@@ -380,8 +391,7 @@ class Pages extends LitElement {
|
|||||||
|
|
||||||
if (!this.dynamicPagesQuery) {
|
if (!this.dynamicPagesQuery) {
|
||||||
this.hasExtraPages = Boolean(
|
this.hasExtraPages = Boolean(
|
||||||
this.textPages &&
|
this.collInfo?.pages &&
|
||||||
this.collInfo?.pages &&
|
|
||||||
this.textPages.length > this.collInfo.pages.length,
|
this.textPages.length > this.collInfo.pages.length,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -391,10 +401,7 @@ class Pages extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'page' implicitly has an 'any' type. | TS7006 - Parameter 'index' implicitly has an 'any' type.
|
pages.map(async (page, index) => {
|
||||||
// TODO: Fix this the next time the file is edited.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
||||||
pages.map((page, index) => {
|
|
||||||
let text = page.url;
|
let text = page.url;
|
||||||
if (page.title) {
|
if (page.title) {
|
||||||
text += " " + page.title;
|
text += " " + page.title;
|
||||||
@@ -402,8 +409,6 @@ class Pages extends LitElement {
|
|||||||
if (page.text) {
|
if (page.text) {
|
||||||
text += " " + page.text;
|
text += " " + page.text;
|
||||||
}
|
}
|
||||||
// TODO: Fix this the next time the file is edited.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
return flex.addAsync(index, text);
|
return flex.addAsync(index, text);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -433,7 +438,7 @@ class Pages extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const lines: unknown[] = [];
|
const lines: Page[] = [];
|
||||||
|
|
||||||
for await (const line of ndjson(resp.body!.getReader())) {
|
for await (const line of ndjson(resp.body!.getReader())) {
|
||||||
if (!line.url) {
|
if (!line.url) {
|
||||||
@@ -445,7 +450,7 @@ class Pages extends LitElement {
|
|||||||
if (typeof line.ts === "string") {
|
if (typeof line.ts === "string") {
|
||||||
line.ts = new Date(line.ts as string).getTime();
|
line.ts = new Date(line.ts as string).getTime();
|
||||||
}
|
}
|
||||||
lines.push(line);
|
lines.push(line as unknown as Page);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.addPages(lines);
|
await this.addPages(lines);
|
||||||
@@ -489,6 +494,7 @@ class Pages extends LitElement {
|
|||||||
.header.columns {
|
.header.columns {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
|
padding: var(--sl-spacing-x-small) var(--sl-spacing-small);
|
||||||
}
|
}
|
||||||
.header a {
|
.header a {
|
||||||
color: black;
|
color: black;
|
||||||
@@ -503,8 +509,6 @@ class Pages extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
margin-top: 0.5em;
|
|
||||||
margin-left: 0.75em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.thumbnail {
|
.thumbnail {
|
||||||
@@ -516,10 +520,10 @@ class Pages extends LitElement {
|
|||||||
.index-bar {
|
.index-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-right: 3px solid rgb(237, 237, 237);
|
border-right: 1px solid var(--sl-panel-border-color);
|
||||||
background-color: whitesmoke;
|
background-color: var(--sl-color-neutral-50);
|
||||||
padding-right: 0px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.index-bar-label {
|
.index-bar-label {
|
||||||
@@ -527,17 +531,27 @@ class Pages extends LitElement {
|
|||||||
font-size: var(--sl-font-size-x-small);
|
font-size: var(--sl-font-size-x-small);
|
||||||
font-weight: var(--sl-font-weight-semibold);
|
font-weight: var(--sl-font-weight-semibold);
|
||||||
color: var(--sl-color-neutral-500);
|
color: var(--sl-color-neutral-500);
|
||||||
margin-bottom: var(--sl-spacing-2x-small);
|
margin-bottom: var(--sl-spacing-x-small);
|
||||||
|
padding: 0 var(--sl-spacing-small);
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.index-bar-label:first-child {
|
||||||
|
margin-top: var(--sl-spacing-medium);
|
||||||
|
}
|
||||||
|
|
||||||
.index-bar-title {
|
.index-bar-title {
|
||||||
font-size: var(--sl-font-size-large);
|
font-size: var(--sl-font-size-small);
|
||||||
font-weight: var(--sl-font-weight-semibold);
|
font-weight: var(--sl-font-weight-semibold);
|
||||||
margin-bottom: var(--sl-spacing-large);
|
margin-bottom: var(--sl-spacing-small);
|
||||||
|
padding: 0 var(--sl-spacing-small);
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.index-bar-title + .index-bar-label {
|
||||||
|
margin-top: var(--sl-spacing-medium);
|
||||||
|
}
|
||||||
|
|
||||||
.index-bar-title:hover + .editIcon {
|
.index-bar-title:hover + .editIcon {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@@ -565,9 +579,59 @@ class Pages extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.num-results {
|
.num-results {
|
||||||
font-style: italic;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--sl-spacing-small);
|
||||||
|
justify-content: space-between;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
line-height: 2.5;
|
font-size: var(--sl-font-size-small);
|
||||||
|
color: var(--sl-color-neutral-700);
|
||||||
|
line-height: 1;
|
||||||
|
border-top: 1px solid var(--sl-panel-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-num-results {
|
||||||
|
padding: var(--sl-spacing-x-small) var(--sl-spacing-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-num-results {
|
||||||
|
padding: var(--sl-spacing-x-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.seed-pages-filter {
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.seed-pages-filter .checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--sl-spacing-x-small);
|
||||||
|
line-height: 1.5;
|
||||||
|
padding-inline-end: var(--sl-spacing-x-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.seed-pages-filter .checkbox span {
|
||||||
|
margin-top: -0.0875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sorter {
|
||||||
|
gap: var(--sl-spacing-x-small);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sorter wr-sorter {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-control-label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--sl-spacing-2x-small);
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
|
font-weight: var(--sl-font-weight-semibold);
|
||||||
|
color: var(--sl-color-neutral-600);
|
||||||
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.asc:after {
|
.asc:after {
|
||||||
@@ -613,19 +677,31 @@ class Pages extends LitElement {
|
|||||||
display: flex !important;
|
display: flex !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host(.sidebar) .search-bar {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
.scroller {
|
.scroller {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: auto;
|
flex: auto;
|
||||||
|
padding: var(--sl-spacing-small);
|
||||||
padding-bottom: 1em;
|
|
||||||
min-height: 0px;
|
min-height: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scroller-help-text {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--sl-spacing-2x-small);
|
||||||
|
color: var(--sl-color-neutral-500);
|
||||||
|
}
|
||||||
|
|
||||||
.page-entry {
|
.page-entry {
|
||||||
padding-bottom: 1.5rem;
|
padding-bottom: 1.5rem;
|
||||||
|
margin-right: -1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected {
|
.selected {
|
||||||
@@ -643,19 +719,22 @@ class Pages extends LitElement {
|
|||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: fit-content;
|
min-height: fit-content;
|
||||||
|
border-bottom: 1px solid var(--sl-panel-border-color);
|
||||||
margin-bottom: 1em;
|
|
||||||
border-bottom: 3px solid rgb(237, 237, 237);
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-select {
|
|
||||||
padding: 0 1em 0 0.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-bar {
|
.search-bar {
|
||||||
width: auto;
|
width: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
align-items: center;
|
||||||
|
gap: var(--sl-spacing-small);
|
||||||
|
background-color: var(--sl-color-neutral-100);
|
||||||
|
border-bottom: 1px solid var(--sl-panel-border-color);
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
|
padding: var(--sl-spacing-x-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar .input {
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-auto {
|
.flex-auto {
|
||||||
@@ -663,11 +742,11 @@ class Pages extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.index-bar-description {
|
.index-bar-description {
|
||||||
margin-bottom: var(--sl-spacing-x-small);
|
font-size: var(--sl-font-size-small);
|
||||||
line-height: var(--sl-line-height-normal);
|
line-height: var(--sl-line-height-normal);
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
border-bottom: 1px solid var(--sl-panel-border-color);
|
padding: 0 var(--sl-spacing-small);
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
@@ -698,8 +777,7 @@ class Pages extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
${prefix} .mobile-header {
|
${prefix} .mobile-header {
|
||||||
margin: 0.5rem;
|
margin: var(--sl-spacing-x-small);
|
||||||
margin-left: 1rem;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -728,6 +806,9 @@ class Pages extends LitElement {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const currList = this.currList;
|
const currList = this.currList;
|
||||||
|
const collList = this.collInfo?.lists.length;
|
||||||
|
const hideSideCol =
|
||||||
|
this.hideMetadataSidebar && !this.editable && !this.editing && !collList;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
@@ -737,11 +818,11 @@ class Pages extends LitElement {
|
|||||||
>
|
>
|
||||||
Pages in ${this.collInfo!.title}
|
Pages in ${this.collInfo!.title}
|
||||||
</div>
|
</div>
|
||||||
<div class="search-bar notification is-marginless">
|
<div class="search-bar is-marginless">
|
||||||
${this.isSidebar
|
${this.isSidebar
|
||||||
? html`<h3 class="is-sr-only">Search and Filter Pages</h3>`
|
? html`<h3 class="is-sr-only">Search and Filter Pages</h3>`
|
||||||
: ""}
|
: ""}
|
||||||
<div class="field flex-auto">
|
<div class="flex-auto">
|
||||||
<div
|
<div
|
||||||
class="control has-icons-left ${this.loading ? "is-loading" : ""}"
|
class="control has-icons-left ${this.loading ? "is-loading" : ""}"
|
||||||
>
|
>
|
||||||
@@ -752,16 +833,19 @@ class Pages extends LitElement {
|
|||||||
type="text"
|
type="text"
|
||||||
placeholder="Search by Page URL, Title, or Text"
|
placeholder="Search by Page URL, Title, or Text"
|
||||||
/>
|
/>
|
||||||
<span class="icon is-left"
|
<span class="icon is-left is-small"
|
||||||
><fa-icon .svg="${fasSearch}" aria-hidden="true"></fa-icon
|
><wr-icon .svg="${iconSearch}"></wr-icon
|
||||||
></span>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
${this.renderSeedPagesFilter()}
|
||||||
</div>
|
</div>
|
||||||
<div class="main columns">
|
<div class="main columns">
|
||||||
<div
|
<div
|
||||||
class="column index-bar is-one-fifth ${this.isSidebar
|
class="column index-bar is-one-fifth ${this.isSidebar
|
||||||
? "is-hidden-mobile"
|
? "is-hidden-mobile"
|
||||||
|
: hideSideCol
|
||||||
|
? "is-hidden"
|
||||||
: ""}"
|
: ""}"
|
||||||
>
|
>
|
||||||
${this.editable && this.editing
|
${this.editable && this.editing
|
||||||
@@ -775,11 +859,9 @@ class Pages extends LitElement {
|
|||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
`
|
`
|
||||||
: html` <div
|
: this.hideMetadataSidebar
|
||||||
class="index-bar-label ${this.collInfo!.description
|
? nothing
|
||||||
? "is-hidden-mobile"
|
: html`<div class="index-bar-label is-hidden-mobile">
|
||||||
: "is-sr-only"}"
|
|
||||||
>
|
|
||||||
Collection Name
|
Collection Name
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -802,36 +884,14 @@ class Pages extends LitElement {
|
|||||||
</div>`
|
</div>`
|
||||||
: html``}`}
|
: html``}`}
|
||||||
${this.editable
|
${this.editable
|
||||||
? html`<fa-icon class="editIcon" .svg="${fasEdit}"></fa-icon>`
|
? html`<wr-icon class="editIcon" .svg="${iconPencil}"></wr-icon>`
|
||||||
: html``}
|
: html``}
|
||||||
${this.hasExtraPages
|
|
||||||
? html` <span class="check-select">
|
|
||||||
<label class="checkbox">
|
|
||||||
<input
|
|
||||||
@change=${(e: Event) =>
|
|
||||||
(this.showAllPages = (
|
|
||||||
e.currentTarget as HTMLInputElement
|
|
||||||
).checked)}
|
|
||||||
type="checkbox"
|
|
||||||
.checked="${this.showAllPages}"
|
|
||||||
/>
|
|
||||||
Show Non-Seed Pages
|
|
||||||
</label>
|
|
||||||
</span>`
|
|
||||||
: ""}
|
|
||||||
|
|
||||||
<span
|
|
||||||
class="num-results is-hidden-mobile"
|
|
||||||
aria-live="polite"
|
|
||||||
aria-atomic="true"
|
|
||||||
>${this.formatResults()}</span
|
|
||||||
>
|
|
||||||
${this.editable
|
${this.editable
|
||||||
? html` <div class="index-bar-actions">
|
? html` <div class="index-bar-actions">
|
||||||
${this.renderDownloadMenu()}
|
${this.renderDownloadMenu()}
|
||||||
</div>`
|
</div>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.collInfo!.lists.length
|
${collList
|
||||||
? html`
|
? html`
|
||||||
<p id="filter-label" class="menu-label">Filter By List:</p>
|
<p id="filter-label" class="menu-label">Filter By List:</p>
|
||||||
<div class="index-bar-menu menu">
|
<div class="index-bar-menu menu">
|
||||||
@@ -889,7 +949,7 @@ class Pages extends LitElement {
|
|||||||
>
|
>
|
||||||
<span>Download</span>
|
<span>Download</span>
|
||||||
<span class="icon is-small">
|
<span class="icon is-small">
|
||||||
<fa-icon .svg="${fasAngleDown}" aria-hidden="true"></fa-icon>
|
<wr-icon .svg="${iconChevronDown}"></wr-icon>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -967,7 +1027,7 @@ class Pages extends LitElement {
|
|||||||
@click="${this.onSort}"
|
@click="${this.onSort}"
|
||||||
@keyup="${clickOnSpacebarPress}"
|
@keyup="${clickOnSpacebarPress}"
|
||||||
data-key=""
|
data-key=""
|
||||||
class="column is-1 ${this.sortKey === ""
|
class="sort-control-label column is-1 ${this.sortKey === ""
|
||||||
? this.sortDesc
|
? this.sortDesc
|
||||||
? "desc"
|
? "desc"
|
||||||
: "asc"
|
: "asc"
|
||||||
@@ -982,7 +1042,7 @@ class Pages extends LitElement {
|
|||||||
@click="${this.onSort}"
|
@click="${this.onSort}"
|
||||||
@keyup="${clickOnSpacebarPress}"
|
@keyup="${clickOnSpacebarPress}"
|
||||||
data-key="date"
|
data-key="date"
|
||||||
class="column is-2 ${this.sortKey === "date"
|
class="sort-control-label column is-2 ${this.sortKey === "date"
|
||||||
? this.sortDesc
|
? this.sortDesc
|
||||||
? "desc"
|
? "desc"
|
||||||
: "asc"
|
: "asc"
|
||||||
@@ -998,8 +1058,9 @@ class Pages extends LitElement {
|
|||||||
@click="${this.onSort}"
|
@click="${this.onSort}"
|
||||||
@keyup="${clickOnSpacebarPress}"
|
@keyup="${clickOnSpacebarPress}"
|
||||||
data-key="title"
|
data-key="title"
|
||||||
class="column is-6 pagetitle ${this.query ? "is-5" : "is-6"} ${this
|
class="sort-control-label column is-6 pagetitle ${this.query
|
||||||
.sortKey === "title"
|
? "is-5"
|
||||||
|
: "is-6"} ${this.sortKey === "title"
|
||||||
? this.sortDesc
|
? this.sortDesc
|
||||||
? "desc"
|
? "desc"
|
||||||
: "asc"
|
: "asc"
|
||||||
@@ -1008,17 +1069,16 @@ class Pages extends LitElement {
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="is-hidden-tablet mobile-header">
|
<div class="sorter is-hidden-tablet mobile-header">
|
||||||
<div class="num-results" aria-live="polite" aria-atomic="true">
|
|
||||||
${this.formatResults()}
|
|
||||||
</div>
|
|
||||||
<wr-sorter
|
<wr-sorter
|
||||||
id="pages"
|
id="pages"
|
||||||
.sortKey="${this.sortKey}"
|
.sortKey="${this.sortKey}"
|
||||||
.sortDesc="${this.sortDesc}"
|
.sortDesc="${this.sortDesc}"
|
||||||
.sortKeys="${Pages.sortKeys}"
|
.sortKeys="${Pages.sortKeys}"
|
||||||
.data="${this.filteredPages}"
|
.data="${this.filteredPages}"
|
||||||
.pageResults="${this.dynamicPagesQuery ? this.totalPages : 100}"
|
.pageResults="${this.dynamicPagesQuery
|
||||||
|
? this.filteredPagesTotal
|
||||||
|
: 100}"
|
||||||
@sort-changed="${this.onSortChanged}"
|
@sort-changed="${this.onSortChanged}"
|
||||||
class="${this.filteredPages.length ? "" : "is-hidden"}"
|
class="${this.filteredPages.length ? "" : "is-hidden"}"
|
||||||
>
|
>
|
||||||
@@ -1092,9 +1152,7 @@ class Pages extends LitElement {
|
|||||||
renderPages() {
|
renderPages() {
|
||||||
//const name = this.currList === 0 ? "All Pages" : this.collInfo.lists[this.currList - 1].title;
|
//const name = this.currList === 0 ? "All Pages" : this.collInfo.lists[this.currList - 1].title;
|
||||||
return html`
|
return html`
|
||||||
<div class="page-header has-text-weight-bold">
|
<div class="page-header">${this.renderPageHeader()}</div>
|
||||||
${this.renderPageHeader()}
|
|
||||||
</div>
|
|
||||||
<ul class="scroller" @scroll="${this.onScroll}">
|
<ul class="scroller" @scroll="${this.onScroll}">
|
||||||
${this.sortedPages.length
|
${this.sortedPages.length
|
||||||
? html` ${this.sortedPages.map((p, i) => {
|
? html` ${this.sortedPages.map((p, i) => {
|
||||||
@@ -1107,6 +1165,7 @@ class Pages extends LitElement {
|
|||||||
?selected="${selected}"
|
?selected="${selected}"
|
||||||
?isCurrent="${this.isCurrPage(p)}"
|
?isCurrent="${this.isCurrPage(p)}"
|
||||||
?isSidebar="${this.isSidebar}"
|
?isSidebar="${this.isSidebar}"
|
||||||
|
useFaviconFallback
|
||||||
.page="${p}"
|
.page="${p}"
|
||||||
pid="${p.id}"
|
pid="${p.id}"
|
||||||
@sel-page="${this.onSelectToggle}"
|
@sel-page="${this.onSelectToggle}"
|
||||||
@@ -1120,6 +1179,15 @@ class Pages extends LitElement {
|
|||||||
})}`
|
})}`
|
||||||
: html`<p class="mobile-header">${this.getNoResultsMessage()}</p>`}
|
: html`<p class="mobile-header">${this.getNoResultsMessage()}</p>`}
|
||||||
</ul>
|
</ul>
|
||||||
|
<div
|
||||||
|
class="num-results ${this.isSidebar
|
||||||
|
? "sidebar-num-results"
|
||||||
|
: "main-num-results"}"
|
||||||
|
aria-live="polite"
|
||||||
|
aria-atomic="true"
|
||||||
|
>
|
||||||
|
${this.renderPaginationResults()}
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1310,13 +1378,41 @@ class Pages extends LitElement {
|
|||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
formatResults() {
|
renderPaginationResults() {
|
||||||
const length = this.totalPages;
|
const total = this.filteredPagesTotal;
|
||||||
if (length === this.sortedPages.length) {
|
const shown = this.sortedPages.length;
|
||||||
return `${length} Page${length !== 1 ? "s" : ""}`;
|
|
||||||
} else {
|
const totalStr = `${total.toLocaleString()} ${
|
||||||
return `${this.sortedPages.length} of ${length} Pages Shown`;
|
total === 1 ? "page" : "pages"
|
||||||
}
|
}`;
|
||||||
|
const allShown = total === shown;
|
||||||
|
const countMsg = allShown
|
||||||
|
? totalStr
|
||||||
|
: `${shown.toLocaleString()} of ${totalStr}`;
|
||||||
|
|
||||||
|
return html`<span>${countMsg}</span>
|
||||||
|
${allShown
|
||||||
|
? nothing
|
||||||
|
: html`<span class="scroller-help-text">
|
||||||
|
Scroll for more
|
||||||
|
<wr-icon .svg="${iconArrowDown}"></wr-icon>
|
||||||
|
</span>`} `;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSeedPagesFilter() {
|
||||||
|
if (!this.hasExtraPages) return;
|
||||||
|
|
||||||
|
return html`<div class="seed-pages-filter check-select">
|
||||||
|
<label class="checkbox">
|
||||||
|
<input
|
||||||
|
@change=${(e: Event) =>
|
||||||
|
(this.showAllPages = (e.currentTarget as HTMLInputElement).checked)}
|
||||||
|
type="checkbox"
|
||||||
|
.checked="${this.showAllPages}"
|
||||||
|
/>
|
||||||
|
<span>Include Non-Seed Pages</span>
|
||||||
|
</label>
|
||||||
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
getNoResultsMessage() {
|
getNoResultsMessage() {
|
||||||
@@ -1345,9 +1441,8 @@ class Pages extends LitElement {
|
|||||||
return "No Pages Found";
|
return "No Pages Found";
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'event' implicitly has an 'any' type.
|
async onScroll(event: Event) {
|
||||||
async onScroll(event) {
|
const element = event.currentTarget as HTMLUListElement;
|
||||||
const element = event.currentTarget;
|
|
||||||
const diff =
|
const diff =
|
||||||
element.scrollHeight - element.scrollTop - element.clientHeight;
|
element.scrollHeight - element.scrollTop - element.clientHeight;
|
||||||
if (diff < 40 && !this.skipScrollMore) {
|
if (diff < 40 && !this.skipScrollMore) {
|
||||||
|
|||||||
+51
-15
@@ -1,13 +1,17 @@
|
|||||||
import { LitElement, html, css, type PropertyValues } from "lit";
|
import { LitElement, html, css, type PropertyValues } from "lit";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
import { property } from "lit/decorators.js";
|
import { property, query, state } from "lit/decorators.js";
|
||||||
|
|
||||||
import { wrapCss } from "./misc";
|
import { wrapCss } from "./misc";
|
||||||
import rwpLogo from "~assets/brand/replaywebpage-icon-color.svg";
|
import rwpLogo from "~assets/brand/replaywebpage-icon-color.svg";
|
||||||
import type { ItemType } from "./types";
|
import type { ItemType } from "./types";
|
||||||
import type { ReplayLoadingDetail, TabNavEvent } from "./events";
|
import type { ReplayLoadingDetail, TabNavEvent } from "./events";
|
||||||
|
import { keyed } from "lit/directives/keyed.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @cssPart iframe
|
||||||
|
* @cssPart iframe-container
|
||||||
|
* @cssPart iframe-page-not-found
|
||||||
* @fires update-title
|
* @fires update-title
|
||||||
* @fires coll-tab-nav
|
* @fires coll-tab-nav
|
||||||
* @fires update-title
|
* @fires update-title
|
||||||
@@ -62,12 +66,31 @@ class Replay extends LitElement {
|
|||||||
@property({ type: String })
|
@property({ type: String })
|
||||||
downloadResUrl = "";
|
downloadResUrl = "";
|
||||||
|
|
||||||
|
@query("iframe")
|
||||||
|
readonly iframe?: HTMLIFrameElement | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use key to force iframe to update even if `src` hasn't changed,
|
||||||
|
* for example, if the iframe window has navigated to a linked page
|
||||||
|
* and is being externally reset to a seed URL.
|
||||||
|
*/
|
||||||
|
@state()
|
||||||
|
private iframeUrlUpdateKey?: number;
|
||||||
|
|
||||||
private reauthWait: null | Promise<void> = null;
|
private reauthWait: null | Promise<void> = null;
|
||||||
|
|
||||||
private _loadPoll: null | number = null;
|
private _loadPoll: null | number = null;
|
||||||
|
|
||||||
private hiliter: HoverHiliter | null = null;
|
private hiliter: HoverHiliter | null = null;
|
||||||
|
|
||||||
|
disconnectedCallback(): void {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
|
||||||
|
if (this._loadPoll) {
|
||||||
|
window.clearInterval(this._loadPoll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
window.addEventListener("message", (event) => this.onReplayMessage(event));
|
window.addEventListener("message", (event) => this.onReplayMessage(event));
|
||||||
// TODO: Fix this the next time the file is edited.
|
// TODO: Fix this the next time the file is edited.
|
||||||
@@ -121,7 +144,7 @@ class Replay extends LitElement {
|
|||||||
: "";
|
: "";
|
||||||
}
|
}
|
||||||
|
|
||||||
updated(changedProperties: PropertyValues<this>) {
|
willUpdate(changedProperties: PropertyValues<this>) {
|
||||||
if (
|
if (
|
||||||
changedProperties.has("sourceUrl") ||
|
changedProperties.has("sourceUrl") ||
|
||||||
changedProperties.has("collInfo")
|
changedProperties.has("collInfo")
|
||||||
@@ -138,9 +161,17 @@ class Replay extends LitElement {
|
|||||||
this.replayTS = this.ts;
|
this.replayTS = this.ts;
|
||||||
this.showAuth = false;
|
this.showAuth = false;
|
||||||
this.reauthWait = null;
|
this.reauthWait = null;
|
||||||
this.doSetIframeUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const prevIframe = this.iframeUrl;
|
||||||
|
this.doSetIframeUrl();
|
||||||
|
|
||||||
|
if (prevIframe === this.iframeUrl) {
|
||||||
|
this.iframeUrlUpdateKey = Date.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updated(changedProperties: PropertyValues<this>) {
|
||||||
if (this.iframeUrl && changedProperties.has("iframeUrl")) {
|
if (this.iframeUrl && changedProperties.has("iframeUrl")) {
|
||||||
this.waitForLoad();
|
this.waitForLoad();
|
||||||
|
|
||||||
@@ -434,17 +465,22 @@ class Replay extends LitElement {
|
|||||||
: undefined,
|
: undefined,
|
||||||
)}"
|
)}"
|
||||||
></a>
|
></a>
|
||||||
<div class="iframe-container">
|
<div part="iframe-container" class="iframe-container">
|
||||||
<iframe
|
${keyed(
|
||||||
class="iframe-main"
|
this.iframeUrlUpdateKey,
|
||||||
name="___wb_replay_top_frame"
|
html`<iframe
|
||||||
@message="${this.onReplayMessage}"
|
part="iframe ${this.replayNotFoundError
|
||||||
allow="autoplay 'self'; fullscreen"
|
? "iframe-page-not-found"
|
||||||
allowfullscreen
|
: ""}"
|
||||||
src="${this.iframeUrl}"
|
class="iframe-main"
|
||||||
title="${title}"
|
name="___wb_replay_top_frame"
|
||||||
></iframe>
|
@message="${this.onReplayMessage}"
|
||||||
|
allow="autoplay 'self'; fullscreen"
|
||||||
|
allowfullscreen
|
||||||
|
src="${this.iframeUrl}"
|
||||||
|
title="${title}"
|
||||||
|
></iframe>`,
|
||||||
|
)}
|
||||||
${this.showAuth
|
${this.showAuth
|
||||||
? html`
|
? html`
|
||||||
<div class="iframe-main modal-bg">
|
<div class="iframe-main modal-bg">
|
||||||
|
|||||||
@@ -1,8 +1,24 @@
|
|||||||
|
import { registerIconLibrary } from "@shoelace-style/shoelace/dist/utilities/icon-library.js";
|
||||||
|
import systemLibrary from "@shoelace-style/shoelace/dist/components/icon/library.system.js";
|
||||||
|
|
||||||
// Cherry-picked Shoelace components
|
// Cherry-picked Shoelace components
|
||||||
import "@shoelace-style/shoelace/dist/components/alert/alert.js";
|
import "@shoelace-style/shoelace/dist/components/alert/alert.js";
|
||||||
import "@shoelace-style/shoelace/dist/components/button/button.js";
|
import "@shoelace-style/shoelace/dist/components/button/button.js";
|
||||||
import "@shoelace-style/shoelace/dist/components/copy-button/copy-button.js";
|
import "@shoelace-style/shoelace/dist/components/copy-button/copy-button.js";
|
||||||
import "@shoelace-style/shoelace/dist/components/dialog/dialog.js";
|
import "@shoelace-style/shoelace/dist/components/dialog/dialog.js";
|
||||||
|
import "@shoelace-style/shoelace/dist/components/divider/divider.js";
|
||||||
import "@shoelace-style/shoelace/dist/components/dropdown/dropdown.js";
|
import "@shoelace-style/shoelace/dist/components/dropdown/dropdown.js";
|
||||||
import "@shoelace-style/shoelace/dist/components/menu/menu.js";
|
import "@shoelace-style/shoelace/dist/components/menu/menu.js";
|
||||||
import "@shoelace-style/shoelace/dist/components/menu-item/menu-item.js";
|
import "@shoelace-style/shoelace/dist/components/menu-item/menu-item.js";
|
||||||
|
import "@shoelace-style/shoelace/dist/components/menu-label/menu-label.js";
|
||||||
|
|
||||||
|
// disable system library to prevent loading of unused data: URLs
|
||||||
|
// allow only "x-lg" as it is needed for sl-dialog
|
||||||
|
registerIconLibrary("system", {
|
||||||
|
resolver: (name) => {
|
||||||
|
if (name === "x-lg") {
|
||||||
|
return systemLibrary.resolver(name);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
+36
-26
@@ -3,8 +3,8 @@ import { customElement, property } from "lit/decorators.js";
|
|||||||
|
|
||||||
import { wrapCss } from "./misc";
|
import { wrapCss } from "./misc";
|
||||||
|
|
||||||
import fasSortDown from "@fortawesome/fontawesome-free/svgs/solid/sort-down.svg";
|
import iconSortDown from "~icons/sort-down.svg";
|
||||||
import fasSortUp from "@fortawesome/fontawesome-free/svgs/solid/sort-up.svg";
|
import iconSortUp from "~icons/sort-up.svg";
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@customElement("wr-sorter")
|
@customElement("wr-sorter")
|
||||||
@@ -118,34 +118,44 @@ class Sorter<T = unknown> extends LitElement {
|
|||||||
button.button.is-small {
|
button.button.is-small {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.is-small {
|
||||||
|
font-size: var(--sl-font-size-x-small);
|
||||||
|
}
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html` <div class="select is-small">
|
||||||
<div class="select is-small">
|
<select
|
||||||
<select id="sort-select" @change=${(e: Event) =>
|
id="sort-select"
|
||||||
(this.sortKey = (e.currentTarget as HTMLSelectElement).value)}>
|
@change=${(e: Event) =>
|
||||||
|
(this.sortKey = (e.currentTarget as HTMLSelectElement).value)}
|
||||||
${this.sortKeys?.map(
|
>
|
||||||
(sort) => html`
|
${this.sortKeys?.map(
|
||||||
<option value="${sort.key}" ?selected="${sort.key === this.sortKey}">
|
(sort) => html`
|
||||||
Sort By: ${sort.name}
|
<option
|
||||||
</option>
|
value="${sort.key}"
|
||||||
`,
|
?selected="${sort.key === this.sortKey}"
|
||||||
)}
|
>
|
||||||
</select>
|
Sort By: ${sort.name}
|
||||||
</div>
|
</option>
|
||||||
<button @click=${() =>
|
`,
|
||||||
(this.sortDesc = !this.sortDesc)} class="button is-small">
|
)}
|
||||||
<span>Order:</span>
|
</select>
|
||||||
<span class="is-sr-only">${
|
</div>
|
||||||
this.sortDesc ? "Ascending" : "Descending"
|
<button
|
||||||
}</span>
|
@click=${() => (this.sortDesc = !this.sortDesc)}
|
||||||
<span class="icon"><fa-icon aria-hidden="true" .svg=${
|
class="button is-small"
|
||||||
this.sortDesc ? fasSortUp : fasSortDown
|
>
|
||||||
}></span>
|
<span>Order:</span>
|
||||||
</button>`;
|
<span class="is-sr-only"
|
||||||
|
>${this.sortDesc ? "Ascending" : "Descending"}</span
|
||||||
|
>
|
||||||
|
<span class="icon"
|
||||||
|
><wr-icon .svg=${this.sortDesc ? iconSortDown : iconSortUp}></wr-icon
|
||||||
|
></span>
|
||||||
|
</button>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ export type ItemType = {
|
|||||||
totalSize?: unknown;
|
totalSize?: unknown;
|
||||||
size?: number | string;
|
size?: number | string;
|
||||||
canQueryPages?: boolean;
|
canQueryPages?: boolean;
|
||||||
|
pageCount?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FavIconEventDetail = {
|
export type FavIconEventDetail = {
|
||||||
|
|||||||
+110
-45
@@ -3,8 +3,8 @@ import { wrapCss, clickOnSpacebarPress } from "./misc";
|
|||||||
|
|
||||||
import { getReplayLink, getDownloadLink } from "./pageutils";
|
import { getReplayLink, getDownloadLink } from "./pageutils";
|
||||||
|
|
||||||
import fasSearch from "@fortawesome/fontawesome-free/svgs/solid/search.svg";
|
import iconDownload from "~icons/download.svg";
|
||||||
import fasDownload from "@fortawesome/fontawesome-free/svgs/solid/download.svg";
|
import iconSearch from "~icons/search.svg";
|
||||||
|
|
||||||
import "keyword-mark-element/lib/keyword-mark.js";
|
import "keyword-mark-element/lib/keyword-mark.js";
|
||||||
import { type ItemType } from "./types";
|
import { type ItemType } from "./types";
|
||||||
@@ -268,6 +268,10 @@ class URLResources extends LitElement {
|
|||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host(.sidebar) .level-left {
|
||||||
|
margin-bottom: var(--sl-spacing-x-small);
|
||||||
|
}
|
||||||
|
|
||||||
:host(.sidebar) .columns {
|
:host(.sidebar) .columns {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -277,17 +281,33 @@ class URLResources extends LitElement {
|
|||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification {
|
.search-bar {
|
||||||
|
gap: var(--sl-spacing-small);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
background-color: var(--sl-color-neutral-100);
|
||||||
|
border-bottom: 1px solid var(--sl-panel-border-color);
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
|
padding: var(--sl-spacing-x-small);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-bar .level-item {
|
||||||
|
gap: var(--sl-spacing-x-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar .input,
|
||||||
|
.search-bar .radio {
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
|
}
|
||||||
|
|
||||||
.all-results {
|
.all-results {
|
||||||
margin: 0 0 0 0.5em;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
flex: 1 1 0;
|
||||||
}
|
}
|
||||||
.main-scroll {
|
.main-scroll {
|
||||||
flex-grow: 1;
|
flex: 1 1 0;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
}
|
}
|
||||||
.minihead {
|
.minihead {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
@@ -296,32 +316,58 @@ class URLResources extends LitElement {
|
|||||||
.columns {
|
.columns {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
thead {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
table th:not([align]) {
|
table th:not([align]) {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
.result {
|
.result {
|
||||||
border-bottom: 1px #dbdbdb solid;
|
|
||||||
min-height: fit-content;
|
min-height: fit-content;
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result:first-child {
|
||||||
|
margin-top: var(--sl-spacing-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.result:not(:last-child) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
border-bottom: 1px solid var(--sl-panel-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
.results-head {
|
.results-head {
|
||||||
border-bottom: 2px #dbdbdb solid;
|
border-bottom: 1px solid var(--sl-panel-border-color);
|
||||||
margin-right: 16px;
|
|
||||||
min-height: fit-content;
|
min-height: fit-content;
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
padding-right: 15px; // For scrollbar gutter
|
||||||
}
|
}
|
||||||
.results-head a {
|
|
||||||
color: black;
|
.results-head .column {
|
||||||
|
background-color: var(--sl-panel-background-color);
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table .column {
|
||||||
|
padding: var(--sl-spacing-x-small);
|
||||||
|
}
|
||||||
|
|
||||||
.all-results .column {
|
.all-results .column {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
.dl-button {
|
|
||||||
padding: 4px;
|
tbody .col-url a {
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dl-button {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 1.125rem;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
padding: var(--sl-spacing-3x-small);
|
||||||
|
}
|
||||||
|
|
||||||
div.sort-header {
|
div.sort-header {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin-bottom: 0px !important;
|
margin-bottom: 0px !important;
|
||||||
@@ -330,6 +376,17 @@ class URLResources extends LitElement {
|
|||||||
.flex-auto {
|
.flex-auto {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sort-control-label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--sl-spacing-2x-small);
|
||||||
|
font-size: var(--sl-font-size-small);
|
||||||
|
font-weight: var(--sl-font-weight-semibold);
|
||||||
|
color: var(--sl-color-neutral-600);
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.asc:after {
|
.asc:after {
|
||||||
content: "▼";
|
content: "▼";
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
@@ -338,9 +395,12 @@ class URLResources extends LitElement {
|
|||||||
content: "▲";
|
content: "▲";
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.num-results {
|
.num-results {
|
||||||
margin-left: 1em;
|
font-size: var(--sl-font-size-small);
|
||||||
font-style: italic;
|
color: var(--sl-color-neutral-500);
|
||||||
|
line-height: 1;
|
||||||
|
margin-left: var(--sl-spacing-small);
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
@@ -362,10 +422,10 @@ class URLResources extends LitElement {
|
|||||||
>
|
>
|
||||||
Search and Filter
|
Search and Filter
|
||||||
</div>
|
</div>
|
||||||
<div class="notification level is-marginless">
|
<div class="search-bar level is-marginless">
|
||||||
<div class="level-left flex-auto">
|
<div class="level-left flex-auto">
|
||||||
<div class="level-item flex-auto">
|
<div class="level-item flex-auto">
|
||||||
<span class="is-hidden-mobile">Search: </span>
|
<span class="is-hidden-mobile">Search:</span>
|
||||||
<div class="select">
|
<div class="select">
|
||||||
<select @change="${this.onChangeTypeSearch}">
|
<select @change="${this.onChangeTypeSearch}">
|
||||||
${URLResources.filters.map(
|
${URLResources.filters.map(
|
||||||
@@ -393,15 +453,15 @@ class URLResources extends LitElement {
|
|||||||
.value="${this.query}"
|
.value="${this.query}"
|
||||||
placeholder="Enter URL to Search"
|
placeholder="Enter URL to Search"
|
||||||
/>
|
/>
|
||||||
<span class="icon is-left"
|
<span class="icon is-left is-small"
|
||||||
><fa-icon .svg="${fasSearch}"></fa-icon
|
><wr-icon .svg="${iconSearch}"></wr-icon
|
||||||
></span>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="control level-right">
|
<div class="control level-right">
|
||||||
<div style="margin-left: 1em" class="control">
|
<div class="control">
|
||||||
<label class="radio has-text-left"
|
<label class="radio has-text-left"
|
||||||
><input
|
><input
|
||||||
type="radio"
|
type="radio"
|
||||||
@@ -435,7 +495,9 @@ class URLResources extends LitElement {
|
|||||||
is-pulled-right
|
is-pulled-right
|
||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
aria-atomic="true"
|
aria-atomic="true"
|
||||||
>${this.filteredResults.length} Result(s)</span
|
>${this.filteredResults.length.toLocaleString()}
|
||||||
|
${this.filteredResults.length === 1 ? "result" : "results"}
|
||||||
|
shown</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -463,7 +525,7 @@ class URLResources extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="all-results" aria-labelledby="results-heading num-results">
|
<table class="all-results" aria-labelledby="results-heading num-results">
|
||||||
<thead>
|
<thead class="all-results-header">
|
||||||
<tr class="columns results-head has-text-weight-bold">
|
<tr class="columns results-head has-text-weight-bold">
|
||||||
<th scope="col" class="column col-url is-6 is-hidden-mobile">
|
<th scope="col" class="column col-url is-6 is-hidden-mobile">
|
||||||
<a
|
<a
|
||||||
@@ -472,7 +534,7 @@ class URLResources extends LitElement {
|
|||||||
@click="${this.onSort}"
|
@click="${this.onSort}"
|
||||||
@keyup="${clickOnSpacebarPress}"
|
@keyup="${clickOnSpacebarPress}"
|
||||||
data-key="url"
|
data-key="url"
|
||||||
class="${this.sortKey === "url"
|
class="sort-control-label ${this.sortKey === "url"
|
||||||
? this.sortDesc
|
? this.sortDesc
|
||||||
? "desc"
|
? "desc"
|
||||||
: "asc"
|
: "asc"
|
||||||
@@ -487,7 +549,7 @@ class URLResources extends LitElement {
|
|||||||
@click="${this.onSort}"
|
@click="${this.onSort}"
|
||||||
@keyup="${clickOnSpacebarPress}"
|
@keyup="${clickOnSpacebarPress}"
|
||||||
data-key="ts"
|
data-key="ts"
|
||||||
class="${this.sortKey === "ts"
|
class="sort-control-label ${this.sortKey === "ts"
|
||||||
? this.sortDesc
|
? this.sortDesc
|
||||||
? "desc"
|
? "desc"
|
||||||
: "asc"
|
: "asc"
|
||||||
@@ -495,14 +557,14 @@ class URLResources extends LitElement {
|
|||||||
>Date</a
|
>Date</a
|
||||||
>
|
>
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" class="column col-mime is-3 is-hidden-mobile">
|
<th scope="col" class="column col-mime is-2 is-hidden-mobile">
|
||||||
<a
|
<a
|
||||||
role="button"
|
role="button"
|
||||||
href="#"
|
href="#"
|
||||||
@click="${this.onSort}"
|
@click="${this.onSort}"
|
||||||
@keyup="${clickOnSpacebarPress}"
|
@keyup="${clickOnSpacebarPress}"
|
||||||
data-key="mime"
|
data-key="mime"
|
||||||
class="${this.sortKey === "mime"
|
class="sort-control-label ${this.sortKey === "mime"
|
||||||
? this.sortDesc
|
? this.sortDesc
|
||||||
? "desc"
|
? "desc"
|
||||||
: "asc"
|
: "asc"
|
||||||
@@ -517,7 +579,7 @@ class URLResources extends LitElement {
|
|||||||
@click="${this.onSort}"
|
@click="${this.onSort}"
|
||||||
@keyup="${clickOnSpacebarPress}"
|
@keyup="${clickOnSpacebarPress}"
|
||||||
data-key="status"
|
data-key="status"
|
||||||
class="${this.sortKey === "status"
|
class="sort-control-label ${this.sortKey === "status"
|
||||||
? this.sortDesc
|
? this.sortDesc
|
||||||
? "desc"
|
? "desc"
|
||||||
: "asc"
|
: "asc"
|
||||||
@@ -525,6 +587,9 @@ class URLResources extends LitElement {
|
|||||||
>Status</a
|
>Status</a
|
||||||
>
|
>
|
||||||
</th>
|
</th>
|
||||||
|
<th scope="col" class="column col-actions is-1 is-hidden-mobile">
|
||||||
|
<span class="sr-only">Actions</span>
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
@@ -535,21 +600,6 @@ class URLResources extends LitElement {
|
|||||||
<tr class="columns result">
|
<tr class="columns result">
|
||||||
<td class="column col-url is-6">
|
<td class="column col-url is-6">
|
||||||
<p class="minihead is-hidden-tablet">URL</p>
|
<p class="minihead is-hidden-tablet">URL</p>
|
||||||
<a
|
|
||||||
class="dl-button"
|
|
||||||
href="${getDownloadLink(
|
|
||||||
this.collInfo!.replayPrefix,
|
|
||||||
result.url,
|
|
||||||
result.ts,
|
|
||||||
)}"
|
|
||||||
><fa-icon
|
|
||||||
size="1.0em"
|
|
||||||
class="has-text-black"
|
|
||||||
aria-hidden="true"
|
|
||||||
title="Download Resource"
|
|
||||||
.svg="${fasDownload}"
|
|
||||||
></fa-icon>
|
|
||||||
</a>
|
|
||||||
<a
|
<a
|
||||||
@click="${this.onReplay}"
|
@click="${this.onReplay}"
|
||||||
data-url="${result.url}"
|
data-url="${result.url}"
|
||||||
@@ -569,7 +619,7 @@ class URLResources extends LitElement {
|
|||||||
<p class="minihead is-hidden-tablet">Date</p>
|
<p class="minihead is-hidden-tablet">Date</p>
|
||||||
${dateTimeFormatter.format(new Date(result.date))}
|
${dateTimeFormatter.format(new Date(result.date))}
|
||||||
</td>
|
</td>
|
||||||
<td class="column col-mime is-3">
|
<td class="column col-mime is-2">
|
||||||
<p class="minihead is-hidden-tablet">Media Type</p>
|
<p class="minihead is-hidden-tablet">Media Type</p>
|
||||||
${result.mime}
|
${result.mime}
|
||||||
</td>
|
</td>
|
||||||
@@ -577,6 +627,21 @@ class URLResources extends LitElement {
|
|||||||
<p class="minihead is-hidden-tablet">Status</p>
|
<p class="minihead is-hidden-tablet">Status</p>
|
||||||
${result.status}
|
${result.status}
|
||||||
</td>
|
</td>
|
||||||
|
<td class="column col-actions is-1">
|
||||||
|
<a
|
||||||
|
class="dl-button"
|
||||||
|
href="${getDownloadLink(
|
||||||
|
this.collInfo!.replayPrefix,
|
||||||
|
result.url,
|
||||||
|
result.ts,
|
||||||
|
)}"
|
||||||
|
download
|
||||||
|
><wr-icon
|
||||||
|
title="Download Resource"
|
||||||
|
.svg="${iconDownload}"
|
||||||
|
></wr-icon>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
`,
|
`,
|
||||||
)
|
)
|
||||||
|
|||||||
+20
-4
@@ -2,7 +2,11 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./dist/",
|
"outDir": "./dist/",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"lib": ["esnext", "dom", "dom.iterable"],
|
"lib": [
|
||||||
|
"esnext",
|
||||||
|
"dom",
|
||||||
|
"dom.iterable"
|
||||||
|
],
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"moduleResolution": "Bundler",
|
"moduleResolution": "Bundler",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
@@ -29,9 +33,21 @@
|
|||||||
],
|
],
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"flexsearch": ["./node_modules/@types/flexsearch"],
|
"flexsearch": [
|
||||||
"~assets/*": ["./src/assets/*"]
|
"./node_modules/@types/flexsearch"
|
||||||
|
],
|
||||||
|
"~assets/*": [
|
||||||
|
"./src/assets/*"
|
||||||
|
],
|
||||||
|
"~icons/*": [
|
||||||
|
"./node_modules/@shoelace-style/shoelace/dist/assets/icons/*",
|
||||||
|
"./node_modules/@fortawesome/fontawesome-free/svgs/*",
|
||||||
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.d.ts"]
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.js",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
+18
-28
@@ -51,6 +51,22 @@ const tsConfig = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @type {import("webpack").Configuration.module.rules} */
|
||||||
|
const commonModuleRules = [
|
||||||
|
{
|
||||||
|
test: /\.svg$/,
|
||||||
|
type: "asset/source",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /main.scss$/,
|
||||||
|
use: ["css-loader", "sass-loader"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /wombat.js|wombatWorkers.js|index.html$/i,
|
||||||
|
type: "asset/source",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const electronMainConfig = (/*env, argv*/) => {
|
const electronMainConfig = (/*env, argv*/) => {
|
||||||
/** @type {import('webpack').Configuration} */
|
/** @type {import('webpack').Configuration} */
|
||||||
const config = {
|
const config = {
|
||||||
@@ -165,20 +181,7 @@ const libConfig = (env, argv) => {
|
|||||||
],
|
],
|
||||||
|
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [...commonModuleRules],
|
||||||
{
|
|
||||||
test: /\.svg$/,
|
|
||||||
use: ["raw-loader"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /main.scss$/,
|
|
||||||
use: ["css-loader", "sass-loader"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /wombat.js|wombatWorkers.js|index.html$/i,
|
|
||||||
use: ["raw-loader"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return merge(tsConfig, config);
|
return merge(tsConfig, config);
|
||||||
@@ -258,20 +261,7 @@ const browserConfig = (/*env, argv*/) => {
|
|||||||
],
|
],
|
||||||
|
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [...commonModuleRules],
|
||||||
{
|
|
||||||
test: /\.svg$/,
|
|
||||||
use: ["raw-loader"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /main.scss$/,
|
|
||||||
use: ["css-loader", "sass-loader"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /wombat.js|wombatWorkers.js|index.html$/i,
|
|
||||||
use: ["raw-loader"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return merge(tsConfig, config);
|
return merge(tsConfig, config);
|
||||||
|
|||||||
Reference in New Issue
Block a user