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