git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Commit fb6a6fd101e60f483142411bcb0f3bc164a3abfb

prompt to set up profile on first use, add description field (only self so far)

Matt McKegg committed on 3/16/2017, 2:07:19 AM
Parent: 0200c1c158b288014cfe99b3917705830f077f70

Files changed

main-window.jschanged
modules/page/html/render/profile.jschanged
modules/profile/sheet/edit.jsadded
plugs/message/html/render/about.jschanged
styles/profile-header.mcsschanged
styles/image-input.mcssadded
styles/profile-editor.mcssadded
main-window.jsView
@@ -2,8 +2,9 @@
22 var entry = require('depject/entry')
33 var electron = require('electron')
44 var h = require('mutant/h')
55 var when = require('mutant/when')
6+var onceTrue = require('mutant/once-true')
67 var computed = require('mutant/computed')
78 var catchLinks = require('./lib/catch-links')
89 var insertCss = require('insert-css')
910 var nest = require('depnest')
@@ -21,18 +22,29 @@
2122 )
2223
2324 var api = entry(sockets, nest({
2425 'keys.sync.id': 'first',
26+ 'sbot.obs.connection': 'first',
2527 'blob.sync.url': 'first',
2628 'page.html.render': 'first',
2729 'app.html.search': 'first',
2830 'app.views': 'first',
29- 'app.html.progressNotifier': 'first'
31+ 'app.html.progressNotifier': 'first',
32+ 'profile.sheet.edit': 'first'
3033 }))
3134
3235 var id = api.keys.sync.id()
3336 var latestUpdate = LatestUpdate()
3437
38+ // prompt to setup profile on first use
39+ onceTrue(api.sbot.obs.connection, (sbot) => {
40+ sbot.latestSequence(sbot.id, (_, key) => {
41+ if (key == null) {
42+ api.profile.sheet.edit()
43+ }
44+ })
45+ })
46+
3547 var views = api.app.views(api.page.html.render, [
3648 '/public', '/private', id, '/mentions'
3749 ])
3850
modules/page/html/render/profile.jsView
@@ -5,22 +5,25 @@
55
66 exports.needs = nest({
77 'about.obs': {
88 name: 'first',
9+ description: 'first',
910 names: 'first',
1011 images: 'first',
1112 color: 'first'
1213 },
1314 'blob.sync.url': 'first',
1415 'blob.html.input': 'first',
1516 'message.async.publish': 'first',
17+ 'message.html.markdown': 'first',
1618 'about.html.image': 'first',
1719 'feed.html.rollup': 'first',
1820 'sbot.pull.userFeed': 'first',
1921 'sbot.async.publish': 'first',
2022 'keys.sync.id': 'first',
2123 'sheet.display': 'first',
2224 'profile.obs.rank': 'first',
25+ 'profile.sheet.edit': 'first',
2326 'contact.obs': {
2427 followers: 'first',
2528 following: 'first'
2629 }
@@ -31,8 +34,9 @@
3134 return nest('page.html.render', function profile (id) {
3235 if (!ref.isFeed(id)) return
3336
3437 var name = api.about.obs.name(id)
38+ var description = api.about.obs.description(id)
3539 var yourId = api.keys.sync.id()
3640 var yourFollows = api.contact.obs.following(yourId)
3741 var rawFollowers = api.contact.obs.followers(id)
3842 var rawFollowing = api.contact.obs.following(id)
@@ -133,9 +137,9 @@
133137 h('div.title', [
134138 h('h1', ['@', name]),
135139 h('div.meta', [
136140 when(id === yourId, [
137- h('a.ToggleButton.-disabled', 'This is you!')
141+ h('button', {'ev-click': api.profile.sheet.edit}, 'Edit Your Profile')
138142 ], [
139143 when(youFollow,
140144 h('a.ToggleButton.-unsubscribe', {
141145 'href': '#',
@@ -149,8 +153,15 @@
149153 )
150154 ])
151155 ])
152156 ]),
157+ h('section -description', [
158+ computed(description, (text) => {
159+ if (typeof text === 'string') {
160+ return api.message.html.markdown(text)
161+ }
162+ })
163+ ]),
153164 h('section', [ namePicker, imagePicker ])
154165 ])
155166 ])
156167
modules/profile/sheet/edit.jsView
@@ -1,0 +1,142 @@
1+var nest = require('depnest')
2+var extend = require('xtend')
3+var {Value, h, computed, when} = require('mutant')
4+var fallbackImageUrl = 'data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
5+
6+exports.gives = nest('profile.sheet.edit')
7+
8+exports.needs = nest({
9+ 'sheet.display': 'first',
10+ 'keys.sync.id': 'first',
11+ 'sbot.async.publish': 'first',
12+ 'about.obs': {
13+ name: 'first',
14+ description: 'first',
15+ image: 'first',
16+ color: 'first'
17+ },
18+ 'blob.html.input': 'first',
19+ 'blob.sync.url': 'first'
20+})
21+
22+exports.create = function (api) {
23+ return nest('profile.sheet.edit', function () {
24+ var id = api.keys.sync.id()
25+ api.sheet.display(close => {
26+ var currentName = api.about.obs.name(id)
27+ var currentImage = api.about.obs.image(id)
28+ var currentDescription = api.about.obs.description(id)
29+
30+ var publishing = Value(false)
31+ var chosenImage = Value(currentImage())
32+ var chosenName = Value(currentName())
33+ var chosenDescription = Value(currentDescription())
34+
35+ return {
36+ content: h('div', {
37+ style: {
38+ padding: '20px',
39+ 'text-align': 'center'
40+ }
41+ }, [
42+ h('h2', {
43+ style: {
44+ 'font-weight': 'normal'
45+ }
46+ }, ['Your Profile']),
47+ h('ProfileEditor', [
48+ h('div.side', [
49+ h('ImageInput', [
50+ h('img', {
51+ style: { 'background-color': api.about.obs.color(id) },
52+ src: computed(chosenImage, (id) => id ? api.blob.sync.url(id) : fallbackImageUrl)
53+ }),
54+ h('span', ['🖼 Choose Profile Image...']),
55+ api.blob.html.input(file => {
56+ chosenImage.set(file.link)
57+ }, {
58+ accept: 'image/*',
59+ resize: { width: 500, height: 500 }
60+ })
61+ ])
62+ ]),
63+ h('div.main', [
64+ h('input.name', {
65+ placeholder: 'Choose a name',
66+ hooks: [ValueHook(chosenName), FocusHook()]
67+ }),
68+ h('textarea.description', {
69+ placeholder: 'Describe yourself',
70+ hooks: [ValueHook(chosenDescription)]
71+ })
72+ ])
73+ ])
74+ ]),
75+ footer: [
76+ h('button -save', {
77+ 'ev-click': save,
78+ 'disabled': publishing
79+ }, when(publishing, 'Publishing...', 'Publish')),
80+ h('button -cancel', {
81+ 'ev-click': close
82+ }, 'Cancel')
83+ ]
84+ }
85+
86+ function save () {
87+ // no confirm
88+ var update = {}
89+
90+ if (chosenImage() !== currentImage()) update.image = chosenImage()
91+ if (chosenName() !== currentName()) update.name = chosenName()
92+ if (chosenDescription() !== currentDescription()) update.description = chosenDescription()
93+
94+ if (Object.keys(update).length) {
95+ publishing.set(true)
96+ api.sbot.async.publish(extend({
97+ type: 'about',
98+ about: id
99+ }, update), (err) => {
100+ if (err) {
101+ publishing.set(false)
102+ showDialog({
103+ type: 'error',
104+ title: 'Error',
105+ buttons: ['OK'],
106+ message: 'An error occured while attempting to publish about message.',
107+ detail: err.message
108+ })
109+ } else {
110+ close()
111+ }
112+ })
113+ } else {
114+ close()
115+ }
116+ }
117+ })
118+ })
119+}
120+
121+function FocusHook () {
122+ return function (element) {
123+ setTimeout(() => {
124+ element.focus()
125+ element.select()
126+ }, 5)
127+ }
128+}
129+
130+function ValueHook (obs) {
131+ return function (element) {
132+ element.value = obs()
133+ element.oninput = function () {
134+ obs.set(element.value.trim())
135+ }
136+ }
137+}
138+
139+function showDialog (opts) {
140+ var electron = require('electron')
141+ electron.remote.dialog.showMessageBox(electron.remote.getCurrentWindow(), opts)
142+}
plugs/message/html/render/about.jsView
@@ -5,9 +5,10 @@
55
66 exports.needs = nest({
77 'message.html': {
88 decorate: 'reduce',
9- layout: 'first'
9+ layout: 'first',
10+ markdown: 'first'
1011 },
1112 'keys.sync.id': 'first',
1213 'about.html.link': 'first',
1314 'about.obs.name': 'first',
@@ -51,11 +52,26 @@
5152 h('img', {src: api.blob.sync.url(c.image)})
5253 ]))
5354 }
5455
55- var element = api.message.html.layout(msg, extend({
56- content, layout: 'mini'
57- }, opts))
56+ var elements = []
5857
59- return api.message.html.decorate(element, { msg })
58+ if (content.length) {
59+ var element = api.message.html.layout(msg, extend({
60+ content, layout: 'mini'
61+ }, opts))
62+ elements.push(api.message.html.decorate(element, { msg }))
63+ }
64+
65+ if (c.description) {
66+ elements.push(api.message.html.decorate(api.message.html.layout(msg, extend({
67+ content: [
68+ self ? 'self assigned a description' : ['assigned a description to ', api.about.html.link(c.about)],
69+ api.message.html.markdown(c.description)
70+ ],
71+ layout: 'mini'
72+ }, opts)), { msg }))
73+ }
74+
75+ return elements
6076 })
6177 }
styles/profile-header.mcssView
@@ -22,6 +22,11 @@
2222 h1 {
2323 flex: 1
2424 }
2525 }
26+ section {
27+ -description {
28+ font-size: 120%
29+ }
30+ }
2631 }
2732 }
styles/image-input.mcssView
@@ -1,0 +1,43 @@
1+ImageInput {
2+ position: relative
3+ width: 200px;
4+ padding: 5px;
5+ background: white;
6+ box-shadow: 0 0 10px #AAA;
7+ transition: box-shadow 0.2s
8+
9+ img {
10+ width: 100%
11+ background-image: linear-gradient(172deg, rgb(247, 247, 247), rgba(0,0,0,0))
12+ }
13+ input {
14+ cursor: pointer
15+ opacity: 0
16+ position: absolute
17+ width: 100%
18+ height: 100%
19+ top: 0
20+ left: 0
21+ }
22+
23+ span {
24+ position: absolute
25+ left: 0
26+ right: 0
27+ bottom: 0
28+ margin: 20px
29+ background: #444
30+ padding: 4px 8px
31+ border-radius: 5px
32+ transition: opacity 0.2s
33+ opacity: 0.5
34+ color: white
35+ }
36+
37+ :hover {
38+ box-shadow: 0 0 10px #393939;
39+ span {
40+ opacity: 1
41+ }
42+ }
43+}
styles/profile-editor.mcssView
@@ -1,0 +1,23 @@
1+ProfileEditor {
2+ display: flex
3+ div.side {
4+ margin-right: 10px
5+ }
6+ div.main {
7+ flex: 1
8+ display: flex
9+ flex-direction: column
10+ input {
11+ border: 1px solid #CCC
12+ font-size: 150%
13+ padding: 10px
14+ }
15+ textarea {
16+ margin-top: 10px
17+ border: 1px solid #CCC
18+ padding: 10px
19+ font-size: 150%
20+ flex: 1
21+ }
22+ }
23+}

Built with git-ssb-web