nostr-web-components
Version:
collection of web components that provide quick access to basic nostr things
162 lines (161 loc) • 4.93 kB
JavaScript
import { verifyEvent } from "@nostr/tools/pure";
import { decodeNostrURI, neventEncode, npubEncode } from "@nostr/tools/nip19";
import { normalizeURL } from "@nostr/tools/utils";
import * as nip10 from "@nostr/tools/nip10";
import { fetchNostrUser, getOutboxRelaysFor, pool } from "./nostr.js";
import { debounce, nostrLink, shorten, splitComma } from "./utils.js";
import { renderText } from "./text.js";
class NostrNote extends HTMLElement {
static observedAttributes = ["ref", "event", "relays", "template"];
root;
constructor() {
super();
this.attachShadow({ mode: "open" });
const { shadowRoot } = this;
this.root = document.createElement("div");
shadowRoot.appendChild(this.root);
}
connectedCallback() {
setTimeout(() => {
let template = this.getAttribute("template") ? document.getElementById(this.getAttribute("template")) : null;
if (template) {
this.root.appendChild(template.content.cloneNode(true));
} else {
this.root.innerHTML = `
<div part="container">
<header part="header">
<a part="author-link">
<span part="author-name"></span>
<span part="author-npub-short"></span>
</a>
<a part="parent-link" style="display: none">
<span part="parent">parent</span>
</a>
<a part="link">
<time part="date"></time>
</a>
</header>
<div part="content"></div>
</div>
`;
}
this.set();
}, 1);
}
*queryPart(name) {
let slotted = this.querySelectorAll(`[part="${name}"]`);
for (let i = 0; i < slotted.length; i++) {
yield slotted[i];
}
let templated = this.root.querySelectorAll(`[part="${name}"]`);
for (let i = 0; i < templated.length; i++) {
yield templated[i];
}
}
attributeChangedCallback() {
this.set();
}
set = debounce(async () => {
var evt = null;
let eventj = this.getAttribute("event");
if (eventj) {
evt = JSON.parse(eventj);
if (evt) {
if (!verifyEvent(evt)) {
return;
}
}
}
if (!evt) {
let ref = this.getAttribute("ref");
if (ref) {
let { type, data } = decodeNostrURI(ref);
if (type !== "nevent") {
return;
}
let d = data;
let relays = (d.relays || []).concat(splitComma(this.getAttribute("relays")).map(normalizeURL));
let filter = { ids: [d.id] };
if (d.author && relays.length === 0)
relays = await getOutboxRelaysFor(d.author);
evt = await pool.get(relays, filter);
if (!evt && d.author) {
relays = await getOutboxRelaysFor(d.author);
evt = await pool.get(relays, filter);
}
}
}
if (!evt) {
return;
}
let npub = npubEncode(evt.pubkey);
for (let el of this.queryPart("author-link")) {
el.href = nostrLink(npub);
el.target = "_blank";
}
for (let el of this.queryPart("author-npub")) {
el.textContent = npub;
}
var nu = null;
for (let el of this.queryPart("author-name")) {
if (!nu) {
nu = await fetchNostrUser(evt.pubkey, []);
}
el.textContent = nu.shortName;
}
for (let el of this.queryPart("author-npub-short")) {
el.textContent = shorten(npub);
}
let thread = null;
for (let el of this.queryPart("parent-link")) {
if (!thread)
thread = nip10.parse(evt);
if (thread.reply) {
el.href = nostrLink(neventEncode(thread.reply));
el.target = "_blank";
el.style.display = "";
} else {
el.remove();
}
}
for (let el of this.queryPart("root-link")) {
if (!thread)
thread = nip10.parse(evt);
if (thread.root) {
el.href = nostrLink(neventEncode(thread.root));
el.target = "_blank";
} else {
el.remove();
}
}
for (let el of this.queryPart("link")) {
el.href = nostrLink(
neventEncode({
id: evt.id,
relays: Array.from(pool.seenOn.get(evt.id) || []).slice(0, 3).map((r) => r.url),
author: evt.pubkey
})
);
el.target = "_blank";
}
for (let el of this.queryPart("date")) {
let date = new Date(evt.created_at * 1e3);
el.textContent = date.toLocaleString();
if (el.tagName === "TIME") {
el.setAttribute("time", date.toISOString().substring(0, 23));
}
}
let contentWrapper = null;
for (let el of this.queryPart("content")) {
if (!contentWrapper) {
contentWrapper = document.createElement("div");
el.appendChild(contentWrapper);
}
renderText(contentWrapper, evt.content);
}
}, 200);
}
window.customElements.define("nostr-note", NostrNote);
export {
NostrNote as default
};