UNPKG

nostr-web-components

Version:

collection of web components that provide quick access to basic nostr things

209 lines (186 loc) 12.3 kB
<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 /> &lt;-- </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>