import { localizeDate } from "./dates.ts"; import Article from "./models/article.ts"; import Profile from "./models/profile.ts"; interface HtmlLayoutOptions { title: string; body: string; metaHtml?: string; } function htmlLayout({ title, body, metaHtml }: HtmlLayoutOptions): string { return ` ${title} ${metaHtml || ""} ${body} `; } export function errorPageHtml(statusCode: number, title: string): string { const body = `

${statusCode} - ${title}

`; return htmlLayout({ title, body }); } export async function articleHtml( article: Article, profile: Profile, ): Promise { const publishedAtFormatted = localizeDate(article.publishedAt); const pageTitle = article.isDraft ? `Draft: ${article.title}` : article.title; let draftLabel = ``; if (article.isDraft) { draftLabel = `

Draft version

`; } const body = `
${draftLabel}

${titleHtml(article.title)}

User Avatar
${profile.name} ${publishedAtFormatted}
${await article.buildContentHtml()}
${openWithNostrAppHtml(article.naddr)}
`; let metaHtml = articleMetaHtml(article, profile); metaHtml += feedLinksHtml(profile); return htmlLayout({ title: pageTitle, body, metaHtml }); } function titleHtml(title: string) { return title.replace(/`([^`]+)`/g, "$1"); } function articleListItemHtml(article: Article): string { const formattedDate = localizeDate(article.publishedAt); return `

${titleHtml(article.title)}

${formattedDate}

`; } export function articleListHtml(articles: Article[]): string { if (articles.length === 0) return ""; let html = ""; for (const article of articles) { html += articleListItemHtml(article); } return `

Articles

${html}
`; } function userAddressHtml(profile: Profile) { let html = ""; if (profile.lud16) { html += `
Lightning address
${profile.lud16}
\n`; } return html; } function nip05VerifiedHtml(verified: boolean): string { if (verified) { return ` `; } else { return ` `; } } export async function profilePageHtml( profile: Profile, articles: Article[], ): Promise { const title = `${profile.name} on Nostr`; let nip05Html = ""; if (profile.nip05) { const nip05Verified = await profile.verifyNip05(); nip05Html += `

${profile.nip05}${ nip05VerifiedHtml(nip05Verified) }

\n`; } const body = `
User Avatar

${profile.name}

${nip05Html}

${profile.about}

Details
Public key
${profile.npub}
${userAddressHtml(profile)}
${articleListHtml(articles)}
`; let metaHtml = profileMetaHtml(profile); metaHtml += feedLinksHtml(profile); return htmlLayout({ title, body, metaHtml }); } function openWithNostrAppHtml(bech32Id: string): string { let appLinksHtml = ""; const appLinks = [ { title: "Habla", href: `https://habla.news/a/${bech32Id}` }, { title: "noStrudel", href: `https://nostrudel.ninja/#/articles/${bech32Id}`, }, { title: "Coracle", href: `https://coracle.social/${bech32Id}` }, { title: "YakiHonne", href: `https://yakihonne.com/article/${bech32Id}` }, ]; for (const link of appLinks) { appLinksHtml += `${link.title}`; } return ` `; } function feedLinksHtml(profile: Profile) { return ``; } function profileMetaHtml(profile: Profile) { return ` `; } function articleMetaHtml(article: Article, profile: Profile) { const imageUrl = article.image || profile.ogImageUrl; return ` `; }