import { localized, msg } from "@lit/localize"; import { Task } from "@lit/task"; import { html, type TemplateResult } from "lit"; import { customElement, property } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { when } from "lit/directives/when.js"; import { BtrixElement } from "@/classes/BtrixElement"; import { metadataColumn } from "@/layouts/collections/metadataColumn"; import { page } from "@/layouts/page"; import { RouteNamespace } from "@/routes"; import type { PublicCollection } from "@/types/collection"; import { formatRwpTimestamp } from "@/utils/replay"; import { richText } from "@/utils/rich-text"; enum Tab { Replay = "replay", About = "about", } @localized() @customElement("btrix-collection") export class Collection extends BtrixElement { @property({ type: String }) orgSlug?: string; @property({ type: String }) collectionSlug?: string; @property({ type: String }) tab: Tab | string = Tab.Replay; get canEditCollection() { return this.orgSlug === this.orgSlugState && this.appState.isCrawler; } private readonly tabLabels: Record< Tab, { icon: { name: string; library: string }; text: string } > = { [Tab.Replay]: { icon: { name: "replaywebpage", library: "app" }, text: msg("Browse Collection"), }, [Tab.About]: { icon: { name: "info-square-fill", library: "default" }, text: msg("About This Collection"), }, }; private readonly collection = new Task(this, { task: async ([orgSlug, collectionSlug]) => { if (!orgSlug || !collectionSlug) throw new Error("orgSlug and collection required"); const collection = await this.fetchCollection({ orgSlug, collectionSlug, }); if (collection.slug !== collectionSlug) { this.navigate.to( `/${RouteNamespace.PublicOrgs}/${this.orgSlug}/collections/${collection.slug}`, ); } if (!collection.crawlCount && (this.tab as unknown) === Tab.Replay) { this.tab = Tab.About; } return collection; }, args: () => [this.orgSlug, this.collectionSlug] as const, }); render() { return this.collection.render({ complete: this.renderComplete, error: this.renderError, }); } private readonly renderComplete = (collection: PublicCollection) => { const header: Parameters[0] = { breadcrumbs: collection.orgPublicProfile || collection.oid === this.orgId ? [ { href: `/${RouteNamespace.PublicOrgs}/${this.orgSlug}`, content: collection.orgName, }, ] : undefined, title: collection.name || "", actions: html` ${when( this.canEditCollection, () => html` ${msg("Go to Private Page")} `, )} `, }; if (collection.caption) { header.secondary = html`
${richText(collection.caption)}
`; } const panel = (tab: Tab, content: TemplateResult) => html`
${content}
`; return html` ${page( header, () => html` ${when(collection.crawlCount, () => panel(Tab.Replay, this.renderReplay(collection)), )} ${panel(Tab.About, this.renderAbout(collection))} `, )} `; }; private readonly renderError = (error?: unknown) => { console.log("error", error); return html`
`; }; private readonly renderTab = (tab: Tab) => { const isSelected = tab === (this.tab as Tab); return html` ${this.tabLabels[tab].text} `; }; private renderReplay(collection: PublicCollection) { const replaySource = new URL( `/api/orgs/${collection.oid}/collections/${collection.id}/public/replay.json`, window.location.href, ).href; return html`
`; } private renderAbout(collection: PublicCollection) { const metadata = metadataColumn(collection); if (collection.description) { return html`

${msg("Details")}

${metadata}
`; } return html`
${metadata}
`; } private async fetchCollection({ orgSlug, collectionSlug, }: { orgSlug: string; collectionSlug: string; }): Promise { const resp = await fetch( `/api/public/orgs/${orgSlug}/collections/${collectionSlug}`, { headers: { "Content-Type": "application/json" }, }, ); switch (resp.status) { case 200: return (await resp.json()) as PublicCollection; default: throw resp.status; } } }