a demonstration replicated social networking web app built with anproto
wiredove.net/
social
ed25519
protocols
1import { apds } from 'apds'
2import { route } from './route.js'
3import { connect } from './connect.js'
4import { navbar } from './navbar.js'
5import { send } from './send.js'
6import { startSync } from './sync.js'
7
8const registerServiceWorker = () => {
9 if (!('serviceWorker' in navigator)) { return }
10 window.addEventListener('load', () => {
11 navigator.serviceWorker.register('/sw.js').catch((err) => {
12 console.warn('service worker registration failed', err)
13 })
14 }, { once: true })
15}
16
17const createImagePopover = () => {
18 const popover = document.createElement('div')
19 popover.id = 'image-popover'
20 popover.className = 'image-popover'
21 popover.setAttribute('role', 'dialog')
22 popover.setAttribute('aria-modal', 'true')
23 popover.setAttribute('aria-hidden', 'true')
24
25 const closeButton = document.createElement('button')
26 closeButton.type = 'button'
27 closeButton.className = 'image-popover-close material-symbols-outlined'
28 closeButton.setAttribute('aria-label', 'Close image')
29 closeButton.textContent = 'Cancel'
30
31 const frame = document.createElement('div')
32 frame.className = 'image-popover-frame'
33
34 const image = document.createElement('img')
35 image.className = 'image-popover-image'
36 image.alt = 'Full size image'
37
38 frame.appendChild(closeButton)
39 frame.appendChild(image)
40 popover.appendChild(frame)
41
42 const closePopover = () => {
43 popover.classList.remove('open')
44 popover.setAttribute('aria-hidden', 'true')
45 image.src = ''
46 }
47
48 const openFromImage = async (target) => {
49 if (!target) return
50 const hash = target.dataset.hash
51 let fullSrc = target.src
52 if ((!fullSrc || fullSrc === window.location.href) && hash) {
53 const data = await apds.get(hash)
54 if (data) {
55 fullSrc = data
56 } else {
57 await send(hash)
58 return
59 }
60 }
61 if (!fullSrc) return
62 image.src = fullSrc
63 popover.classList.add('open')
64 popover.setAttribute('aria-hidden', 'false')
65 }
66
67 popover.addEventListener('click', (event) => {
68 if (event.target === popover) {
69 closePopover()
70 }
71 })
72 closeButton.addEventListener('click', (event) => {
73 event.preventDefault()
74 closePopover()
75 })
76
77 document.addEventListener('keydown', (event) => {
78 if (event.key === 'Escape' && popover.classList.contains('open')) {
79 closePopover()
80 }
81 })
82
83 document.body.addEventListener('click', (event) => {
84 const target = event.target.closest('img.post-image')
85 if (!target) return
86 event.preventDefault()
87 openFromImage(target)
88 })
89
90 document.body.addEventListener('keydown', (event) => {
91 const target = event.target
92 if (!target || !target.matches('img.post-image')) return
93 if (event.key === 'Enter' || event.key === ' ') {
94 event.preventDefault()
95 openFromImage(target)
96 }
97 })
98
99 return popover
100}
101
102await apds.start('wiredovedbversion1')
103document.body.appendChild(await navbar())
104document.body.appendChild(createImagePopover())
105const connectPromise = connect()
106await route()
107await connectPromise
108await startSync(send)
109registerServiceWorker()
110
111if (!window.location.hash) { window.location = '#' }