ui: Public Collections UI Nitpicks (#2287)
- Removes share link from the dialogue footer - Removes stickied collection navigation, replaces with improved viewport-based scaling! - Adds a max-width for the collection description in the logged in view. - Moves the markdown editor buttons to below the editor - Controls are now In-line with how we handle dialogue options elsewhere, fixes a minor responsive design issue. - Minor copy changes --------- Co-authored-by: emma <hi@emma.cafe> Co-authored-by: sua yoo <sua@webrecorder.org>
This commit is contained in:
parent
d8655d3bc6
commit
56a634e593
@ -27,6 +27,14 @@ export class MarkdownEditor extends BtrixElement {
|
||||
--ink-block-padding: var(--sl-input-spacing-small);
|
||||
}
|
||||
|
||||
.ink-mde-textarea {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.ink-mde {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ink-mde {
|
||||
border: solid var(--sl-input-border-width) var(--sl-input-border-color);
|
||||
}
|
||||
@ -56,7 +64,8 @@ export class MarkdownEditor extends BtrixElement {
|
||||
}
|
||||
|
||||
.cm-line:only-child {
|
||||
min-height: 8em;
|
||||
height: 100%;
|
||||
min-height: 20em;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -111,7 +120,11 @@ export class MarkdownEditor extends BtrixElement {
|
||||
render() {
|
||||
const isInvalid = this.maxlength && this.value.length > this.maxlength;
|
||||
return html`
|
||||
<fieldset ?data-invalid=${isInvalid} ?data-user-invalid=${isInvalid}>
|
||||
<fieldset
|
||||
?data-invalid=${isInvalid}
|
||||
?data-user-invalid=${isInvalid}
|
||||
class="flex h-full flex-col"
|
||||
>
|
||||
${this.label && html`<label class="form-label">${this.label}</label>`}
|
||||
<textarea id="editor-textarea"></textarea>
|
||||
<div class="helpText flex items-baseline justify-between">
|
||||
|
@ -25,14 +25,14 @@ export class CollectionStartPageDialog extends BtrixElement {
|
||||
{ label: string; icon: NonNullable<SlIcon["name"]>; detail: string }
|
||||
> = {
|
||||
[HomeView.Pages]: {
|
||||
label: msg("Default"),
|
||||
label: msg("List of Pages"),
|
||||
icon: "list-ul",
|
||||
detail: `${msg("ReplayWeb.Page default view")}`,
|
||||
},
|
||||
[HomeView.URL]: {
|
||||
label: msg("Page"),
|
||||
icon: "file-earmark",
|
||||
detail: msg("Load a single page URL"),
|
||||
label: msg("Start Page"),
|
||||
icon: "file-earmark-richtext",
|
||||
detail: msg("Show a single URL snapshot"),
|
||||
},
|
||||
};
|
||||
|
||||
@ -188,7 +188,7 @@ export class CollectionStartPageDialog extends BtrixElement {
|
||||
<form @submit=${this.onSubmit}>
|
||||
<sl-select
|
||||
name="homeView"
|
||||
label=${msg("Select View")}
|
||||
label=${msg("Select Initial View")}
|
||||
value=${this.homeView}
|
||||
hoist
|
||||
?disabled=${!this.replayLoaded}
|
||||
|
@ -63,11 +63,11 @@ export class CollectionsGrid extends BtrixElement {
|
||||
href=${this.navigate.isPublicPage
|
||||
? `/${RouteNamespace.PublicOrgs}/${this.slug}/collections/${collection.id}`
|
||||
: `/${RouteNamespace.PrivateOrgs}/${this.slug}/collections/view/${collection.id}`}
|
||||
class="group block h-full rounded-lg transition-all hover:scale-[102%]"
|
||||
class="group block h-full rounded-lg"
|
||||
@click=${this.navigate.link}
|
||||
>
|
||||
<div
|
||||
class="relative mb-4 rounded-lg shadow-md shadow-stone-600/10 ring-1 ring-stone-600/10 transition-shadow group-hover:shadow-sm"
|
||||
class="relative mb-4 rounded-lg shadow-md shadow-stone-600/10 ring-1 ring-stone-600/10 transition group-hover:shadow-stone-800/20 group-hover:ring-stone-800/20"
|
||||
>
|
||||
<btrix-collection-thumbnail
|
||||
src=${ifDefined(
|
||||
|
@ -252,11 +252,7 @@ export class ShareCollection extends BtrixElement {
|
||||
|
||||
<sl-tab-panel name=${Tab.Link}>
|
||||
<div class="px-4 pb-4">
|
||||
${when(
|
||||
showSettings && this.collection,
|
||||
this.renderSettings,
|
||||
this.renderShareLink,
|
||||
)}
|
||||
${when(showSettings && this.collection, this.renderSettings)}
|
||||
</div>
|
||||
</sl-tab-panel>
|
||||
|
||||
@ -266,7 +262,6 @@ export class ShareCollection extends BtrixElement {
|
||||
</sl-tab-group>
|
||||
|
||||
<div slot="footer">
|
||||
${when(showSettings, this.renderShareLink)}
|
||||
<sl-button size="small" @click=${() => (this.showDialog = false)}>
|
||||
${msg("Done")}
|
||||
</sl-button>
|
||||
@ -287,6 +282,10 @@ export class ShareCollection extends BtrixElement {
|
||||
);
|
||||
}}
|
||||
></btrix-select-collection-access>
|
||||
${when(
|
||||
this.collection?.access != CollectionAccess.Private,
|
||||
this.renderShareLink,
|
||||
)}
|
||||
${when(
|
||||
this.org &&
|
||||
!this.org.enablePublicProfile &&
|
||||
@ -389,7 +388,7 @@ export class ShareCollection extends BtrixElement {
|
||||
>
|
||||
${isSelected
|
||||
? html`<sl-icon
|
||||
class="size-10 text-white drop-shadow-md"
|
||||
class="size-10 stroke-black/50 text-white drop-shadow-md [paint-order:stroke]"
|
||||
name="check-lg"
|
||||
></sl-icon>`
|
||||
: nothing}
|
||||
@ -410,7 +409,7 @@ export class ShareCollection extends BtrixElement {
|
||||
|
||||
private readonly renderShareLink = () => {
|
||||
return html`
|
||||
<div class="text-left">
|
||||
<div class="mt-4 text-left">
|
||||
<div class="form-label">${msg("Link to Share")}</div>
|
||||
<btrix-copy-field
|
||||
class="mb-3"
|
||||
|
@ -15,12 +15,12 @@ export const iconFor = cached(
|
||||
case "severe":
|
||||
return html`<sl-icon
|
||||
name="exclamation-triangle-fill"
|
||||
class=${clsx("text-red-600", baseClasses, classList)}
|
||||
class=${clsx("text-red-500", baseClasses, classList)}
|
||||
></sl-icon>`;
|
||||
case "moderate":
|
||||
return html`<sl-icon
|
||||
name="dash-square-fill"
|
||||
class=${clsx("text-yellow-600", baseClasses, classList)}
|
||||
class=${clsx("text-yellow-500", baseClasses, classList)}
|
||||
></sl-icon>`;
|
||||
case "good":
|
||||
return html`<sl-icon
|
||||
@ -37,7 +37,7 @@ export const iconFor = cached(
|
||||
case "rejected":
|
||||
return html`<sl-icon
|
||||
name="hand-thumbs-down-fill"
|
||||
class=${clsx("text-red-600", baseClasses, classList)}
|
||||
class=${clsx("text-red-500", baseClasses, classList)}
|
||||
></sl-icon>`;
|
||||
case "commentOnly":
|
||||
// Comment icons are rendered separately
|
||||
|
@ -29,9 +29,9 @@ export const textColorFromSeverity = cached((severity: Severity) => {
|
||||
case "good":
|
||||
return tw`text-green-600`;
|
||||
case "moderate":
|
||||
return tw`text-yellow-600`;
|
||||
return tw`text-yellow-500`;
|
||||
case "severe":
|
||||
return tw`text-red-600`;
|
||||
return tw`text-red-500`;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ export function page(
|
||||
></btrix-document-title>
|
||||
|
||||
<div
|
||||
class="mx-auto box-border flex min-h-full w-full max-w-screen-desktop flex-1 flex-col gap-3 p-3 lg:px-10"
|
||||
class="mx-auto box-border flex min-h-full w-full max-w-screen-desktop flex-1 flex-col gap-3 p-3 lg:px-10 lg:pb-10"
|
||||
>
|
||||
${header.breadcrumbs ? html` ${pageNav(header.breadcrumbs)} ` : nothing}
|
||||
${pageHeader(header)}
|
||||
|
@ -206,6 +206,7 @@ export class Collection extends BtrixElement {
|
||||
`;
|
||||
}
|
||||
|
||||
// TODO Consolidate with collection-detail.ts
|
||||
private renderAbout(collection: PublicCollection) {
|
||||
const dateRange = () => {
|
||||
if (!collection.dateEarliest || !collection.dateLatest) {
|
||||
@ -243,13 +244,13 @@ export class Collection extends BtrixElement {
|
||||
return html`
|
||||
<div class="flex flex-1 flex-col gap-10 lg:flex-row">
|
||||
<section
|
||||
class="flex-1 py-3 leading-relaxed lg:rounded-lg lg:border lg:p-6"
|
||||
class="w-full max-w-4xl py-3 leading-relaxed lg:rounded-lg lg:border lg:p-6"
|
||||
>
|
||||
<btrix-markdown-viewer
|
||||
value=${collection.description}
|
||||
></btrix-markdown-viewer>
|
||||
</section>
|
||||
<section class="min-w-60 lg:-mt-8">
|
||||
<section class="flex-1 lg:-mt-8">
|
||||
<btrix-section-heading>
|
||||
<h3>${msg("Metadata")}</h3>
|
||||
</btrix-section-heading>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { localized, msg, str } from "@lit/localize";
|
||||
import clsx from "clsx";
|
||||
import { html, nothing, type PropertyValues, type TemplateResult } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators.js";
|
||||
import { choose } from "lit/directives/choose.js";
|
||||
@ -24,6 +25,7 @@ import type { ArchivedItem, Crawl, Upload } from "@/types/crawler";
|
||||
import type { CrawlState } from "@/types/crawlState";
|
||||
import { pluralOf } from "@/utils/pluralize";
|
||||
import { formatRwpTimestamp } from "@/utils/replay";
|
||||
import { tw } from "@/utils/tailwind";
|
||||
|
||||
const ABORT_REASON_THROTTLE = "throttled";
|
||||
const INITIAL_ITEMS_PAGE_SIZE = 20;
|
||||
@ -115,7 +117,7 @@ export class CollectionDetail extends BtrixElement {
|
||||
if (this.descriptionEditor) {
|
||||
// FIXME Focus on editor ready instead of timeout
|
||||
window.setTimeout(() => {
|
||||
void this.descriptionEditor?.focus();
|
||||
this.descriptionEditor && void this.descriptionEditor.focus();
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
@ -148,9 +150,7 @@ export class CollectionDetail extends BtrixElement {
|
||||
<div class="mt-3 rounded-lg border px-4 py-2">
|
||||
${this.renderInfoBar()}
|
||||
</div>
|
||||
<div
|
||||
class="sticky top-0 z-50 -mx-3 mb-3 flex items-center justify-between bg-white px-3 pt-3 shadow-lg shadow-white"
|
||||
>
|
||||
<div class="flex items-center justify-between py-3">
|
||||
${this.renderTabs()}
|
||||
${when(this.isCrawler, () =>
|
||||
choose(this.collectionTab, [
|
||||
@ -174,40 +174,6 @@ export class CollectionDetail extends BtrixElement {
|
||||
</sl-tooltip>
|
||||
`,
|
||||
],
|
||||
[
|
||||
Tab.About,
|
||||
() =>
|
||||
this.isEditingDescription
|
||||
? html`
|
||||
<div>
|
||||
<sl-button
|
||||
variant="primary"
|
||||
size="small"
|
||||
@click=${() => void this.saveDescription()}
|
||||
?disabled=${!this.collection}
|
||||
>
|
||||
<sl-icon name="check-lg" slot="prefix"></sl-icon>
|
||||
${msg("Save")}
|
||||
</sl-button>
|
||||
<sl-button
|
||||
size="small"
|
||||
@click=${() => (this.isEditingDescription = false)}
|
||||
>
|
||||
${msg("Cancel")}
|
||||
</sl-button>
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<sl-button
|
||||
size="small"
|
||||
@click=${() => (this.isEditingDescription = true)}
|
||||
?disabled=${!this.collection}
|
||||
>
|
||||
<sl-icon name="pencil" slot="prefix"></sl-icon>
|
||||
${msg("Edit")}
|
||||
</sl-button>
|
||||
`,
|
||||
],
|
||||
[
|
||||
Tab.Items,
|
||||
() => html`
|
||||
@ -230,7 +196,7 @@ export class CollectionDetail extends BtrixElement {
|
||||
Tab.Items,
|
||||
() => guard([this.archivedItems], this.renderArchivedItems),
|
||||
],
|
||||
[Tab.About, () => this.renderDescription()],
|
||||
[Tab.About, () => this.renderAbout()],
|
||||
])}
|
||||
|
||||
<btrix-dialog
|
||||
@ -544,38 +510,133 @@ export class CollectionDetail extends BtrixElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private renderDescription() {
|
||||
// TODO Consolidate with collection.ts
|
||||
private renderAbout() {
|
||||
const dateRange = (collection: Collection) => {
|
||||
if (!collection.dateEarliest || !collection.dateLatest) {
|
||||
return msg("n/a");
|
||||
}
|
||||
const format: Intl.DateTimeFormatOptions = {
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
};
|
||||
const dateEarliest = this.localize.date(collection.dateEarliest, format);
|
||||
const dateLatest = this.localize.date(collection.dateLatest, format);
|
||||
|
||||
if (dateEarliest === dateLatest) return dateLatest;
|
||||
|
||||
return msg(str`${dateEarliest} to ${dateLatest}`, {
|
||||
desc: "Date range formatted to show full month name and year",
|
||||
});
|
||||
};
|
||||
const skeleton = html`<sl-skeleton class="w-24"></sl-skeleton>`;
|
||||
|
||||
const metadata = html`
|
||||
<btrix-desc-list>
|
||||
<btrix-desc-list-item label=${msg("Collection Period")}>
|
||||
<span class="font-sans"
|
||||
>${this.collection ? dateRange(this.collection) : skeleton}</span
|
||||
>
|
||||
</btrix-desc-list-item>
|
||||
</btrix-desc-list>
|
||||
`;
|
||||
|
||||
return html`
|
||||
<section>
|
||||
${when(
|
||||
this.collection,
|
||||
(collection) =>
|
||||
this.isEditingDescription
|
||||
? html`
|
||||
<btrix-markdown-editor
|
||||
initialValue=${collection.description || ""}
|
||||
placeholder=${msg("Tell viewers about this collection")}
|
||||
maxlength=${4000}
|
||||
></btrix-markdown-editor>
|
||||
`
|
||||
: html`
|
||||
<div class="rounded-lg border p-4 leading-relaxed">
|
||||
${collection.description
|
||||
? html`
|
||||
<btrix-markdown-viewer
|
||||
value=${collection.description}
|
||||
></btrix-markdown-viewer>
|
||||
`
|
||||
: html`
|
||||
<p class="py-10 text-center text-neutral-500">
|
||||
${msg("No description provided.")}
|
||||
</p>
|
||||
`}
|
||||
</div>
|
||||
`,
|
||||
this.renderSpinner,
|
||||
)}
|
||||
</section>
|
||||
<div class="flex flex-1 flex-col gap-10 lg:flex-row">
|
||||
<section class="flex w-full max-w-4xl flex-col leading-relaxed">
|
||||
<header class="mb-3 flex min-h-8 items-end justify-between">
|
||||
<h2 class="text-base font-semibold leading-none">
|
||||
${msg("Description")}
|
||||
</h2>
|
||||
${when(
|
||||
this.collection?.description && !this.isEditingDescription,
|
||||
() => html`
|
||||
<sl-button
|
||||
size="small"
|
||||
@click=${() => (this.isEditingDescription = true)}
|
||||
>
|
||||
<sl-icon name="pencil" slot="prefix"></sl-icon>
|
||||
${msg("Edit Description")}
|
||||
</sl-button>
|
||||
`,
|
||||
)}
|
||||
</header>
|
||||
${when(
|
||||
this.collection,
|
||||
(collection) =>
|
||||
this.isEditingDescription
|
||||
? this.renderDescriptionForm()
|
||||
: html`
|
||||
<div
|
||||
class=${clsx(
|
||||
tw`flex-1 rounded-lg border p-3 lg:p-6`,
|
||||
!collection.description &&
|
||||
tw`flex flex-col items-center justify-center`,
|
||||
)}
|
||||
>
|
||||
${collection.description
|
||||
? html`
|
||||
<btrix-markdown-viewer
|
||||
value=${collection.description}
|
||||
></btrix-markdown-viewer>
|
||||
`
|
||||
: html`
|
||||
<div class="text-center text-neutral-500">
|
||||
<p class="mb-3">
|
||||
${msg("No description provided.")}
|
||||
</p>
|
||||
<sl-button
|
||||
size="small"
|
||||
@click=${() =>
|
||||
(this.isEditingDescription = true)}
|
||||
?disabled=${!this.collection}
|
||||
>
|
||||
<sl-icon name="pencil" slot="prefix"></sl-icon>
|
||||
${msg("Add Description")}
|
||||
</sl-button>
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
`,
|
||||
this.renderSpinner,
|
||||
)}
|
||||
</section>
|
||||
<section class="flex-1">
|
||||
<btrix-section-heading>
|
||||
<h2>${msg("Metadata")}</h2>
|
||||
</btrix-section-heading>
|
||||
<div class="mt-5">${metadata}</div>
|
||||
</section>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderDescriptionForm() {
|
||||
if (!this.collection) return;
|
||||
|
||||
return html`
|
||||
<btrix-markdown-editor
|
||||
class="flex-1"
|
||||
initialValue=${this.collection.description || ""}
|
||||
placeholder=${msg("Tell viewers about this collection")}
|
||||
maxlength=${4000}
|
||||
></btrix-markdown-editor>
|
||||
<div class="flex-column mt-4 flex justify-between border-t pt-4">
|
||||
<sl-button
|
||||
size="small"
|
||||
@click=${() => (this.isEditingDescription = false)}
|
||||
>
|
||||
${msg("Cancel")}
|
||||
</sl-button>
|
||||
<sl-button
|
||||
variant="primary"
|
||||
size="small"
|
||||
@click=${() => void this.saveDescription()}
|
||||
?disabled=${!this.collection}
|
||||
>
|
||||
${msg("Update Description")}
|
||||
</sl-button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -708,32 +769,31 @@ export class CollectionDetail extends BtrixElement {
|
||||
const headers = this.authState?.headers;
|
||||
const config = JSON.stringify({ headers });
|
||||
|
||||
return html`<section>
|
||||
<div class="aspect-4/3 overflow-hidden rounded-lg border">
|
||||
<replay-web-page
|
||||
source=${replaySource}
|
||||
config="${config}"
|
||||
coll=${this.collectionId}
|
||||
url=${this.collection.homeUrl ||
|
||||
/* must be empty string to reset the attribute: */ ""}
|
||||
ts=${formatRwpTimestamp(this.collection.homeUrlTs) ||
|
||||
/* must be empty string to reset the attribute: */ ""}
|
||||
replayBase="/replay/"
|
||||
noSandbox="true"
|
||||
noCache="true"
|
||||
@rwp-url-change=${() => {
|
||||
if (!this.isRwpLoaded) {
|
||||
this.isRwpLoaded = true;
|
||||
}
|
||||
}}
|
||||
></replay-web-page>
|
||||
</div>
|
||||
return html` <section class="overflow-hidden rounded-lg border">
|
||||
<replay-web-page
|
||||
class="h-[calc(100vh-6.5rem)]"
|
||||
source=${replaySource}
|
||||
config="${config}"
|
||||
coll=${this.collectionId}
|
||||
url=${this.collection.homeUrl ||
|
||||
/* must be empty string to reset the attribute: */ ""}
|
||||
ts=${formatRwpTimestamp(this.collection.homeUrlTs) ||
|
||||
/* must be empty string to reset the attribute: */ ""}
|
||||
replayBase="/replay/"
|
||||
noSandbox="true"
|
||||
noCache="true"
|
||||
@rwp-url-change=${() => {
|
||||
if (!this.isRwpLoaded) {
|
||||
this.isRwpLoaded = true;
|
||||
}
|
||||
}}
|
||||
></replay-web-page>
|
||||
</section>`;
|
||||
};
|
||||
|
||||
private readonly renderSpinner = () => html`
|
||||
<div
|
||||
class="flex items-center justify-center rounded-lg border py-24 text-3xl"
|
||||
class="flex min-h-full items-center justify-center rounded-lg border py-24 text-3xl"
|
||||
>
|
||||
<sl-spinner></sl-spinner>
|
||||
</div>
|
||||
|
@ -602,6 +602,7 @@ export class Org extends BtrixElement {
|
||||
|
||||
if (params.collectionId) {
|
||||
return html`<btrix-collection-detail
|
||||
class="flex min-h-screen flex-1 flex-col pb-7"
|
||||
collectionId=${params.collectionId}
|
||||
collectionTab=${ifDefined(
|
||||
params.collectionTab as CollectionTab | undefined,
|
||||
|
Loading…
Reference in New Issue
Block a user