nostr-web-components
Version:
collection of web components that provide quick access to basic nostr things
209 lines (186 loc) • 12.3 kB
HTML
<link href="demo-bundle.css" rel="stylesheet" />
<h1 class="text-2xl my-4 text-center">nostr web components demo</h1>
<div class="columns-1 md:columns-2 lg:columns-3 gap-4 p-4">
<section class="bg-blue-100 px-4 py-4 mb-4 break-inside-avoid inline-block w-full">
<script src="dist/nostr-name.js"></script>
<main>
hello,
<nostr-name
class="text-2xl text-orange-500"
pubkey="nprofile1qqsgfhhxuemwtwm8kjk5uppv7uxtmp5pz4wm2dv59lxx5pfnsk98ysqpz3mhxue69uhkummnw3ezummcw3ezuer9wcq3camnwvaz7tmwdaehgu3wvf5hgcm0d9hx2u3wwdhkx6tpds37vfju"
></nostr-name>
</main>
</section>
<section class="bg-emerald-100 px-4 py-4 mb-4 break-inside-avoid inline-block w-full">
<script src="dist/nostr-picture.js"></script>
<main>
<div class="flex gap-2 items-center h-16">
<nostr-picture
pubkey="nprofile1qqsgfhhxuemwtwm8kjk5uppv7uxtmp5pz4wm2dv59lxx5pfnsk98ysqpz3mhxue69uhkummnw3ezummcw3ezuer9wcq3camnwvaz7tmwdaehgu3wvf5hgcm0d9hx2u3wwdhkx6tpds37vfju"
class="part-[img]:h-full part-[img]:border-solid part-[img]:border-8 part-[img]:border-rose-600"
></nostr-picture>
<div class="font-mono">
there should be a picture of snowden here<br />
<--
</div>
</div>
</main>
</section>
<section class="bg-pink-100 px-4 py-4 mb-4 break-inside-avoid inline-block w-full">
<script src="dist/nostr-follow.js"></script>
<main>
<nostr-follow
pubkey="npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6"
class="part-[button]:bg-white part-[button]:rounded part-[button]:border-0 part-[button]:drop-shadow part-[button]:p-2 part-[button]:hover:bg-gray-50 part-[button]:cursor-pointer part-[button]:active:shadow-inner part-[button]:hover:bg-gray-100 part-[button]:disabled:cursor-default"
>
click here to follow me on nostr
<span class="text-sky-500" slot="loading">...</span>
<span class="text-green-500" slot="success">It worked.</span>
<span class="text-red-500" slot="failure">It went bad: <span part="error-message"></span></span>
</nostr-follow>
</main>
</section>
<section class="bg-lime-100 px-4 py-4 mb-4 break-inside-avoid inline-block w-full">
<script src="dist/nostr-text.js"></script>
<main>
<nostr-text
class="block p-4 border-4 border-white part-[video]:block part-[audio]:block part-[image]:block part-[image]:rounded part-[reference]:font-semibold part-[reference]:text-black part-[url]:text-blue-600 part-[relay]:text-orange-600"
content="this video got 96 views when it was published on January 11, 2013 at https://youtube.com/watch?v=rr7xo8LdGJs:
https://cdn.nostrcheck.me/1fc19ef347a19e3675231bad2d25d43b878886838386adf128175b778b45ac82.mp4"
></nostr-text>
</main>
</section>
<section class="bg-yellow-200 px-4 py-4 mb-4 break-inside-avoid inline-block w-full">
<script src="dist/nostr-user-search.js"></script>
<main>
<nostr-user-search
class="part-[input]:text-xl part-[input]:px-1 part-[input]:py-2 part-[item]:text-xl part-[item]:px-1 part-[item]:py-2 part-[picture]:w-16 part-[picture]:h-16 part-[picture]:border part-[name]:max-w-64"
></nostr-user-search>
<p>you have selected <a id="result" class="font-bold text-rose-500" target="_blank"></a></p>
<script>
document.querySelector('nostr-user-search').addEventListener('selected', function (ev) {
console.log('selected', ev.detail)
document.querySelector('#result').textContent = ev.detail.metadata.name || ev.detail.npub
document.querySelector('#result').href = 'https://nostrrr.com/p/' + ev.detail.npub
})
</script>
</main>
</section>
<section class="bg-purple-100 px-4 py-4 mb-4 break-inside-avoid inline-block w-full">
<script src="dist/nostr-rsvp.js"></script>
<main>
<nostr-rsvp
ref="naddr1qqjrys6px56yydpk94prxdes956yxw2r95u5g33s94pnxwpjgg6ygv69xqcrvqgdwaehxw309ahx7uewd3hkcq3q0hj9rg5gds5x2gk0z0s2jlqnq04jg7g30aj2t5pqzdaaztfactgsxpqqqp7tx45kyl4"
class="part-[container]:bg-white part-[container]:p-4 part-[container]:pt-2 part-[container]:rounded-lg part-[title]:text-xl part-[title]:font-bold part-[title]:text-center part-[time]:text-gray-600 part-[description]:mt-4 part-[buttons]:mt-4 part-[buttons]:flex part-[buttons]:justify-center part-[buttons]:gap-2 part-[button]:cursor-pointer part-[button]:text-white part-[button]:px-4 part-[button]:py-2 part-[button]:rounded part-[accepted]:bg-green-500 part-[tentative]:bg-yellow-500 part-[declined]:bg-red-500"
>
<span slot="declined">Decline</span>
<span slot="rsvp-sent">Sent!</span>
</nostr-rsvp>
</main>
</section>
<section class="bg-orange-100 px-4 py-4 mb-4 break-inside-avoid inline-block w-full">
<script src="dist/nostr-livestream.js"></script>
<main>
<nostr-livestream
ref="naddr1qqjr2vehvyenvdtr94nrzetr956rgctr94skvvfs95eryep3x3snwve389nxyqgwwaehxw309ahx7uewd3hkctcpz4mhxue69uhhyetvv9ujuerpd46hxtnfduhszxthwden5te0wfjkccte9eekummjwsh8xmmrd9skctcpzamhxue69uhhyetvv9ujumn0wd68ytnzv9hxgtcpz9mhxue69uhkummnw3ezumrpdejz7qg7waehxw309ahx7um5wgkhqatz9emk2mrvdaexgetj9ehx2ap0qyghwumn8ghj7mn0wd68ytnhd9hx2tcpz4mhxue69uhhyetvv9ujumn0wd68ytnzvuhsz9thwden5te0dehhxarj9ehhsarj9ejx2a30qgsv73dxhgfk8tt76gf6q788zrfyz9dwwgwfk3aar6l5gk82a76v9fgrqsqqqan8tp7le0"
class="part-[error]:text-red-500 part-[error]:font-bold part-[header]:flex part-[title]:ml-2 part-[status]:mx-4 part-[status]:p-2 part-[status]:bg-yellow-400 part-[stats]:flex part-[stats]:justify-end"
>
<span slot="error-pointer">the code is wrong!</span>
<span slot="error-fetch">couldn't find the event anywhere!</span>
<span slot="error-invalid">this is not a livestream!</span>
<span slot="current">this many people here: <span class="value"></span></span>
<span slot="stats">
<div class="flex items-center">
<span class="text-xl" part="current-value"></span>
<span class="text-xs">viewers</span>
</div>
</span>
</nostr-livestream>
</main>
</section>
<section class="bg-sky-100 px-4 py-4 mb-4 break-inside-avoid inline-block w-full">
<script src="dist/nostr-note.js"></script>
<main>
<nostr-note
event='{"id":"b9fead6eef87d8400cbc1a5621600b360438affb9760a6a043cc0bddea21dab6","pubkey":"82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","created_at":1676161639,"kind":1,"tags":[],"content": "this is going to work","sig":"76d19889a803236165a290fa8f3cf5365af8977ee1e002afcfd37063d1355fc755d0293d27ba0ec1c2468acfaf95b7e950e57df275bb32d7a4a3136f8862d2b7"}'
class="part-[container]:mb-4 part-[container]:break-inside-avoid part-[container]:bg-white part-[container]:rounded-lg part-[container]:shadow-md part-[container]:p-4 part-[header]:flex part-[header]:w-full part-[header]:items-center part-[header]:justify-between part-[header]:mb-3 part-[author-link]:no-underline part-[author-link]:text-black part-[author-name]:font-semibold part-[author-npub-short]:hidden part-[parent-link]:text-sm part-[parent-link]:text-gray-800 part-[link]:text-xs part-[link]:text-gray-500 part-[content]:text-gray-700 part-[content]:mb-3 part-[video]:block part-[audio]:block part-[image]:block part-[image]:rounded part-[reference]:font-semibold part-[reference]:text-black part-[url]:text-blue-600 part-[relay]:text-orange-600"
></nostr-note>
<nostr-note
ref="nevent1qqsp2fasgxsh4d39htpvu23sanvsd2d3xavxkrvktulzqwczk72xs4qpz9mhxue69uhkummnw3ezuamfdejj7qr6mw8"
class="part-[container]:mb-4 part-[container]:break-inside-avoid part-[container]:bg-white part-[container]:rounded-lg part-[container]:shadow-md part-[container]:p-4 part-[header]:flex part-[header]:w-full part-[header]:items-center part-[header]:justify-between part-[header]:mb-3 part-[author-link]:no-underline part-[author-link]:text-black part-[author-name]:font-semibold part-[author-npub-short]:hidden part-[parent-link]:text-sm part-[parent-link]:text-gray-800 part-[link]:text-xs part-[link]:text-gray-500 part-[content]:text-gray-700 part-[content]:mb-3 part-[video]:block part-[audio]:block part-[image]:block part-[image]:rounded part-[reference]:font-semibold part-[reference]:text-black part-[url]:text-blue-600 part-[relay]:text-orange-600"
></nostr-note>
<nostr-note
ref="nevent1qqsvmjrqmlfmf0csk8uy43jc52jpsktqyqehtgh326clh0avj25vsscppemhxue69uhkummn9ekx7mp0qyg8wumn8ghj7mn0wd68ytnddakj7qg4waehxw309ahx7um5wghx77r5wghxgetk9uug2ajj"
class="part-[container]:mb-4 part-[container]:break-inside-avoid part-[container]:bg-white part-[container]:rounded-lg part-[container]:shadow-md part-[container]:p-4 part-[header]:flex part-[header]:w-full part-[header]:items-center part-[header]:justify-between part-[header]:mb-3 part-[author-link]:no-underline part-[author-link]:text-black part-[author-name]:font-semibold part-[author-npub-short]:hidden part-[parent-link]:text-sm part-[parent-link]:text-gray-800 part-[link]:text-xs part-[link]:text-gray-500 part-[content]:text-gray-700 part-[content]:mb-3 part-[video]:block part-[audio]:block part-[image]:block part-[image]:rounded part-[reference]:font-semibold part-[reference]:text-black part-[url]:text-blue-600 part-[relay]:text-orange-600"
></nostr-note>
</main>
</section>
<section class="bg-red-50 px-4 py-4 mb-4 break-inside-avoid inline-block w-full">
<script src="dist/nostr-event-json.js"></script>
<main>
<nostr-event-json
ref="nevent1qvzqqqqy2upzpepndn2jthmelfxn4umylktqp493ph8yy9d2fse76al2ppprgjcsqywhwumn8ghj7mn0wd68ytnzd96xxmmfdejhytnnda3kjctv9uq3qamnwvaz7tmwdaehgu3wd4hk6tcqypn3wpnyd8kt6nxjm92lnkwczq6a45rul8eh4ancag9lh60zewpu6ug6xcc"
class="part-[pre]:rounded-lg part-[pre]:bg-sky-800 part-[pre]:transition-colors hover:part-[pre]:bg-sky-600 part-[pre]:p-4 part-[pre]:text-white part-[key]:text-emerald-200 part-[key]:font-bold part-[kind]:text-xl part-[content]:decoration-italic part-[id]:text-sm part-[pubkey]:text-sm part-[sig]:text-sm"
></nostr-event-json>
</main>
</section>
</div>
<script>
let sections = document.querySelectorAll('section')
// for each example display a title and the HTML code that generated it
for (let i = 0; i < sections.length; i++) {
let section = sections[i]
// the example code
let main = section.querySelector('main')
main.classList.add('mt-4')
let codeString = main.innerHTML
// the <nostr-whatever> component name
let componentName = codeString.match(/nostr-([\w-])+/)[0]
// remove excessive indentation
let lines = codeString.split('\n')
let smallestIndent = 900
for (let i = 0; i < lines.length; i++) {
let len = lines[i].match(/^ */)[0].length
if (len > 0 && len < smallestIndent) smallestIndent = len
}
for (let i = 0; i < lines.length; i++) {
lines[i] = lines[i].substring(smallestIndent)
}
// prepend with <script> tag pointing to a CDN
lines.splice(
0,
0,
' <script src="https://cdn.jsdelivr.net/npm/nostr-web-components/dist/' +
componentName +
'.js">< /script>'.replace('< /', '</'),
)
codeString = lines.join('\n')
// remove style=... that were added to the components by their own code
codeString = codeString.replace(/ style="[^"]+"/g, '')
// add title
let h1 = document.createElement('h1')
h1.classList.add('font-mono')
h1.classList.add('text-3xl')
h1.classList.add('text-center')
h1.classList.add('mt-4')
h1.textContent = `<${componentName}>`
section.insertBefore(h1, main)
// add HTML
let pre = document.createElement('pre')
pre.classList.add('text-sm')
pre.classList.add('text-wrap')
pre.classList.add('break-all')
pre.textContent = codeString
section.insertBefore(pre, main)
// if the HTML text is edited we update the actual HTML
pre.contentEditable = 'plaintext-only'
let changed = false
pre.oninput = () => {
changed = true
}
pre.onblur = () => {
if (changed) main.innerHTML = pre.textContent
changed = false
}
}
</script>