git ssb

10+

Matt McKegg / patchwork



Commit 5cfee7fcb845036b63555b7546206364a1700b7a

compose: suggest mentions and emoji

Matt McKegg committed on 2/19/2017, 8:46:12 AM
Parent: 18d5d5c12c41651882d96e8d597c169e95dc4e73

Files changed

modules/message/html/compose.jschanged
modules/profile/async/suggest.jsadded
package.jsonchanged
styles/suggest-box.mcssadded
modules/message/html/compose.jsView
@@ -6,12 +6,16 @@
66 var computed = require('mutant/computed')
77 var nest = require('depnest')
88 var mentions = require('ssb-mentions')
99 var extend = require('xtend')
10 +var addSuggest = require('suggest-box')
1011
1112 exports.needs = nest({
1213 'blob.html.input': 'first',
13- 'message.async.publish': 'first'
14 + 'profile.async.suggest': 'first',
15 + 'message.async.publish': 'first',
16 + 'emoji.sync.names': 'first',
17 + 'emoji.sync.url': 'first'
1418 })
1519
1620 exports.gives = nest('message.html.compose')
1721
@@ -20,8 +24,9 @@
2024 var files = []
2125 var filesById = {}
2226 var focused = Value(false)
2327 var hasContent = Value(false)
28 + var getProfileSuggestions = api.profile.async.suggest()
2429 var blurTimeout = null
2530
2631 var expanded = computed([shrink, focused, hasContent], (shrink, focused, hasContent) => {
2732 if (!shrink || hasContent) {
@@ -72,8 +77,31 @@
7277 textArea,
7378 actions
7479 ])
7580
81 + addSuggest(textArea, (inputText, cb) => {
82 + if (inputText[0] === '@') {
83 + cb(null, getProfileSuggestions(inputText.slice(1)))
84 + } else if (inputText[0] === ':') {
85 + // suggest emojis
86 + var word = inputText.slice(1)
87 + if (word[word.length - 1] === ':') {
88 + word = word.slice(0, -1)
89 + }
90 + // TODO: when no emoji typed, list some default ones
91 + cb(null, api.emoji.sync.names().filter(function (name) {
92 + return name.slice(0, word.length) === word
93 + }).slice(0, 100).map(function (emoji) {
94 + return {
95 + image: api.emoji.sync.url(emoji),
96 + title: emoji,
97 + subtitle: emoji,
98 + value: ':' + emoji + ':'
99 + }
100 + }))
101 + }
102 + }, {cls: 'SuggestBox'})
103 +
76104 return composer
77105
78106 // scoped
79107
modules/profile/async/suggest.jsView
@@ -1,0 +1,67 @@
1 +var nest = require('depnest')
2 +var {Struct, map, computed, watch} = require('mutant')
3 +
4 +exports.needs = nest({
5 + 'profile.obs.recentlyUpdated': 'first',
6 + 'contact.obs.following': 'first',
7 + 'about.obs.name': 'first',
8 + 'about.obs.imageUrl': 'first',
9 + 'keys.sync.id': 'first'
10 +})
11 +
12 +exports.gives = nest('profile.async.suggest')
13 +
14 +exports.create = function (api) {
15 + var suggestions = null
16 + var recentSuggestions = null
17 +
18 + return nest('profile.async.suggest', function () {
19 + loadSuggestions()
20 + return function (word) {
21 + if (!word) {
22 + return recentSuggestions()
23 + } else {
24 + return suggestions().filter((item) => {
25 + return item.title.toLowerCase().startsWith(word.toLowerCase())
26 + })
27 + }
28 + }
29 + })
30 +
31 + function loadSuggestions () {
32 + if (!suggestions) {
33 + var id = api.keys.sync.id()
34 + var following = api.contact.obs.following(id)
35 + var recentlyUpdated = api.profile.obs.recentlyUpdated()
36 + var contacts = computed([following, recentlyUpdated], function (a, b) {
37 + var result = Array.from(a)
38 + b.forEach((item, i) => {
39 + if (!result.includes(item)) {
40 + result.push(item)
41 + }
42 + })
43 + return result
44 + })
45 +
46 + recentSuggestions = map(computed(recentlyUpdated, (items) => Array.from(items).slice(0, 10)), suggestion, {idle: true})
47 + suggestions = map(contacts, suggestion, {idle: true})
48 + watch(recentSuggestions)
49 + watch(suggestions)
50 + }
51 + }
52 +
53 + function suggestion (id) {
54 + var name = api.about.obs.name(id)
55 + return Struct({
56 + title: name,
57 + subtitle: id.substring(0, 10),
58 + value: computed([name, id], mention),
59 + image: api.about.obs.imageUrl(id),
60 + showBoth: true
61 + })
62 + }
63 +}
64 +
65 +function mention (name, id) {
66 + return `[@${name}](${id})`
67 +}
package.jsonView
@@ -27,9 +27,9 @@
2727 "is-visible": "^2.1.1",
2828 "level": "~1.4.0",
2929 "level-memview": "0.0.0",
3030 "micro-css": "^1.0.0",
31- "mutant": "^3.15.0",
31 + "mutant": "^3.15.1",
3232 "mutant-pull-reduce": "^1.0.1",
3333 "non-private-ip": "^1.4.1",
3434 "on-change-network": "0.0.2",
3535 "on-wakeup": "^1.0.1",
@@ -55,9 +55,10 @@
5555 "ssb-msgs": "^5.2.0",
5656 "ssb-query": "~0.1.1",
5757 "ssb-ref": "~2.6.2",
5858 "ssb-sort": "^1.0.0",
59- "statistics": "^3.3.0"
59 + "statistics": "^3.3.0",
60 + "suggest-box": "^2.2.3"
6061 },
6162 "devDependencies": {
6263 "electron": "~1.4.4"
6364 }
styles/suggest-box.mcssView
@@ -1,0 +1,48 @@
1 +SuggestBox {
2 + width: max-content;
3 + max-height: 50vh;
4 + overflow-y: scroll;
5 + background-color: #fff;
6 + border: 1px gainsboro solid;
7 +
8 + padding: .2rem .5rem;
9 + margin-top: .35rem;
10 +
11 + ul {
12 + list-style-type: none;
13 + padding: 0;
14 +
15 + li {
16 + display: flex;
17 + align-items: center;
18 +
19 + padding-right: .2rem;
20 + margin-bottom: .2rem;
21 +
22 + img {
23 + height: 36px;
24 + width: 36px;
25 + padding: .2rem;
26 + }
27 +
28 + strong {
29 + flex-grow: 1;
30 + margin-left: .5rem;
31 + font-weight: 300;
32 + }
33 +
34 + small {
35 + font-family: monospace;
36 + margin-left: .5rem;
37 + padding-right: .2rem;
38 + font-size: 1rem;
39 + }
40 + }
41 +
42 + li.selected {
43 + color: #fff;
44 + background: #0caaf9;
45 + }
46 + }
47 +
48 +}

Built with git-ssb-web