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)}
${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 `
`;
}
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 = `
${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 `
`;
}