Files
replayweb.page/src/embed-receipt.ts
T
Henry WilkinsonandIlya Kreymer cbe98c4fa1 Reasonably Scoped Branding Update (#299)
- Adds TsconfigPathsPlugin
- Custom icons, branding assets, and favicons now all live under
`/src/assets` in organized folders (Mirrors Browsertrix folder
organization and naming)
- Assets can now be referenced with `import: varName from
~assets/assetpath` app wide!
- SVGs continue to use `svg-inline-loader`, favicons are copied to
`/site/favicons` on app build
- Adds favicons to the main `index.html` page for ReplayWeb.page and
`embed.html` example page
- Replace README header with new branding
  - Lives under /assets because it's not app related
- Adds new webmanifest app icons
- Adds new Electron app .icns (macOS ) and .png (Windows & Linux) app
icons
- Replaces globe icon in the embed receipt with ReplayWebpage icon!
  - Adds lockup to the footer section
- Removes logo animation
- Removes logo values from `renderErrorReport()` in swmanager.ts in
favour of additional import statements

---------
Co-authored-by: Ilya Kreymer <ikreymer@gmail.com>
2024-04-08 18:47:17 -07:00

353 lines
10 KiB
TypeScript

import rwpLogo from "~assets/brand/replaywebpage-icon-color.svg";
import brandLockupColor from "~assets/brand/replaywebpage-lockup-color.svg";
import btAngleDoubleDown from "~assets/icons/chevron-double-down.svg";
import btAngleDoubleUp from "~assets/icons/chevron-double-up.svg";
import fabGithub from "@fortawesome/fontawesome-free/svgs/brands/github.svg";
import fasDownload from "@fortawesome/fontawesome-free/svgs/solid/download.svg";
import { clickOnSpacebarPress } from "./misc";
import { LitElement, html, css, nothing } from "lit";
import { tsToDate } from "./pageutils";
import prettyBytes from "pretty-bytes";
import { property } from "lit/decorators.js";
import type { ItemType } from "./types";
// ===========================================================================
export class RWPEmbedReceipt extends LitElement {
@property({ type: Object }) collInfo:
| ItemType
| null
| Record<string, never> = null;
@property({ type: String }) ts: string | null = null;
@property({ type: String }) url: string | null = null;
@property({ type: Boolean }) active = false;
// @ts-expect-error - TS2611 - 'renderRoot' is defined as a property in class 'LitElement', but is overridden here in 'RWPEmbedReceipt' as an accessor.
get renderRoot() {
return this;
}
static get embedStyles() {
return css`
rwp-embed-receipt {
display: flex;
flex-direction: column;
}
.icon {
vertical-align: text-top;
}
#embed-dropdown {
max-height: calc(100vh - 50px);
padding-top: 0;
margin-top: -0.5rem;
display: block;
z-index: 1;
pointer-events: none;
transition: all 0.3s linear;
transform-origin: left top;
transform: scaleY(0);
transition: all 300ms cubic-bezier(0.15, 0, 0.1, 1);
filter: drop-shadow(0px 8px 4px rgba(0, 0, 0, 0.15));
}
.dropdown.is-active #embed-dropdown {
transform: scaleY(1);
}
.embed-info-container {
width: 100%;
display: flex !important;
justify-content: center;
}
button.embed-info {
padding: 0;
background-color: white;
justify-content: space-between;
max-width: 40rem;
width: calc(100% - 1rem);
height: 42px;
border-color: #d1d5da;
border-width: 1px;
border-style: solid;
border-radius: 999px;
display: flex;
align-items: center;
text-overflow: ellipsis;
filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.15));
transition-duration: 50ms;
transition-timing-function: ease-out;
cursor: pointer;
z-index: 2;
}
button.embed-info:active {
color: initial;
}
button.embed-info:hover {
filter: drop-shadow(0px 2px 4px rgba(0, 0, 0, 0.2));
transform: scale(1.01);
}
button.embed-info:hover:active {
transform: translateY(0.25rem);
}
.embed-info-buttontext {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex-grow: 1;
text-align: start;
font-size: 13px;
}
.embed-info-drop {
font-size: 14px;
padding: 1rem;
padding-top: 2rem;
max-width: 38rem;
max-height: 42rem;
width: calc(100% - 2rem);
border-top-right-radius: 0px;
border-top-left-radius: 0px;
pointer-events: auto;
overflow-y: auto;
}
.embed-info-drop > p {
font-size: 14px;
color: black;
}
.embed-info-drop > h2 {
margin-bottom: 0.25rem;
font-size: 16px;
font-weight: bold;
text-transform: none;
letter-spacing: 0;
color: #24292e;
}
.embed-info-drop-statscontainer > h3 {
font-size: 12px;
color: #394146;
}
.embed-info-drop-statscontainer > p {
font-size: 14px;
color: black;
}
.embed-info-drop a {
word-break: break-all;
}
.embed-info-drop .show-hash {
word-break: break-all;
font-family: monospace;
}
.embed-info-drop .show-key {
text-overflow: ellipsis;
overflow: hidden;
whitespace: nowrap;
font-family: monospace;
}
.embed-logo {
margin: 0.5rem;
line-height: 0.5rem;
}
`;
}
render() {
const {
numValid = 0,
numInvalid = 0,
domain,
certFingerprint,
datapackageHash,
publicKey,
software,
} = this.collInfo?.verify ?? {};
const sourceUrl = this.collInfo?.sourceUrl;
const certFingerprintUrl = certFingerprint
? `https://crt.sh/?q=${certFingerprint}`
: "";
const dateStr = tsToDate(this.ts).toLocaleString();
return html`
<div class="dropdown mb-4 ${this.active ? "is-active" : ""}">
<div class="dropdown-trigger embed-info-container">
<button
class="embed-info is-small is-rounded mt-4"
aria-haspopup="true"
aria-controls="embed-dropdown"
@click="${this.onEmbedDrop}"
>
<fa-icon
class="embed-logo"
size="1.5rem"
aria-hidden="true"
.svg=${rwpLogo}
></fa-icon>
<span class="embed-info-buttontext">
This embed is part of a web archive. Click here to learn more.
</span>
<span class="icon is-small mr-4 ml-2">
<fa-icon
title="Toggle"
.svg="${this.active ? btAngleDoubleUp : btAngleDoubleDown}"
aria-hidden="true"
></fa-icon>
</span>
</button>
</div>
<div
class="dropdown-menu embed-info-container"
id="embed-dropdown"
role="menu"
>
<div class="dropdown-content embed-info-drop">
<p class="mb-4">
Even if the original page goes offline or is changed, the content
below will remain unchanged as it is loaded from a web archive.
</p>
<hr class="dropdown-divider" />
<h2 class="mt-4">Get A Copy!</h2>
<p class="mt-2">
After downloading, this web archive can be loaded and viewed
directly in your browser via
<a
style="white-space: nowrap;"
target="_blank"
href="https://replayweb.page"
>replayweb.page</a
>.
</p>
${sourceUrl
? html`
<a
href="${sourceUrl}"
class="button is-primary mt-4"
@keyup="${clickOnSpacebarPress}"
>
<span class="icon is-small">
<fa-icon
size="1.0em"
aria-hidden="true"
.svg="${fasDownload}"
></fa-icon>
</span>
<span>Download Archive</span>
</a>
<hr class="dropdown-divider mt-4" />
`
: nothing}
<h2 class="mt-4">Technical Information</h2>
<div class="embed-info-drop-statscontainer mb-4">
${this.url
? html`
<h3>Original URL:</h3>
<p>
<a target="_blank" href="${this.url}">${this.url}</a>
</p>
`
: nothing}
<h3 class="mt-2">Archived On:</h3>
<p>${dateStr}</p>
${domain
? html`
<h3 class="mt-2">Observed By:</h3>
<p>${domain}</p>
${certFingerprintUrl
? html` <p>
<a target="_blank" href="${certFingerprintUrl}"
>View Certificate</a
>
</p>`
: ""}
`
: software
? html` <h3 class="mt-2">Created With:</h3>
<p>${software}</p>`
: ""}
${!domain && publicKey
? html` <h3 class="mt-2">Observer Public Key:</h3>
<p class="show-key">${publicKey}</p>`
: ""}
<h3 class="mt-2">Validation:</h3>
${numValid > 0 || numInvalid > 0
? html` <p>
${numValid} hashes
verified${numInvalid ? html`, ${numInvalid} invalid` : ""}
</p>`
: html` <p>Not Available</p> `}
<h3 class="mt-2">Package Hash:</h3>
<p class="show-hash">${datapackageHash}</p>
${this.collInfo?.size != null
? html`
<h3 class="mt-2">Size</h3>
<p>${prettyBytes(Number(this.collInfo.size || 0))}</p>
`
: nothing}
</div>
${sourceUrl ? html`` : ""}
<div
class="is-size-7 is-flex is-justify-content-space-between is-align-items-center"
style="margin-top: 40px"
>
<div>
<a
target="_blank"
href="https://github.com/webrecorder/replayweb.page"
>
<img
style="height: 1.5rem;"
src="data:image/svg+xml,${encodeURIComponent(
brandLockupColor as string,
)}"
alt="ReplayWeb.page Logo"
/>
</a>
</div>
<span>
<a
class="has-text-black"
target="_blank"
href="https://github.com/webrecorder/replayweb.page"
>Source Code
<fa-icon
class="menu-logo ml-1"
size="1.0rem"
aria-hidden="true"
.svg=${fabGithub}
></fa-icon>
</a>
</span>
</div>
</div>
</div>
</div>
`;
}
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'event' implicitly has an 'any' type.
onEmbedDrop(event) {
event.stopPropagation();
this.active = !this.active;
}
}
customElements.define("rwp-embed-receipt", RWPEmbedReceipt);