git ssb

16+

Dominic / patchbay



Tree: 747bb2d95395b5f07ec8780551fd62881c5618af

Files: 747bb2d95395b5f07ec8780551fd62881c5618af / about / html / edit.js

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

Built with git-ssb-web