Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Collection thumbnails, start page, and public view updates #2209

Merged
merged 43 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
457ad69
update types
SuaYoo Dec 4, 2024
b6940f3
update routes
SuaYoo Dec 9, 2024
13c29ad
update description
SuaYoo Dec 9, 2024
d51e21b
switch to offscreen tab
SuaYoo Dec 9, 2024
3aa6195
remove public option on create
SuaYoo Dec 9, 2024
0329afa
update spinner
SuaYoo Dec 9, 2024
37f8268
select default thumbnail
SuaYoo Dec 10, 2024
bbb970b
show collections in dashboard
SuaYoo Dec 10, 2024
d97514c
update thumbnails
SuaYoo Dec 10, 2024
6c9cd7f
add caption
SuaYoo Dec 10, 2024
29a84d2
add start page dialog
SuaYoo Dec 10, 2024
ff66113
use default thumbnail
SuaYoo Dec 11, 2024
1fe1a0d
default thumbnails
SuaYoo Dec 11, 2024
3f07c22
show snapshot list
SuaYoo Dec 11, 2024
7594004
update layouts
SuaYoo Dec 11, 2024
941cf6f
update home view dialog
SuaYoo Dec 11, 2024
7352dd2
update thumbnail preview
SuaYoo Dec 11, 2024
8b0902c
use custom thumbnail
SuaYoo Dec 11, 2024
80508b0
use existing replay frame
SuaYoo Dec 12, 2024
6417f0f
update dialog save progress
SuaYoo Dec 12, 2024
9f52725
simplify thumbnails
SuaYoo Dec 12, 2024
8845e5f
hide replay tab if no items
SuaYoo Dec 12, 2024
5048a99
enable download
SuaYoo Dec 17, 2024
d0b09ee
show start page
SuaYoo Dec 17, 2024
857fd34
update layout
SuaYoo Dec 17, 2024
3e82c1b
update access
SuaYoo Dec 17, 2024
a4dce9f
update layout
SuaYoo Dec 17, 2024
4b248a9
Apply suggestions from code review
SuaYoo Dec 17, 2024
38a99d4
update not found page
SuaYoo Dec 17, 2024
d178dfd
add disclaimer
SuaYoo Dec 17, 2024
d62e3ef
update thumbnail styles
SuaYoo Dec 17, 2024
3335117
show what will be public
SuaYoo Dec 17, 2024
251b1a7
update info text
SuaYoo Dec 17, 2024
d67dffb
Update frontend/src/features/collections/select-collection-start-page.ts
SuaYoo Dec 17, 2024
71b1d7c
update copy
SuaYoo Dec 17, 2024
8e95a3a
revert test
SuaYoo Dec 17, 2024
2ab49a7
show first few results
SuaYoo Dec 17, 2024
dd90831
fix updating snapshot after home url
SuaYoo Dec 17, 2024
e6aad3e
remove console log
SuaYoo Dec 17, 2024
0ef99fd
add link to org settings
SuaYoo Dec 17, 2024
474eadd
show download toggle
SuaYoo Dec 18, 2024
237b6ab
remove min height
SuaYoo Dec 18, 2024
2e6467f
encode url prefix
SuaYoo Dec 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
declare module "*.avif";
declare module "*.svg";
declare module "*.webp";
declare module "*.css";
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
38 changes: 25 additions & 13 deletions frontend/src/components/not-found.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { localized, msg } from "@lit/localize";
import { html } from "lit";
import { html, nothing } from "lit";
import { customElement } from "lit/decorators.js";

import { BtrixElement } from "@/classes/BtrixElement";
Expand All @@ -9,27 +9,39 @@ import { BtrixElement } from "@/classes/BtrixElement";
export class NotFound extends BtrixElement {
render() {
return html`
<div class="text-center text-neutral-500">
<p class="my-4 border-b py-4 text-xl leading-none text-neutral-400">
${msg("Page not found")}
<div class="text-center">
<p class="my-4 border-b py-4 text-xl leading-none text-neutral-500">
${msg("Sorry, we couldn’t find that page")}
</p>
<p>
<p class="text-neutral-600">
${msg("Check the URL to make sure you’ve entered it correctly.")}
</p>
<div class="my-4">
<sl-button href="/" @click=${this.navigate.link} size="small"
>${msg("Go to Home")}</sl-button
>
</div>
<p class="text-neutral-500">
${msg("Did you click a link to get here?")}
<button
class="text-blue-500 transition-colors hover:text-blue-600"
class="text-cyan-500 transition-colors hover:text-cyan-600"
@click=${() => {
window.history.back();
}}
>
${msg("Go Back")}
</button>
<br />
${msg("Or")}
<btrix-link
href="https://github.com/webrecorder/browsertrix/issues/new/choose"
>
${msg("Report a Broken Link")}
</btrix-link>
${this.navigate.isPublicPage
? nothing
: html`
<br />
${msg("Or")}
<btrix-link
href="https://github.com/webrecorder/browsertrix/issues/new/choose"
>
${msg("Report a Broken Link")}
</btrix-link>
`}
</p>
</div>
`;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ui/button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class Button extends TailwindElement {
small: tw`min-h-6 min-w-6 rounded-md text-base`,
medium: tw`min-h-8 min-w-8 rounded-sm text-lg`,
}[this.size],
this.raised && tw`border shadow-sm`,
this.raised && tw`shadow ring-1 ring-neutral-200`,
this.filled
? [
tw`text-white`,
Expand Down
18 changes: 16 additions & 2 deletions frontend/src/components/ui/markdown-editor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { msg, str } from "@lit/localize";
import { localized, msg, str } from "@lit/localize";
import { wrap, type AwaitableInstance } from "ink-mde";
import { css, html, type PropertyValues } from "lit";
import { customElement, property, query } from "lit/decorators.js";
Expand All @@ -16,6 +16,7 @@ export type MarkdownChangeEvent = CustomEvent<MarkdownChangeDetail>;
*
* @fires btrix-change MarkdownChangeEvent
*/
@localized()
@customElement("btrix-markdown-editor")
export class MarkdownEditor extends BtrixElement {
static styles = css`
Expand Down Expand Up @@ -53,11 +54,18 @@ export class MarkdownEditor extends BtrixElement {
white-space: nowrap;
border-width: 0;
}

.cm-line:only-child {
min-height: 8em;
}
`;

@property({ type: String })
label = "";

@property({ type: String })
placeholder = "";

@property({ type: String })
initialValue = "";

Expand All @@ -76,6 +84,11 @@ export class MarkdownEditor extends BtrixElement {
return this.textarea?.checkValidity();
}

public async focus() {
await this.updateComplete;
(await this.editor)?.focus();
}

protected willUpdate(changedProperties: PropertyValues<this>): void {
if (
changedProperties.has("initialValue") &&
Expand All @@ -99,7 +112,7 @@ export class MarkdownEditor extends BtrixElement {
const isInvalid = this.maxlength && this.value.length > this.maxlength;
return html`
<fieldset ?data-invalid=${isInvalid} ?data-user-invalid=${isInvalid}>
<label class="form-label">${this.label}</label>
${this.label && html`<label class="form-label">${this.label}</label>`}
<textarea id="editor-textarea"></textarea>
<div class="helpText flex items-baseline justify-between">
<p class="text-xs">
Expand Down Expand Up @@ -181,6 +194,7 @@ export class MarkdownEditor extends BtrixElement {
taskList: false,
upload: false,
},
placeholder: this.placeholder,
});
}
}
12 changes: 12 additions & 0 deletions frontend/src/components/ui/markdown-viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ export class MarkdownViewer extends LitElement {
img {
max-width: 100%;
}
p {
line-height: inherit;
}
p:first-child {
margin-top: 0;
}
p:last-child {
margin-bottom: 0;
}
`,
];

Expand Down
27 changes: 18 additions & 9 deletions frontend/src/components/ui/overflow-dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import type { SlDropdown, SlMenu } from "@shoelace-style/shoelace";
import { html } from "lit";
import {
customElement,
property,
query,
queryAssignedElements,
state,
} from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";

import { TailwindElement } from "@/classes/TailwindElement";

Expand All @@ -26,6 +28,9 @@ import { TailwindElement } from "@/classes/TailwindElement";
@localized()
@customElement("btrix-overflow-dropdown")
export class OverflowDropdown extends TailwindElement {
@property({ type: Boolean })
raised = false;

@state()
private hasMenuItems?: boolean;

Expand All @@ -37,15 +42,19 @@ export class OverflowDropdown extends TailwindElement {

render() {
return html`
<sl-dropdown ?disabled=${!this.hasMenuItems} hoist>
<sl-icon-button
slot="trigger"
class="font-base attr-[disabled]:invisible part-[base]:p-3"
label=${msg("Actions")}
name="three-dots-vertical"
?disabled=${!this.hasMenuItems}
>
</sl-icon-button>
<sl-dropdown
?disabled=${!this.hasMenuItems}
hoist
distance=${ifDefined(this.raised ? "4" : undefined)}
>
<btrix-button slot="trigger" ?raised=${this.raised}>
<sl-icon
label=${msg("Actions")}
name="three-dots-vertical"
class="size-4 text-base leading-none"
></sl-icon>
</btrix-button>

<slot
@slotchange=${() => (this.hasMenuItems = this.menu.length > 0)}
></slot>
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/components/ui/section-heading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ export class SectionHeading extends LitElement {
gap: 0.5rem;
font-size: var(--sl-font-size-medium);
color: var(--sl-color-neutral-500);
padding-top: var(--sl-spacing-x-small);
padding-bottom: var(--sl-spacing-x-small);
min-height: 2rem;
line-height: 1;
border-bottom: 1px solid var(--sl-panel-border-color);
margin-bottom: var(--margin);
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/ui/table/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ tableCSS.split("}").forEach((rule: string) => {
* @slot head
* @slot
* @csspart head
* @cssproperty --btrix-column-gap
* @cssproperty --btrix-cell-gap
* @cssproperty --btrix-cell-padding-top
* @cssproperty --btrix-cell-padding-left
Expand All @@ -58,13 +59,15 @@ tableCSS.split("}").forEach((rule: string) => {
export class Table extends LitElement {
static styles = css`
:host {
--btrix-column-gap: 0;
--btrix-cell-gap: 0;
--btrix-cell-padding-top: 0;
--btrix-cell-padding-bottom: 0;
--btrix-cell-padding-left: 0;
--btrix-cell-padding-right: 0;
display: grid;
column-gap: var(--btrix-column-gap, 0);
}
`;

Expand Down
85 changes: 84 additions & 1 deletion frontend/src/controllers/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { msg } from "@lit/localize";
import type { ReactiveController, ReactiveControllerHost } from "lit";
import throttle from "lodash/fp/throttle";

import { APIError, type Detail } from "@/utils/api";
import AuthService from "@/utils/AuthService";
Expand All @@ -12,6 +13,11 @@ export interface APIEventMap {
"btrix-storage-quota-update": CustomEvent<QuotaUpdateDetail>;
}

export enum AbortReason {
UserCancel = "user-canceled",
QuotaReached = "storage_quota_reached",
}

/**
* Utilities for interacting with the Browsertrix backend API
*
Expand All @@ -29,13 +35,20 @@ export interface APIEventMap {
export class APIController implements ReactiveController {
host: ReactiveControllerHost & EventTarget;

uploadProgress = 0;

private uploadRequest: XMLHttpRequest | null = null;

constructor(host: APIController["host"]) {
this.host = host;
host.addController(this);
}

hostConnected() {}
hostDisconnected() {}

hostDisconnected() {
this.cancelUpload();
}

async fetch<T = unknown>(path: string, options?: RequestInit): Promise<T> {
const auth = appState.auth;
Expand Down Expand Up @@ -156,4 +169,74 @@ export class APIController implements ReactiveController {
details: errorDetail as Detail[],
});
}

async upload(
path: string,
file: File,
): Promise<{ id: string; added: boolean; storageQuotaReached: boolean }> {
const auth = appState.auth;

if (!auth) throw new Error("auth not in state");

// TODO handle multiple uploads
if (this.uploadRequest) {
console.debug("upload request exists");
this.cancelUpload();
}

return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();

xhr.open("PUT", `/api/${path}`);
xhr.setRequestHeader("Content-Type", "application/octet-stream");
Object.entries(auth.headers).forEach(([k, v]) => {
xhr.setRequestHeader(k, v);
});
xhr.addEventListener("load", () => {
if (xhr.status === 200) {
resolve(
JSON.parse(xhr.response as string) as {
id: string;
added: boolean;
storageQuotaReached: boolean;
},
);
}
if (xhr.status === 403) {
reject(AbortReason.QuotaReached);
}
});
xhr.addEventListener("error", () => {
reject(
new APIError({
message: xhr.statusText,
status: xhr.status,
}),
);
});
xhr.addEventListener("abort", () => {
reject(AbortReason.UserCancel);
});
xhr.upload.addEventListener("progress", this.onUploadProgress);

xhr.send(file);

this.uploadRequest = xhr;
});
}

readonly onUploadProgress = throttle(100)((e: ProgressEvent) => {
this.uploadProgress = (e.loaded / e.total) * 100;

this.host.requestUpdate();
});

private cancelUpload() {
if (this.uploadRequest) {
this.uploadRequest.abort();
this.uploadRequest = null;
}

this.onUploadProgress.cancel();
}
}
6 changes: 6 additions & 0 deletions frontend/src/controllers/navigate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ export class NavigateController implements ReactiveController {
return "/";
}

get isPublicPage() {
return window.location.pathname.startsWith(
`/${RouteNamespace.PublicOrgs}/`,
);
}

constructor(host: NavigateController["host"]) {
this.host = host;
host.addController(this);
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/features/archived-items/file-uploader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ enum AbortReason {
* ></btrix-file-uploader>
* ```
*
* @TODO Refactor to use this.api.upload
*
* @event request-close
* @event upload-start
* @event uploaded
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/features/collections/collection-items-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ export class CollectionItemsDialog extends BtrixElement {
this.close();
this.dispatchEvent(new CustomEvent("btrix-collection-saved"));
this.notify.toast({
message: msg(str`Successfully saved archived item selection.`),
message: msg(str`Archived item selection updated.`),
variant: "success",
icon: "check2-circle",
id: "archived-item-selection-status",
Expand All @@ -683,7 +683,7 @@ export class CollectionItemsDialog extends BtrixElement {
this.notify.toast({
message: isApiError(e)
? e.message
: msg("Something unexpected went wrong"),
: msg("Sorry, couldn't save archived item selection at this time."),
variant: "danger",
icon: "exclamation-octagon",
id: "archived-item-selection-status",
Expand Down
Loading
Loading