git ssb

16+

Dominic / patchbay



Commit 98160d45e90af28d4a3c38e17ba614f245725906

transition avatar/edit to mcss + mutant

mix irving committed on 1/25/2017, 8:07:55 AM
Parent: 39a3fdd490156a44a50029332ebf5c046b40274a

Files changed

modules_basic/avatar/edit.jschanged
modules_basic/avatar/edit.mcssadded
modules_basic/avatar/edit.jsView
@@ -1,31 +1,36 @@
11 'use strict'
2-var dataurl = require('dataurl-')
3-var hyperfile = require('hyperfile')
4-var hypercrop = require('hypercrop')
5-var hyperlightbox = require('hyperlightbox')
6-var h = require('hyperscript')
7-var pull = require('pull-stream')
8-var getAvatar = require('ssb-avatar')
9-var ref = require('ssb-ref')
10-var visualize = require('visualize-buffer')
11-var self_id = require('../../keys').id
2 +const fs = require('fs')
3 +const dataurl = require('dataurl-')
4 +const hyperfile = require('hyperfile')
5 +const hypercrop = require('hypercrop')
6 +const hyperlightbox = require('hyperlightbox')
7 +const h = require('../../h')
8 +const {
9 + Value, Array: MutantArray, Dict: MutantObject,
10 + map, computed, when
11 +} = require('@mmckegg/mutant')
12 +const pull = require('pull-stream')
13 +const getAvatar = require('ssb-avatar')
14 +const ref = require('ssb-ref')
15 +const visualize = require('visualize-buffer')
16 +const self_id = require('../../keys').id
1217
1318 function crop (d, cb) {
1419 var canvas = hypercrop(h('img', {src: d}))
1520
16- return h('div.column.avatar_pic',
21 + return h('div.column.avatar_pic', [
1722 canvas,
1823 //canvas.selection,
19- h('div.row.avatar_pic__controls',
20- h('button', 'okay', {onclick: function () {
24 + h('div.row.avatar_pic__controls', [
25 + h('button', 'okay', {'ev-click': () => {
2126 cb(null, canvas.selection.toDataURL())
2227 }}),
23- h('button', 'cancel', {onclick: function () {
28 + h('button', 'cancel', {'ev-click': () => {
2429 cb(new Error('canceled'))
2530 }})
26- )
27- )
31 + ])
32 + ])
2833 }
2934
3035 exports.needs = {
3136 message_confirm: 'first',
@@ -34,110 +39,125 @@
3439 sbot_links: 'first',
3540 avatar_name: 'first'
3641 }
3742
38-exports.gives = 'avatar_edit'
43 +exports.gives = {
44 + avatar_edit: true,
45 + mcss: true
46 +}
3947
4048 exports.create = function (api) {
41- return function (id) {
49 + return {
50 + avatar_edit,
51 + mcss: () => fs.readFileSync(__filename.replace(/js$/, 'mcss'), 'utf8')
52 + }
4253
54 + function avatar_edit (id) {
4355 var img = visualize(new Buffer(id.substring(1), 'base64'), 256)
44- img.classList.add('avatar--large')
4556
46- var lb = hyperlightbox()
47- var name_input = h('input', {placeholder: 'rename'})
48- var name = api.avatar_name(id)
49- var selected = null
50-
51- getAvatar({links: api.sbot_links}, self_id, id, function (err, avatar) {
57 + var proposedAvatar = MutantObject()
58 + getAvatar({links: api.sbot_links}, self_id, id, (err, avatar) => {
5259 if (err) return console.error(err)
5360 //don't show user has already selected an avatar.
54- if(selected) return
61 + if(proposedAvatar.keys().length) return
5562 if(ref.isBlob(avatar.image))
5663 img.src = api.blob_url(avatar.image)
5764 })
5865
59- var also_pictured = h('div.profile__alsopicturedas.wrap')
60-
66 + var images = MutantArray()
6167 pull(
6268 api.sbot_links({dest: id, rel: 'about', values: true}),
63- pull.map(function (e) {
64- return e.value.content.image
65- }),
66- pull.filter(function (e) {
67- return e && 'string' == typeof e.link
68- }),
69 + pull.map(e => e.value.content.image),
70 + pull.filter(e => e && 'string' == typeof e.link),
6971 pull.unique('link'),
70- pull.drain(function (image) {
71- also_pictured.appendChild(
72- h('a', {href:'#', onclick: function (ev) {
73- ev.stopPropagation()
74- ev.preventDefault()
75- selected = image
76- img.src = api.blob_url(image.link || image)
77- }},
78- h('img.avatar--thumbnail', {src: api.blob_url(image)})
79- )
80- )
81- })
72 + pull.drain(image => images.push(image) )
8273 )
8374
84- return h('div.row.profile',
85- lb,
86- img,
87- h('div.column.profile__info',
88- h('strong', name),
89- name_input,
75 + var lb = hyperlightbox()
76 + var name = Value(api.avatar_name(id))
77 + var proposedName = Value()
78 + var names = [] //TODO load in name aliases
79 + var name_input = h('input', {placeholder: ' + another name', 'ev-keyup': (e) => proposedName.set(e.target.value) })
80 + var description = '' //TODO load this in, make this editable
9081
91- hyperfile.asDataURL(function (data) {
92- var el = crop(data, function (err, data) {
93- if(data) {
94- img.src = data
95- var _data = dataurl.parse(data)
96- pull(
97- pull.once(_data.data),
98- api.sbot_blobs_add(function (err, hash) {
99- //TODO. Alerts are EVIL.
100- //I use them only in a moment of weakness.
82 + var isPossibleUpdate = computed([proposedName, proposedAvatar], (name, image) => {
83 + console.log('checking', name, image)
10184
102- if(err) return alert(err.stack)
103- selected = {
104- link: hash,
105- size: _data.data.length,
106- type: _data.mimetype,
107- width: 512,
108- height: 512
109- }
85 + return name || Object.keys(image).length
86 + })
11087
111- })
112- )
113- }
114- lb.close()
115- })
116- lb.show(el)
117- }),
118- h('button', 'update', {onclick: function () {
119- if(name_input.value)
120- name.textContent = name_input.value
88 + return h('ProfileEdit', [
89 + h('section.lightbox', lb),
90 + h('section.avatar', [
91 + h('section', img),
92 + h('footer', name),
93 + ]),
94 + h('section.description', description),
95 + h('section.aliases', [
96 + h('header', 'Aliases'),
97 + h('section.avatars', [
98 + h('header', 'Avatars'),
99 + map(images, image => h('img', {
100 + 'src': api.blob_url(image),
101 + 'ev-click': changeSelectedImage(image)
102 + })),
103 + hyperfile.asDataURL(dataUrlCallback),
104 + ]),
105 + h('section.names', [
106 + h('header', 'Names'),
107 + names,
108 + name_input
109 + ]),
110 + when(isPossibleUpdate, h('button.confirm', { 'ev-click': handleUpdateClick }, 'Confirm changes'))
111 + ])
112 + ])
121113
122- if(selected)
123- api.message_confirm({
124- type: 'about',
125- about: id,
126- name: name_input.value || undefined,
127- image: selected
114 + function changeSelectedImage (image) {
115 + return () => {
116 + proposedAvatar.set(image)
117 + img.src = api.blob_url(image.link || image)
118 + }
119 + }
120 +
121 + function dataUrlCallback (data) {
122 + var el = crop(data, (err, data) => {
123 + if(data) {
124 + img.src = data
125 + var _data = dataurl.parse(data)
126 + pull(
127 + pull.once(_data.data),
128 + api.sbot_blobs_add((err, hash) => {
129 + //TODO. Alerts are EVIL.
130 + //I use them only in a moment of weakness.
131 +
132 + if(err) return alert(err.stack)
133 + proposedAvatar.set({
134 + link: hash,
135 + size: _data.data.length,
136 + type: _data.mimetype,
137 + width: 512,
138 + height: 512
139 + })
128140 })
129- else if(name_input.value) //name only
130- api.message_confirm({
131- type: 'about',
132- about: id,
133- name: name_input.value || undefined,
134- })
135- else
136- //another moment of weakness
137- alert('must select a name or image')
138- }}),
139- also_pictured
140- )
141- )
141 + )
142 + }
143 + lb.close()
144 + })
145 + lb.show(el)
146 + }
147 +
148 + function handleUpdateClick () {
149 + const msg = {
150 + type: 'about',
151 + about: id,
152 + name: proposedName(),
153 + image: proposedAvatar()
154 + }
155 +
156 + api.message_confirm(msg)
157 +
158 + if(proposedName) name.set('@'+proposedName())
159 + }
142160 }
161 +
143162 }
163 +
modules_basic/avatar/edit.mcssView
@@ -1,0 +1,84 @@
1 +ProfileEdit {
2 + display: flex
3 + flex-wrap: wrap
4 + justify-content: space-between
5 +
6 + margin-bottom: 2rem
7 +
8 + section.lightbox {
9 + position: absolute
10 + }
11 +
12 + section.avatar {
13 + margin-right: 1rem
14 +
15 + section img {
16 + width: 256px
17 + height: 256px
18 + }
19 +
20 + footer {
21 + font-size: 1.2rem
22 + }
23 + }
24 +
25 + section.description {
26 + flex-basis: 40%
27 + flex-grow: 1
28 +
29 + margin-top: 1rem
30 + }
31 +
32 + section.aliases {
33 + flex-basis: 100%
34 +
35 + margin-top: 1rem
36 +
37 + header {
38 + margin-bottom: .2rem
39 + }
40 +
41 + section {
42 + display: flex
43 + flex-wrap: wrap
44 + justify-content: space-between
45 + align-content: flex-start
46 +
47 + margin-bottom: 1rem
48 +
49 + header {
50 + flex-basis: 100%
51 +
52 + font-size: .9rem
53 + $textSubtle
54 +
55 + margin-bottom: .2rem
56 + }
57 +
58 + input {
59 + }
60 + }
61 +
62 + section.avatars {
63 +
64 + img {
65 + $avatar-large
66 + margin: 0 .15rem 0.2rem 0
67 +
68 + cursor: pointer
69 + }
70 + }
71 +
72 + section.names {
73 + input {
74 + border: 1px gainsboro solid
75 + font-size: 1rem
76 + }
77 + }
78 +
79 + button.confirm {
80 + margin-left: 0
81 + }
82 + }
83 +}
84 +

Built with git-ssb-web