import {renderCachedEmbed} from './embed-cache.ts' export type ProfileView = { avatar?: string banner?: string description?: string did: string displayName?: string handle: string } // based on https://github.com/Janpot/escape-html-template-tag/blob/master/src/index.ts const ENTITIES: { [key: string]: string } = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/', '`': '`', '=': '=', } const ENT_REGEX = new RegExp(Object.keys(ENTITIES).join('|'), 'g') function escapehtml(unsafe: Sub): string { if (Array.isArray(unsafe)) { return unsafe.map(escapehtml).join('') } if (unsafe instanceof HtmlSafeString) { return unsafe.toString() } return String(unsafe).replace(ENT_REGEX, char => ENTITIES[char]) } type Sub = HtmlSafeString | string | (HtmlSafeString | string)[] export class HtmlSafeString { private _parts: readonly string[] private _subs: readonly Sub[] constructor(parts: readonly string[], subs: readonly Sub[]) { this._parts = parts this._subs = subs } toString(): string { let result = this._parts[0] for (let i = 1; i < this._parts.length; i++) { result += escapehtml(this._subs[i - 1]) + this._parts[i] } return result } } export function html(parts: TemplateStringsArray, ...subs: Sub[]) { return new HtmlSafeString(parts, subs) } export const renderHandleString = (profile: ProfileView) => profile.displayName ? `${profile.displayName} (@${profile.handle})` : `@${profile.handle}` class HeadHandler { profile: ProfileView url: string constructor(profile: ProfileView, url: string) { this.profile = profile this.url = url } async element(element) { const view = this.profile const description = view.description ? html` ` : '' const img = view.banner ? html` ` : view.avatar ? html`` : '' element.append( html` ${description} ${img} `, {html: true}, ) } } class TitleHandler { profile: ProfileView constructor(profile: ProfileView) { this.profile = profile } async element(element) { element.setInnerContent(renderHandleString(this.profile)) } } class NoscriptHandler { profile: ProfileView constructor(profile: ProfileView) { this.profile = profile } async element(element) { const view = this.profile element.append( html`
${view.displayName ?? ''}
${view.handle}
${view.did}
${view.description ?? ''}