git ssb

16+

Dominic / patchbay



Tree: 4441fae4d0d265267896434addfea2900d7f5154

Files: 4441fae4d0d265267896434addfea2900d7f5154 / about / html / edit.js

5222 bytesRaw
1const nest = require('depnest')
2const dataurl = require('dataurl-')
3const hyperfile = require('hyperfile')
4const hypercrop = require('hypercrop')
5const hyperlightbox = require('hyperlightbox')
6const {
7 h, Value, Array: MutantArray, Dict: MutantObject, Struct,
8 map, computed, when, dictToCollection
9} = require('mutant')
10const pull = require('pull-stream')
11
12exports.gives = nest('about.html.edit')
13
14exports.needs = nest({
15 'about.obs.name': 'first',
16 'about.obs.imageUrl': 'first',
17 'blob.sync.url': 'first',
18 'keys.sync.id': 'first',
19 'message.html.confirm': 'first',
20 sbot: {
21 'async.addBlob': 'first',
22 'pull.links': 'first'
23 }
24})
25
26exports.create = function (api) {
27 return nest({
28 'about.html.edit': edit
29 })
30
31 // TODO refactor this to use obs better
32 function edit (id) {
33 var avatar = Struct({
34 current: api.about.obs.imageUrl(id),
35 new: MutantObject()
36 })
37
38 const links = api.sbot.pull.links
39
40 var name = Struct({
41 current: api.about.obs.name(id),
42 new: Value()
43 })
44
45 // TODO use patchcores observable images + names
46 var images = MutantArray()
47 pull(
48 links({dest: id, rel: 'about', values: true}),
49 pull.map(e => e.value.content.image),
50 pull.filter(e => e && typeof e.link === 'string'),
51 pull.unique('link'),
52 pull.drain(image => images.push(image))
53 )
54
55 var namesRecord = MutantObject()
56 // TODO constrain query to one name per peer?
57 pull(
58 links({dest: id, rel: 'about', values: true}),
59 pull.map(e => e.value.content.name),
60 pull.filter(Boolean),
61 pull.drain(name => {
62 var n = namesRecord.get(name) || 0
63 namesRecord.put(name, n + 1)
64 })
65 )
66 var names = dictToCollection(namesRecord)
67
68 var lb = hyperlightbox()
69
70 // TODO load this in, make this editable
71 var description = ''
72
73 var isPossibleUpdate = computed([name.new, avatar.new], (name, avatar) => {
74 return name || avatar.link
75 })
76
77 var avatarSrc = computed([avatar], avatar => {
78 if (avatar.new.link) return api.blob.sync.url(avatar.new.link)
79 else return avatar.current
80 })
81
82 var displayedName = computed([name], name => {
83 if (name.new) return '@' + name.new
84 else return '@' + name.current
85 })
86
87 return h('AboutEditor', [
88 h('section.lightbox', lb),
89 h('section.avatar', [
90 h('section', [
91 h('img', { src: avatarSrc })
92 ]),
93 h('footer', displayedName)
94 ]),
95 h('section.description', description),
96 h('section.aliases', [
97 h('header', 'Aliases'),
98 h('section.avatars', [
99 h('header', 'Avatars'),
100 map(images, image => h('img', {
101 'src': api.blob.sync.url(image.link),
102 'ev-click': () => avatar.new.set(image)
103 })),
104 h('div.file-upload', [
105 hyperfile.asDataURL(dataUrlCallback)
106 ])
107 ]),
108 h('section.names', [
109 h('header', 'Names'),
110 h('section', [
111 map(names, n => h('div', { 'ev-click': () => name.new.set(n.key()) }, [
112 h('div.name', n.key),
113 h('div.count', n.value)
114 ])),
115 h('input', {
116 placeholder: ' + another name',
117 'ev-keyup': e => name.new.set(e.target.value)
118 })
119 ])
120 ]),
121 when(isPossibleUpdate, h('section.action', [
122 h('button.cancel', { 'ev-click': clearNewSelections }, 'cancel'),
123 h('button.confirm', { 'ev-click': handleUpdateClick }, 'confirm changes')
124 ]))
125 ])
126 ])
127
128 function dataUrlCallback (data) {
129 var el = crop(data, (err, data) => {
130 if (err) throw err
131
132 if (data) {
133 var _data = dataurl.parse(data)
134 pull(
135 pull.once(_data.data),
136 api.sbot.async.addBlob((err, hash) => {
137 if (err) throw err // TODO check if this is safely caught by error catcher
138
139 avatar.new.set({
140 link: hash,
141 size: _data.data.length,
142 type: _data.mimetype,
143 width: 512,
144 height: 512
145 })
146 })
147 )
148 }
149 lb.close()
150 })
151 lb.show(el)
152 }
153
154 function clearNewSelections () {
155 name.new.set(null)
156 avatar.new.set({})
157 }
158
159 function handleUpdateClick () {
160 const newName = name.new()
161 const newAvatar = avatar.new()
162
163 const msg = {
164 type: 'about',
165 about: id
166 }
167
168 if (newName) msg.name = newName
169 if (newAvatar.link) msg.image = newAvatar
170
171 api.message.html.confirm(msg, (err, data) => {
172 if (err) return console.error(err)
173
174 clearNewSelections()
175
176 // TODO - update aliases displayed
177 })
178 }
179 }
180}
181
182function crop (d, cb) {
183 var canvas = hypercrop(h('img', {src: d}))
184
185 return h('AboutImageEditor', [
186 h('header', 'Click and drag to crop your avatar.'),
187 canvas,
188 // canvas.selection,
189 h('section.actions', [
190 h('button.cancel', { 'ev-click': () => cb(new Error('canceled')) }, 'cancel'),
191 h('button.okay', { 'ev-click': () => cb(null, canvas.selection.toDataURL()) }, 'okay')
192 ])
193 ])
194}
195
196

Built with git-ssb-web