a demonstration replicated social networking web app built with anproto
wiredove.net/
social
ed25519
protocols
1import { h } from 'h'
2import { apds } from 'apds'
3
4export const nameDiv = async () => {
5 const name = await apds.get('name')
6
7 const namer = h('input', {
8 placeholder: name || 'Name yourself'
9 })
10
11 const namerDiv = h('div', [
12 namer,
13 h('button', {onclick: async () => {
14 if (namer.value) {
15 namer.placeholder = namer.value
16 await apds.put('name', namer.value)
17 namer.value = ''
18 }
19 }}, ['Save'])
20 ])
21
22 return namerDiv
23}
24
25export const nameSpan = async () => {
26 const pubkey = await apds.pubkey()
27 const span = h('a', {href: '#' + pubkey, classList: 'avatarlink'}, [await apds.get('name') || pubkey.substring(0, 10)])
28 return span
29}
30
31export const imageSpan = async () => {
32 const avatarImg = await apds.visual(await apds.pubkey())
33
34 const existingImage = await apds.get('image')
35
36 if (existingImage) { avatarImg.src = await apds.get(existingImage)}
37
38 avatarImg.classList = 'avatar_small'
39
40 return avatarImg
41}
42
43export const avatarSpan = async () => {
44 const avatarImg = await apds.visual(await apds.pubkey())
45
46 const existingImage = await apds.get('image')
47
48 if (existingImage) { avatarImg.src = await apds.get(existingImage)}
49
50 avatarImg.classList = 'avatar'
51
52 avatarImg.onclick = () => {uploader.click()}
53
54 const uploader = h('input', { type: 'file', style: 'display: none;'})
55
56 uploader.addEventListener('change', (e) => {
57 const file = e.target.files[0]
58 const reader = new FileReader()
59
60 reader.onload = (e) => {
61 const canvas = document.createElement("canvas")
62 const ctx = canvas.getContext("2d")
63 const img = new Image()
64
65 img.onload = async () => {
66 const size = 256
67 if (img.width > size || img.height > size) {
68 const width = img.width
69 const height = img.height
70 let cropWidth
71 let cropHeight
72
73 if (width > height) {
74 cropWidth = size
75 cropHeight = cropWidth * (height / width)
76 } else {
77 cropHeight = size
78 cropWidth = cropHeight * (width / height)
79 }
80
81 canvas.width = cropWidth
82 canvas.height = cropHeight
83 ctx.drawImage(img, 0, 0, width, height, 0, 0, cropWidth, cropHeight)
84 const croppedImage = canvas.toDataURL()
85 avatarImg.src = croppedImage
86 const hash = await apds.make(croppedImage)
87 await apds.put('image', hash)
88 } else {
89 const croppedImage = canvas.toDataURL()
90 avatarImg.src = img.src
91 const hash = await apds.make(img.src)
92 await apds.put('image', hash)
93 }
94 }
95 img.src = e.target.result
96 }
97 reader.readAsDataURL(file)
98 })
99
100 const span = h('span', [
101 avatarImg,
102 uploader
103 ])
104
105 return span
106}
107
108export const profile = async () => {
109 const div = h('div')
110
111 div.appendChild(await avatarSpan())
112
113 div.appendChild(h('div', {classList: 'pubkey' }, [await apds.pubkey()]))
114
115 div.appendChild(await nameDiv())
116 return div
117}