a demonstration replicated social networking web app built with anproto wiredove.net/
social ed25519 protocols
at main 117 lines 3.0 kB view raw
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}