Commit 453e088bb1a566f6624aca8299dbbac2fee35272
Merge branch 'master' into patchwork_friendly (and small friends subs
page fix)mix irving committed on 2/13/2018, 10:58:20 PM
Parent: b4bb2278fc6720ae4aa5470a30a66da315b74f00
Parent: bee2958f3a890cd7ecae7658ea242acbfdcfdc52
Files changed
about/index.js | ||
---|---|---|
@@ -1,5 +1,5 @@ | ||
1 | 1 … | module.exports = { |
2 | 2 … | html: { |
3 | 3 … | avatar: require('./html/avatar') |
4 | - }, | |
4 … | + } | |
5 | 5 … | } |
app/async/catch-link-click.js | ||
---|---|---|
@@ -30,22 +30,20 @@ | ||
30 | 30 … | const href = anchor.getAttribute('href') |
31 | 31 … | if (!href) return |
32 | 32 … | |
33 | 33 … | const url = Url.parse(href) |
34 | - const opts = { | |
34 … | + const opts = { | |
35 | 35 … | isExternal: !!url.host |
36 | 36 … | } |
37 | 37 … | |
38 | 38 … | if (isMsg(href)) { |
39 | 39 … | api.sbot.async.get(href, (err, data) => { |
40 | 40 … | // NOTE the catchLinkClick cb has signature (link, opts) |
41 | - cb(err || {key:href, value: data}, opts) | |
41 … | + cb(err || {key: href, value: data}, opts) | |
42 | 42 … | }) |
43 | 43 … | return |
44 | 44 … | } |
45 | 45 … | |
46 | 46 … | cb(href, opts) |
47 | 47 … | }) |
48 | 48 … | } |
49 | 49 … | } |
50 | - | |
51 | - |
app/html/app.js | ||
---|---|---|
@@ -20,17 +20,18 @@ | ||
20 | 20 … | 'sbot.async.get': 'first' |
21 | 21 … | }) |
22 | 22 … | |
23 | 23 … | exports.create = (api) => { |
24 | - var view = Value() | |
24 … | + var view | |
25 | 25 … | |
26 | 26 … | return nest({ |
27 | 27 … | 'app.html.app': function app () { |
28 | 28 … | api.app.sync.initialize() |
29 | 29 … | |
30 … | + view = Value() | |
30 | 31 … | var app = h('App', view) |
31 | 32 … | api.history.obs.location()(renderLocation) |
32 | - api.history.obs.location()(logLocation) | |
33 … | + api.history.obs.location()(loc => console.log('location:', loc)) | |
33 | 34 … | |
34 | 35 … | startApp() |
35 | 36 … | |
36 | 37 … | return app |
@@ -38,72 +39,65 @@ | ||
38 | 39 … | }) |
39 | 40 … | |
40 | 41 … | function renderLocation (loc) { |
41 | 42 … | var page = api.router.sync.router(loc) |
42 | - if (page) view.set([ | |
43 | - api.app.html.header({location: loc, push: api.history.sync.push}), | |
44 | - api.app.html.warning(), | |
45 | - page | |
46 | - ]) | |
43 … | + if (page) { | |
44 … | + view.set([ | |
45 … | + api.app.html.header({location: loc, push: api.history.sync.push}), | |
46 … | + api.app.html.warning(), | |
47 … | + page | |
48 … | + ]) | |
49 … | + } | |
47 | 50 … | } |
48 | 51 … | |
49 | 52 … | function startApp () { |
50 | 53 … | api.history.sync.push({page: 'splash'}) |
51 | 54 … | |
52 | 55 … | const delay = process.env.STARTUP_DELAY || 2000 |
53 | 56 … | setTimeout(enterApp, delay) |
57 … | + } | |
54 | 58 … | |
55 | - function enterApp() { | |
56 | - const isOnboarded = api.settings.sync.get('onboarded') | |
57 | - const initialPage = process.env.STARTUP_PAGE || 'blogIndex' | |
58 | - if (isOnboarded) { | |
59 | - autoPub() | |
60 | - api.history.sync.push({page: initialPage}) | |
61 | - } | |
62 | - else { | |
63 | - api.history.sync.push({ | |
64 | - page:'userEdit', | |
65 | - feed: api.keys.sync.id(), | |
66 | - callback: (err, didEdit) => { | |
67 | - if (err) throw new Error ('Error editing profile', err) | |
59 … | + function enterApp () { | |
60 … | + const isOnboarded = api.settings.sync.get('onboarded') | |
61 … | + const initialPage = process.env.STARTUP_PAGE || 'blogIndex' | |
62 … | + if (isOnboarded) { | |
63 … | + autoPub() | |
64 … | + api.history.sync.push({page: initialPage}) | |
65 … | + } else { | |
66 … | + api.history.sync.push({ | |
67 … | + page: 'userEdit', | |
68 … | + feed: api.keys.sync.id(), | |
69 … | + callback: (err, didEdit) => { | |
70 … | + if (err) throw new Error('Error editing profile', err) | |
68 | 71 … | |
69 | - // if they clicked something, just mark them onboarded | |
70 | - api.settings.sync.set({ onboarded: true }) | |
72 … | + // if they clicked something, just mark them onboarded | |
73 … | + api.settings.sync.set({ onboarded: true }) | |
71 | 74 … | |
72 | - autoPub() | |
73 | - api.history.sync.push({page: initialPage}) | |
74 | - } | |
75 | - }) | |
76 | - } | |
75 … | + autoPub() | |
76 … | + api.history.sync.push({page: initialPage}) | |
77 … | + } | |
78 … | + }) | |
77 | 79 … | } |
80 … | + } | |
78 | 81 … | |
79 | - function autoPub () { | |
80 | - var invites = api.config.sync.load().autoinvites | |
81 | - if(!invites) { | |
82 | - console.log('no invites') | |
83 | - return | |
84 | - } | |
82 … | + function autoPub () { | |
83 … | + var invites = api.config.sync.load().autoinvites | |
84 … | + if (!invites) { | |
85 … | + console.log('no invites') | |
86 … | + return | |
87 … | + } | |
85 | 88 … | |
86 | - var self_id = api.config.sync.load().keys.id | |
87 | - api.sbot.async.friendsGet({dest: self_id}, function (err, friends) { | |
88 | - //if you have less than 5 followers, maybe use the autoinvite | |
89 | - if(Object.keys(friends).length <= 5) | |
90 | - invites.forEach(invite => { | |
91 | - console.log('using invite:', invite) | |
92 | - api.invite.async.autofollow(invite, (err, follows) => { | |
93 | - if (err) console.error('Autofollow error:', err) | |
94 | - else console.log('Autofollow success', follows) | |
95 | - }) | |
89 … | + var self_id = api.config.sync.load().keys.id | |
90 … | + api.sbot.async.friendsGet({dest: self_id}, function (err, friends) { | |
91 … | + // if you have less than 5 followers, maybe use the autoinvite | |
92 … | + if (Object.keys(friends).length <= 5) { | |
93 … | + invites.forEach(invite => { | |
94 … | + console.log('using invite:', invite) | |
95 … | + api.invite.async.autofollow(invite, (err, follows) => { | |
96 … | + if (err) console.error('Autofollow error:', err) | |
97 … | + else console.log('Autofollow success', follows) | |
96 | 98 … | }) |
97 | - else | |
98 | - console.log('no autoinvite - you have friends already') | |
99 | - }) | |
100 | - } | |
99 … | + }) | |
100 … | + } else { console.log('no autoinvite - you have friends already') } | |
101 … | + }) | |
101 | 102 … | } |
102 | 103 … | } |
103 | - | |
104 | -function logLocation (loc) { | |
105 | - console.groupCollapsed('%c location', 'color: #00f') | |
106 | - console.log(loc) | |
107 | - console.groupEnd() | |
108 | - | |
109 | -} |
app/html/blogCard.js | ||
---|---|---|
@@ -1,23 +1,22 @@ | ||
1 | 1 … | var nest = require('depnest') |
2 | 2 … | var h = require('mutant/h') |
3 | -var isString= require('lodash/isString') | |
4 | -var maxBy= require('lodash/maxBy') | |
5 | -var markdown = require('ssb-markdown') | |
6 | -var ref = require('ssb-ref') | |
7 | -var htmlEscape = require('html-escape') | |
3 … | +// var maxBy = require('lodash/maxBy') | |
4 … | +// var markdown = require('ssb-markdown') | |
5 … | +// var ref = require('ssb-ref') | |
6 … | +// var htmlEscape = require('html-escape') | |
8 | 7 … | |
9 | -function renderEmoji (emoji, url) { | |
10 | - if (!url) return ':' + emoji + ':' | |
11 | - return ` | |
12 | - <img | |
13 | - src="${htmlEscape(url)}" | |
14 | - alt=":${htmlEscape(emoji)}:" | |
15 | - title=":${htmlEscape(emoji)}:" | |
16 | - class="emoji" | |
17 | - > | |
18 | - ` | |
19 | -} | |
8 … | +// function renderEmoji (emoji, url) { | |
9 … | +// if (!url) return ':' + emoji + ':' | |
10 … | +// return ` | |
11 … | +// <img | |
12 … | +// src="${htmlEscape(url)}" | |
13 … | +// alt=":${htmlEscape(emoji)}:" | |
14 … | +// title=":${htmlEscape(emoji)}:" | |
15 … | +// class="emoji" | |
16 … | +// > | |
17 … | +// ` | |
18 … | +// } | |
20 | 19 … | |
21 | 20 … | exports.gives = nest('app.html.blogCard', true) |
22 | 21 … | |
23 | 22 … | exports.needs = nest({ |
@@ -25,99 +24,88 @@ | ||
25 | 24 … | 'history.sync.push': 'first', |
26 | 25 … | 'about.obs.color': 'first', |
27 | 26 … | 'about.obs.name': 'first', |
28 | 27 … | 'about.html.avatar': 'first', |
29 | - 'translations.sync.strings': 'first', | |
30 | 28 … | 'unread.sync.isUnread': 'first', |
31 | 29 … | 'message.html.channel': 'first', |
32 | 30 … | 'message.html.timeago': 'first', |
33 | 31 … | 'blob.sync.url': 'first', |
34 | 32 … | 'emoji.sync.url': 'first', |
35 | 33 … | |
36 | 34 … | 'blog.html.title': 'first', |
37 | 35 … | 'blog.html.summary': 'first', |
38 | - 'blog.html.thumbnail': 'first', | |
36 … | + 'blog.html.thumbnail': 'first' | |
39 | 37 … | }) |
40 | 38 … | |
41 | 39 … | exports.create = function (api) { |
40 … | + // render markdown, but don't support patchwork@2 style mentions or custom emoji right now. | |
41 … | + // function render (source) { | |
42 … | + // return markdown.block(source, { | |
43 … | + // emoji: (emoji) => { | |
44 … | + // return renderEmoji(emoji, api.emoji.sync.url(emoji)) | |
45 … | + // }, | |
46 … | + // toUrl: (id) => { | |
47 … | + // if (ref.isBlob(id)) return api.blob.sync.url(id) | |
48 … | + // return id | |
49 … | + // }, | |
50 … | + // imageLink: (id) => id | |
51 … | + // }) | |
52 … | + // } | |
42 | 53 … | |
43 | - //render markdown, but don't support patchwork@2 style mentions or custom emoji right now. | |
44 | - function render (source) { | |
45 | - return markdown.block(source, { | |
46 | - emoji: (emoji) => { | |
47 | - return renderEmoji(emoji, api.emoji.sync.url(emoji)) | |
48 | - }, | |
49 | - toUrl: (id) => { | |
50 | - if (ref.isBlob(id)) return api.blob.sync.url(id) | |
51 | - return id | |
52 | - }, | |
53 | - imageLink: (id) => id | |
54 | - }) | |
55 | - } | |
54 … | + // render the icon for a blog. | |
55 … | + // it would be more depjecty to split this | |
56 … | + // into two methods, one in a private plugin | |
57 … | + // one in a channel plugin | |
58 … | + // function blogIcon (msg) { | |
59 … | + // if (msg.value.private) { | |
60 … | + // const myId = api.keys.sync.id() | |
56 | 61 … | |
62 … | + // return msg.value.content.recps | |
63 … | + // .map(link => isString(link) ? link : link.link) | |
64 … | + // .filter(link => link !== myId) | |
65 … | + // .map(link => api.about.html.avatar) | |
66 … | + // } else if (msg.value.content.channel) { return '#' + msg.value.content.channel } | |
67 … | + // } | |
57 | 68 … | |
58 | - //render the icon for a blog. | |
59 | - //it would be more depjecty to split this | |
60 | - //into two methods, one in a private plugin | |
61 | - //one in a channel plugin | |
62 | - function blogIcon (msg) { | |
63 | - if(msg.value.private) { | |
64 | - const myId = api.keys.sync.id() | |
65 | - | |
66 | - return msg.value.content.recps | |
67 | - .map(link => isString(link) ? link : link.link) | |
68 | - .filter(link => link !== myId) | |
69 | - .map(link => api.about.html.avatar) | |
70 | - } | |
71 | - else if(msg.value.content.channel) | |
72 | - return '#'+msg.value.content.channel | |
73 | - } | |
74 | - | |
75 | - | |
76 | 69 … | // REFACTOR: move this to a template? |
77 | - function buildRecipientNames (blog) { | |
78 | - const myId = api.keys.sync.id() | |
70 … | + // function buildRecipientNames (blog) { | |
71 … | + // const myId = api.keys.sync.id() | |
79 | 72 … | |
80 | - return blog.value.content.recps | |
81 | - .map(link => isString(link) ? link : link.link) | |
82 | - .filter(link => link !== myId) | |
83 | - .map(api.about.obs.name) | |
84 | - } | |
73 … | + // return blog.value.content.recps | |
74 … | + // .map(link => isString(link) ? link : link.link) | |
75 … | + // .filter(link => link !== myId) | |
76 … | + // .map(api.about.obs.name) | |
77 … | + // } | |
85 | 78 … | |
86 | 79 … | return nest('app.html.blogCard', (blog, opts = {}) => { |
87 | - var strings = api.translations.sync.strings() | |
80 … | + if (!blog.value) return | |
88 | 81 … | |
89 | - if(!blog.value) return | |
82 … | + // const lastReply = blog.replies && maxBy(blog.replies, r => r.timestamp) | |
90 | 83 … | |
91 | - const lastReply = blog.replies && maxBy(blog.replies, r => r.timestamp) | |
92 | - | |
93 | 84 … | const goToBlog = () => api.history.sync.push(blog) |
94 | 85 … | const onClick = opts.onClick || goToBlog |
95 | - const id = `${blog.key.replace(/[^a-z0-9]/gi, '')}` //-${JSON.stringify(opts)}` | |
86 … | + const id = `${blog.key.replace(/[^a-z0-9]/gi, '')}` // -${JSON.stringify(opts)}` | |
96 | 87 … | // id is only here to help morphdom morph accurately |
97 | 88 … | |
98 | 89 … | const { content, author } = blog.value |
99 | 90 … | |
100 | 91 … | var img = h('Thumbnail') |
101 | 92 … | |
102 | 93 … | var image = api.blog.html.thumbnail(blog) |
103 | 94 … | |
104 | - if(image) { | |
105 | - //Hey this works! fit an image into a specific size (see blog-card.mcss) | |
106 | - //centered, and scaled to fit the square (works with both landscape and portrait!) | |
107 | - //This is functional css not opinionated css, so all embedded. | |
108 | - img.style = 'background-image: url("'+api.blob.sync.url(image)+'"); background-position:center; background-size: cover;' | |
109 | - | |
110 | - } | |
111 | - else { | |
112 | - var style = { 'background-color': api.about.obs.color(blog.key) } | |
95 … | + if (image) { | |
96 … | + // Hey this works! fit an image into a specific size (see blog-card.mcss) | |
97 … | + // centered, and scaled to fit the square (works with both landscape and portrait!) | |
98 … | + // This is functional css not opinionated css, so all embedded. | |
99 … | + img.style = 'background-image: url("' + api.blob.sync.url(image) + '"); background-position:center; background-size: cover;' | |
100 … | + } else { | |
101 … | + var style = { 'background-color': api.about.obs.color(blog.key) } | |
113 | 102 … | img = h('Thumbnail -empty', { style }, [ |
114 | 103 … | h('i.fa.fa-file-text-o') |
115 | 104 … | ]) |
116 | - | |
117 | 105 … | } |
118 | 106 … | |
119 | - const className = blog.unread ? '-unread': '' | |
107 … | + const className = blog.unread ? '-unread' : '' | |
120 | 108 … | |
121 | 109 … | var b = h('BlogCard', { id, className, 'ev-click': onClick }, [ |
122 | 110 … | h('div.context', [ |
123 | 111 … | api.about.html.avatar(author, 'tiny'), |
@@ -138,5 +126,4 @@ | ||
138 | 126 … | |
139 | 127 … | return b |
140 | 128 … | }) |
141 | 129 … | } |
142 | - |
app/html/channelCard.js | ||
---|---|---|
@@ -1,33 +1,20 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h, when } = require('mutant') | |
2 … | +const { h } = require('mutant') | |
3 | 3 … | |
4 | 4 … | exports.gives = nest('app.html.channelCard') |
5 | 5 … | |
6 | 6 … | exports.needs = nest({ |
7 | - 'keys.sync.id': 'first', | |
8 | 7 … | 'history.sync.push': 'first', |
9 | - 'translations.sync.strings': 'first', | |
10 | - 'channel.obs.subscribed': 'first', | |
11 | - 'channel.obs.isSubscribedTo': 'first', | |
12 | - 'channel.async.subscribe': 'first', | |
13 | - 'channel.async.unsubscribe': 'first', | |
14 | - 'channel.html.subscribe': 'first', | |
8 … | + 'channel.html.subscribe': 'first' | |
15 | 9 … | }) |
16 | 10 … | |
17 | 11 … | exports.create = function (api) { |
18 | - | |
19 | 12 … | return nest('app.html.channelCard', (channel) => { |
20 | - const strings = api.translations.sync.strings() | |
21 | - const myId = api.keys.sync.id() | |
22 | - const { subscribe, unsubscribe } = api.channel.async | |
23 | - const { isSubscribedTo } = api.channel.obs | |
24 | - const youSubscribe = isSubscribedTo(channel, myId) | |
25 | - | |
26 | 13 … | const goToChannel = () => { |
27 | 14 … | api.history.sync.push({ page: 'channelShow', channel: channel }) |
28 | 15 … | } |
29 | - | |
16 … | + | |
30 | 17 … | return h('ChannelCard', [ |
31 | 18 … | h('div.content', [ |
32 | 19 … | h('div.text', [ |
33 | 20 … | h('h2', {'ev-click': goToChannel}, channel), |
@@ -36,5 +23,4 @@ | ||
36 | 23 … | ]) |
37 | 24 … | ]) |
38 | 25 … | }) |
39 | 26 … | } |
40 | - |
app/html/comments.js | ||
---|---|---|
@@ -1,6 +1,6 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h, Array: MutantArray, Value, map, computed, when, resolve, throttle } = require('mutant') | |
2 … | +const { h, Value, map, computed, when, resolve, throttle } = require('mutant') | |
3 | 3 … | const get = require('lodash/get') |
4 | 4 … | |
5 | 5 … | exports.gives = nest('app.html.comments') |
6 | 6 … | |
@@ -14,9 +14,9 @@ | ||
14 | 14 … | 'message.html.timeago': 'first', |
15 | 15 … | 'message.html.likes': 'first', |
16 | 16 … | 'unread.sync.markRead': 'first', |
17 | 17 … | 'unread.sync.isUnread': 'first', |
18 | - 'translations.sync.strings': 'first', | |
18 … | + 'translations.sync.strings': 'first' | |
19 | 19 … | }) |
20 | 20 … | |
21 | 21 … | exports.create = (api) => { |
22 | 22 … | return nest('app.html.comments', comments) |
@@ -28,9 +28,9 @@ | ||
28 | 28 … | // TODO - move this up into Patchcore |
29 | 29 … | const messagesTree = computed(throttle(messages, 200), msgs => { |
30 | 30 … | return msgs |
31 | 31 … | .filter(msg => forkOf(msg) === undefined) |
32 | - .map(threadMsg => { | |
32 … | + .map(threadMsg => { | |
33 | 33 … | const nestedReplies = msgs.filter(msg => forkOf(msg) === threadMsg.key) |
34 | 34 … | threadMsg.replies = nestedReplies |
35 | 35 … | return threadMsg |
36 | 36 … | }) |
@@ -55,9 +55,9 @@ | ||
55 | 55 … | |
56 | 56 … | return h('Comments', [ |
57 | 57 … | // when(twoComposers, compose({ meta, shrink: true, canAttach: false })), |
58 | 58 … | map(messagesTree, msg => Comment(msg, root, branch)), |
59 | - compose({ meta, feedIdsInThread, shrink: false, canAttach: true, placeholder: strings.writeComment }), | |
59 … | + compose({ meta, feedIdsInThread, shrink: false, canAttach: true, placeholder: strings.writeComment }) | |
60 | 60 … | ]) |
61 | 61 … | } |
62 | 62 … | |
63 | 63 … | function Comment (msgObs, root, branch) { |
@@ -73,9 +73,9 @@ | ||
73 | 73 … | const { author, content } = msg.value |
74 | 74 … | |
75 | 75 … | // // TODO - move this upstream into patchcore:feed.obs.thread ?? |
76 | 76 … | // // OR change strategy to use forks |
77 | - // const backlinks = api.backlinks.obs.for(msg.key) | |
77 … | + // const backlinks = api.backlinks.obs.for(msg.key) | |
78 | 78 … | // const nestedReplies = computed(backlinks, backlinks => { |
79 | 79 … | // return backlinks.filter(backlinker => { |
80 | 80 … | // const { type, root } = backlinker.value.content |
81 | 81 … | // return type === 'post' && root === msg.key |
@@ -94,9 +94,9 @@ | ||
94 | 94 … | }, |
95 | 95 … | shrink: false, |
96 | 96 … | canAttach: true, |
97 | 97 … | canPreview: false, |
98 | - placeholder: strings.writeComment | |
98 … | + placeholder: strings.writeComment | |
99 | 99 … | }, toggleCompose) |
100 | 100 … | |
101 | 101 … | return h('Comment', { className }, [ |
102 | 102 … | h('div.left', api.about.html.avatar(author, 'tiny')), |
@@ -105,20 +105,20 @@ | ||
105 | 105 … | h('div.name', api.about.obs.name(author)), |
106 | 106 … | api.message.html.timeago(msg) |
107 | 107 … | ]), |
108 | 108 … | h('section.content', api.message.html.markdown(raw)), |
109 | - when(msgObs.replies, | |
110 | - h('section.replies', | |
109 … | + when(msgObs.replies, | |
110 … | + h('section.replies', | |
111 | 111 … | map(msgObs.replies, NestedComment) |
112 | 112 … | ) |
113 | 113 … | ), |
114 | 114 … | h('section.actions', [ |
115 | - h('div.reply', { 'ev-click': toggleCompose }, [ | |
116 | - h('i.fa.fa-commenting-o'), | |
115 … | + h('div.reply', { 'ev-click': toggleCompose }, [ | |
116 … | + h('i.fa.fa-commenting-o') | |
117 | 117 … | ]), |
118 | 118 … | api.message.html.likes(msg) |
119 | 119 … | ]), |
120 | - when(nestedReplyCompose, nestedReplyComposer), | |
120 … | + when(nestedReplyCompose, nestedReplyComposer) | |
121 | 121 … | ]) |
122 | 122 … | ]) |
123 | 123 … | } |
124 | 124 … | |
@@ -135,9 +135,9 @@ | ||
135 | 135 … | h('section.context', [ |
136 | 136 … | h('div.name', api.about.obs.name(author)), |
137 | 137 … | api.message.html.timeago(msg) |
138 | 138 … | ]), |
139 | - h('section.content', api.message.html.markdown(raw)), | |
139 … | + h('section.content', api.message.html.markdown(raw)) | |
140 | 140 … | ]) |
141 | 141 … | ]) |
142 | 142 … | |
143 | 143 … | api.message.html.markdown(raw) |
@@ -146,8 +146,4 @@ | ||
146 | 146 … | |
147 | 147 … | function forkOf (msg) { |
148 | 148 … | return get(msg, 'value.content.fork') |
149 | 149 … | } |
150 | - | |
151 | - | |
152 | - | |
153 | - |
app/html/header.js | ||
---|---|---|
@@ -1,28 +1,22 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | 2 … | const { h, computed, when } = require('mutant') |
3 | -const get = require('lodash/get') | |
4 | 3 … | const path = require('path') |
5 | 4 … | const { remote } = require('electron') |
6 | 5 … | |
7 | 6 … | exports.gives = nest('app.html.header') |
8 | 7 … | |
9 | -exports.needs = nest({ | |
10 | - 'keys.sync.id': 'first' | |
11 | -}) | |
12 | - | |
13 | 8 … | const SETTINGS_PAGES = [ |
14 | 9 … | 'settings', |
15 | - 'userEdit', | |
10 … | + 'userEdit' | |
16 | 11 … | ] |
17 | 12 … | |
18 | 13 … | exports.create = (api) => { |
19 | 14 … | return nest('app.html.header', (nav) => { |
20 | 15 … | const { location, push } = nav |
21 | - const myKey = api.keys.sync.id() | |
22 | 16 … | |
23 | 17 … | const loc = computed(location, location => { |
24 | - if (typeof location != 'object') return {} | |
18 … | + if (typeof location !== 'object') return {} | |
25 | 19 … | return location |
26 | 20 … | }) |
27 | 21 … | |
28 | 22 … | if (loc().page === 'splash') return |
@@ -56,19 +50,19 @@ | ||
56 | 50 … | ]), |
57 | 51 … | h('nav', [ |
58 | 52 … | h('img.feed', { |
59 | 53 … | src: when(isFeed, assetPath('feed_on.png'), assetPath('feed.png')), |
60 | - 'ev-click': () => push({page: 'blogIndex'}), | |
54 … | + 'ev-click': () => push({page: 'blogIndex'}) | |
61 | 55 … | }), |
62 | 56 … | h('img.addressBook', { |
63 | 57 … | src: when(isAddressBook, assetPath('address_bk_on.png'), assetPath('address_bk.png')), |
64 | 58 … | 'ev-click': () => push({page: 'addressBook'}) |
65 | 59 … | }), |
66 | 60 … | h('img.settings', { |
67 | 61 … | src: when(isSettings, assetPath('settings_on.png'), assetPath('settings.png')), |
68 | 62 … | 'ev-click': () => push({page: 'settings'}) |
69 | - }), | |
70 | - ]), | |
63 … | + }) | |
64 … | + ]) | |
71 | 65 … | ]) |
72 | 66 … | }) |
73 | 67 … | } |
74 | 68 … |
app/html/lightbox.js | ||
---|---|---|
@@ -1,12 +1,11 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h, computed, when, Value } = require('mutant') | |
2 … | +const { h, when, Value } = require('mutant') | |
3 | 3 … | |
4 | 4 … | exports.gives = nest('app.html.lightbox') |
5 | 5 … | |
6 | 6 … | exports.create = (api) => { |
7 | 7 … | return nest('app.html.lightbox', (content, isOpen) => { |
8 | - | |
9 | 8 … | if (typeof isOpen !== 'function') isOpen = Value(false) |
10 | 9 … | |
11 | 10 … | const openMe = () => isOpen.set(true) |
12 | 11 … | const closeMe = () => isOpen.set(false) |
@@ -21,5 +20,4 @@ | ||
21 | 20 … | |
22 | 21 … | return lb |
23 | 22 … | }) |
24 | 23 … | } |
25 | - |
app/html/link.js | ||
---|---|---|
@@ -3,16 +3,15 @@ | ||
3 | 3 … | |
4 | 4 … | exports.gives = nest('app.html.link') |
5 | 5 … | |
6 | 6 … | exports.needs = nest({ |
7 | - 'history.sync.push': 'first', | |
7 … | + 'history.sync.push': 'first' | |
8 | 8 … | }) |
9 | 9 … | |
10 | 10 … | exports.create = (api) => { |
11 | 11 … | return nest('app.html.link', (location, body) => { |
12 | - return h('Link', { | |
12 … | + return h('Link', { | |
13 | 13 … | 'ev-click': () => api.history.sync.push(location), |
14 | 14 … | className: typeof body === 'string' ? '-string' : '' |
15 | 15 … | }, body) |
16 | 16 … | }) |
17 | 17 … | } |
18 | - |
app/html/scroller.js | ||
---|---|---|
@@ -1,6 +1,5 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h } = require('mutant') | |
3 | 2 … | const pull = require('pull-stream') |
4 | 3 … | const Scroller = require('mutant-scroll') |
5 | 4 … | const next = require('pull-next-step') |
6 | 5 … | |
@@ -13,9 +12,9 @@ | ||
13 | 12 … | exports.create = function (api) { |
14 | 13 … | return nest('app.html.scroller', createScroller) |
15 | 14 … | |
16 | 15 … | function createScroller (opts = {}) { |
17 | - const { | |
16 … | + const { | |
18 | 17 … | stream, |
19 | 18 … | filter = () => pull.filter((msg) => true), |
20 | 19 … | indexProperty = ['value', 'timestamp'] |
21 | 20 … | } = opts |
@@ -43,39 +42,4 @@ | ||
43 | 42 … | // store = MutantArray(), |
44 | 43 … | // cb = (err) => { if (err) throw err } |
45 | 44 … | } |
46 | 45 … | } |
47 | - | |
48 | -function keyscroll (content) { | |
49 | - var curMsgEl | |
50 | - | |
51 | - if (!content) return () => {} | |
52 | - | |
53 | - content.addEventListener('click', onActivateChild, false) | |
54 | - content.addEventListener('focus', onActivateChild, true) | |
55 | - | |
56 | - function onActivateChild (ev) { | |
57 | - for (var el = ev.target; el; el = el.parentNode) { | |
58 | - if (el.parentNode === content) { | |
59 | - curMsgEl = el | |
60 | - return | |
61 | - } | |
62 | - } | |
63 | - } | |
64 | - | |
65 | - function selectChild (el) { | |
66 | - if (!el) { return } | |
67 | - | |
68 | - ;(el.scrollIntoViewIfNeeded || el.scrollIntoView).call(el) | |
69 | - el.focus() | |
70 | - curMsgEl = el | |
71 | - } | |
72 | - | |
73 | - return function scroll (d) { | |
74 | - selectChild((!curMsgEl || d === 'first') ? content.firstChild | |
75 | - : d < 0 ? curMsgEl.previousElementSibling || content.firstChild | |
76 | - : d > 0 ? curMsgEl.nextElementSibling || content.lastChild | |
77 | - : curMsgEl) | |
78 | - | |
79 | - return curMsgEl | |
80 | - } | |
81 | -} |
app/html/sideNav/sideNavAddressBook.js | ||
---|---|---|
@@ -1,14 +1,9 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h, computed, Struct, map, when, Dict, Array: MutantArray, Value, Set, resolve } = require('mutant') | |
3 | -const pull = require('pull-stream') | |
4 | -const next = require('pull-next-step') | |
5 | -const get = require('lodash/get') | |
6 | -const isEmpty = require('lodash/isEmpty') | |
7 | -const path = require('path') | |
2 … | +const { h, computed } = require('mutant') | |
8 | 3 … | |
9 | 4 … | exports.gives = nest({ |
10 | - 'app.html.sideNav': true, | |
5 … | + 'app.html.sideNav': true | |
11 | 6 … | }) |
12 | 7 … | |
13 | 8 … | exports.needs = nest({ |
14 | 9 … | // 'app.html.scroller': 'first', |
@@ -17,15 +12,15 @@ | ||
17 | 12 … | // 'feed.pull.private': 'first', |
18 | 13 … | 'history.sync.push': 'first', |
19 | 14 … | // 'message.html.subject': 'first', |
20 | 15 … | // 'sbot.obs.localPeers': 'first', |
21 | - 'translations.sync.strings': 'first', | |
16 … | + 'translations.sync.strings': 'first' | |
22 | 17 … | // 'unread.sync.isUnread': 'first' |
23 | 18 … | }) |
24 | 19 … | |
25 | 20 … | exports.create = (api) => { |
26 | 21 … | return nest({ |
27 | - 'app.html.sideNav': sideNav, | |
22 … | + 'app.html.sideNav': sideNav | |
28 | 23 … | }) |
29 | 24 … | |
30 | 25 … | function sideNav (location, relationships) { |
31 | 26 … | if (location.page !== 'addressBook') return |
@@ -37,35 +32,35 @@ | ||
37 | 32 … | // TODO - show local peers? |
38 | 33 … | // var nearby = api.sbot.obs.localPeers() |
39 | 34 … | |
40 | 35 … | return h('SideNav -addressBook', [ |
41 | - LevelOneSideNav(), | |
36 … | + LevelOneSideNav() | |
42 | 37 … | ]) |
43 | 38 … | |
44 | 39 … | function LevelOneSideNav () { |
45 | 40 … | return h('div.level.-one', [ |
46 | 41 … | h('section', [ |
47 | 42 … | SectionOption('search', [ |
48 | 43 … | h('Button -primary', {}, strings.action.addUser) |
49 | 44 … | ]), |
50 | - h('hr'), | |
45 … | + h('hr') | |
51 | 46 … | ]), |
52 | - | |
53 | - //Friends | |
47 … | + | |
48 … | + // Friends | |
54 | 49 … | h('section', [ |
55 | - h('header',strings.heading.people), | |
50 … | + h('header', strings.heading.people), | |
56 | 51 … | SectionOption('friends'), |
57 | 52 … | SectionOption('following'), |
58 | - SectionOption('followers'), | |
53 … | + SectionOption('followers') | |
59 | 54 … | ]) |
60 | 55 … | ]) |
61 | 56 … | } |
62 | 57 … | |
63 | 58 … | function SectionOption (section, body) { |
64 | 59 … | const className = section === location.section |
65 | 60 … | ? '-selected' |
66 | 61 … | : '' |
67 | - return h('Option', | |
62 … | + return h('Option', | |
68 | 63 … | { className, 'ev-click': goTo({page: 'addressBook', section }) }, |
69 | 64 … | body || defaulBody(section) |
70 | 65 … | ) |
71 | 66 … | |
@@ -82,6 +77,4 @@ | ||
82 | 77 … | return computed(relationships, rels => rels[relationshipType].length) |
83 | 78 … | } |
84 | 79 … | } |
85 | 80 … | } |
86 | - | |
87 | - |
app/html/sideNav/sideNavDiscovery.js | ||
---|---|---|
@@ -15,11 +15,11 @@ | ||
15 | 15 … | 'app.html.scroller': 'first', |
16 | 16 … | 'about.html.avatar': 'first', |
17 | 17 … | 'about.obs.name': 'first', |
18 | 18 … | 'feed.pull.private': 'first', |
19 | - 'keys.sync.id': 'first', | |
20 | 19 … | 'history.sync.push': 'first', |
21 | 20 … | 'history.obs.store': 'first', |
21 … | + 'keys.sync.id': 'first', | |
22 | 22 … | 'message.html.subject': 'first', |
23 | 23 … | 'message.sync.getParticipants': 'first', |
24 | 24 … | 'sbot.obs.localPeers': 'first', |
25 | 25 … | 'translations.sync.strings': 'first', |
@@ -31,48 +31,38 @@ | ||
31 | 31 … | var usersLastMsgCache = Dict() // { id: [ msgs ] } |
32 | 32 … | var unreadMsgsCache = Dict() // { id: [ msgs ] } |
33 | 33 … | |
34 | 34 … | return nest({ |
35 | - //intercept markUnread and remove them from the cache. | |
36 | - 'unread.sync.markUnread': function (msg) { | |
37 | - unreadMsgsCache.get(msg.value.content.root || msg.key) | |
38 | - .delete(msg.key) | |
39 | - unreadMsgsCache.get(msg.value.author) | |
40 | - .delete(msg.key) | |
41 | - }, | |
42 | - 'app.html.sideNav': sideNav, | |
35 … | + // intercept markUnread and remove them from the cache. | |
36 … | + 'unread.sync.markUnread': markUnread, | |
37 … | + 'app.html.sideNav': sideNav | |
43 | 38 … | }) |
44 | 39 … | |
45 | - function isMatch (location) { | |
46 | - if (location.page) { | |
47 | - if (location.page.match(/^blog/)) return true | |
48 | - if (location.page.match(/^thread/)) return true | |
49 | - if (location.page.match(/^user/)) return true | |
50 | - if (location.page.match(/^channel/)) return true | |
51 | - } | |
52 | - if (location.key) { | |
53 | - return true | |
54 | - } | |
55 | - return false | |
40 … | + function markUnread (msg) { | |
41 … | + unreadMsgsCache.get(msg.value.content.root || msg.key) | |
42 … | + .delete(msg.key) | |
43 … | + | |
44 … | + const participants = api.message.sync.getParticipants(msg) | |
45 … | + unreadMsgsCache.get(participants.key) | |
46 … | + .delete(msg.key) | |
56 | 47 … | } |
57 | 48 … | |
58 | 49 … | function sideNav (location) { |
59 | - if (!isMatch(location)) return | |
50 … | + if (!isSideNavDiscovery(location)) return | |
60 | 51 … | |
61 | 52 … | const strings = api.translations.sync.strings() |
62 | - const myKey = api.keys.sync.id() | |
63 | 53 … | var nearby = api.sbot.obs.localPeers() |
64 | 54 … | const getParticipants = api.message.sync.getParticipants |
55 … | + const myKey = api.keys.sync.id() | |
65 | 56 … | |
66 | 57 … | // Unread message counts |
67 | 58 … | function updateCache (cache, msg) { |
68 | - if(api.unread.sync.isUnread(msg)) | |
69 | - cache.add(msg.key) | |
70 | - else | |
71 | - cache.delete(msg.key) | |
59 … | + if (api.unread.sync.isUnread(msg)) { cache.add(msg.key) } else { cache.delete(msg.key) } | |
72 | 60 … | } |
73 | 61 … | |
74 | 62 … | function updateUnreadMsgsCache (msg) { |
63 … | + if (msg.value.author === myKey) return | |
64 … | + | |
75 | 65 … | const participantsKey = getParticipants(msg).key |
76 | 66 … | updateCache(getUnreadMsgsCache(participantsKey), msg) |
77 | 67 … | |
78 | 68 … | const rootKey = get(msg, 'value.content.root', msg.key) |
@@ -100,10 +90,10 @@ | ||
100 | 90 … | function isDiscoverLocation (loc) { |
101 | 91 … | const PAGES_UNDER_DISCOVER = ['blogIndex', 'blogShow', 'userShow'] |
102 | 92 … | |
103 | 93 … | if (PAGES_UNDER_DISCOVER.includes(location.page)) return true |
104 | - if (location.page === 'threadNew') return false | |
105 | - if (location.page === 'channelSubscriptions') return false | |
94 … | + if (location.page === 'threadNew') return false | |
95 … | + if (location.page === 'channelSubscriptions') return false | |
106 | 96 … | if (get(location, 'value.private') === undefined) return true |
107 | 97 … | return false |
108 | 98 … | } |
109 | 99 … | |
@@ -119,22 +109,22 @@ | ||
119 | 109 … | const lastMsg = recent.find(msg => msg.value.author === feedId) |
120 | 110 … | return lastMsg |
121 | 111 … | ? Object.assign(lastMsg, { participants: [feedId] }) |
122 | 112 … | : { page: 'threadNew', participants: [feedId] } |
123 | - }), | |
113 … | + }) | |
124 | 114 … | }), { comparer: (a, b) => a === b }), |
125 | 115 … | |
126 | 116 … | // --------------------- |
127 | - computed(nearby, n => !isEmpty(n) ? h('hr') : null), | |
117 … | + computed(nearby, n => !isEmpty(n) ? h('hr') : null), | |
128 | 118 … | |
129 | 119 … | // Discover |
130 | 120 … | Option({ |
131 | 121 … | imageEl: h('i', [ |
132 | 122 … | h('img', { src: path.join(__dirname, '../../../assets', 'discover.png') }) |
133 | 123 … | ]), |
134 | 124 … | label: strings.blogIndex.title, |
135 | 125 … | selected: isDiscoverLocation(location), |
136 | - location: { page: 'blogIndex' }, | |
126 … | + location: { page: 'blogIndex' } | |
137 | 127 … | }), |
138 | 128 … | |
139 | 129 … | // My subscriptions |
140 | 130 … | Option({ |
@@ -142,9 +132,9 @@ | ||
142 | 132 … | h('img', { src: path.join(__dirname, '../../../assets', 'my_subscribed.png') }) |
143 | 133 … | ]), |
144 | 134 … | label: strings.subscriptions.user, |
145 | 135 … | selected: location.page === 'channelSubscriptions' && location.scope === 'user', |
146 | - location: { page: 'channelSubscriptions', scope: 'user' }, | |
136 … | + location: { page: 'channelSubscriptions', scope: 'user' } | |
147 | 137 … | }), |
148 | 138 … | |
149 | 139 … | // Friends subscriptions |
150 | 140 … | Option({ |
@@ -152,9 +142,9 @@ | ||
152 | 142 … | h('img', { src: path.join(__dirname, '../../../assets', 'friends_subscribed.png') }) |
153 | 143 … | ]), |
154 | 144 … | label: strings.subscriptions.friends, |
155 | 145 … | selected: location.page === 'channelSubscriptions' && location.scope === 'friends', |
156 | - location: { page: 'channelSubscriptions', scope: 'friends' }, | |
146 … | + location: { page: 'channelSubscriptions', scope: 'friends' } | |
157 | 147 … | }) |
158 | 148 … | ] |
159 | 149 … | |
160 | 150 … | return api.app.html.scroller({ |
@@ -166,32 +156,31 @@ | ||
166 | 156 … | updateTop: updateRecentMsgCache, |
167 | 157 … | updateBottom: updateRecentMsgCache, |
168 | 158 … | render |
169 | 159 … | }) |
170 | - | |
160 … | + | |
171 | 161 … | function render (msgObs) { |
172 | 162 … | const msg = resolve(msgObs) |
173 | 163 … | const participants = getParticipants(msg) |
174 | 164 … | // TODO msg has been decorated with a flat participantsKey, could re-hydrate |
175 | 165 … | |
176 | 166 … | if (participants.length === 1 && nearby.has(participants.key)) return |
177 | - const locParticipantsKey = get(location, 'participants', []).join(' ') //TODO collect logic | |
167 … | + const locParticipantsKey = get(location, 'participants', []).join(' ') // TODO collect logic | |
178 | 168 … | |
179 | 169 … | if (participants.length === 1) { |
180 | 170 … | const author = participants[0] |
181 | 171 … | return Option({ |
182 | - //the number of threads with each peer | |
172 … | + // the number of threads with each peer | |
183 | 173 … | notifications: notifications(author), |
184 | 174 … | imageEl: api.about.html.avatar(author), |
185 | 175 … | label: api.about.obs.name(author), |
186 | 176 … | selected: locParticipantsKey === author, |
187 | 177 … | location: Object.assign({}, msg, { participants }) // TODO make obs? |
188 | 178 … | }) |
189 | - } | |
190 | - else { | |
179 … | + } else { | |
191 | 180 … | const rootMsg = get(msg, 'value.content.root', msg) |
192 | 181 … | return Option({ |
193 | - //the number of threads with each peer | |
182 … | + // the number of threads with each peer | |
194 | 183 … | notifications: notifications(participants), |
195 | 184 … | imageEl: participants.map(p => api.about.html.avatar(p, 'halfSmall')), |
196 | 185 … | label: api.message.html.subject(rootMsg), |
197 | 186 … | selected: locParticipantsKey === participants.key, |
@@ -200,19 +189,19 @@ | ||
200 | 189 … | } |
201 | 190 … | } |
202 | 191 … | |
203 | 192 … | function updateRecentMsgCache (soFar, newMsg) { |
204 | - soFar.transaction(() => { | |
193 … | + soFar.transaction(() => { | |
205 | 194 … | const { timestamp } = newMsg.value |
206 | - newMsg.participantsKey = getParticipants(newMsg).key | |
207 | - const index = indexOf(soFar, (msg) => newMsg.participantsKey === resolve(msg).participantsKey) | |
195 … | + newMsg.participants = getParticipants(newMsg) | |
196 … | + const index = indexOf(soFar, (msg) => newMsg.participants.key === resolve(msg).participants.key) | |
208 | 197 … | var object = Value() |
209 | 198 … | |
210 | 199 … | if (index >= 0) { |
211 | 200 … | // reference already exists, lets use this instead! |
212 | 201 … | const existingMsg = soFar.get(index) |
213 | 202 … | |
214 | - if (resolve(existingMsg).value.timestamp > timestamp) return | |
203 … | + if (resolve(existingMsg).value.timestamp > timestamp) return | |
215 | 204 … | // but abort if the existing reference is newer |
216 | 205 … | |
217 | 206 … | object = existingMsg |
218 | 207 … | soFar.deleteAt(index) |
@@ -227,15 +216,14 @@ | ||
227 | 216 … | soFar.push(object) |
228 | 217 … | } |
229 | 218 … | }) |
230 | 219 … | } |
231 | - | |
232 | 220 … | } |
233 | 221 … | |
234 | 222 … | function getUnreadMsgsCache (key) { |
235 | 223 … | var cache = unreadMsgsCache.get(key) |
236 | 224 … | if (!cache) { |
237 | - cache = Set () | |
225 … | + cache = Set() | |
238 | 226 … | unreadMsgsCache.put(key, cache) |
239 | 227 … | } |
240 | 228 … | return cache |
241 | 229 … | } |
@@ -255,9 +243,9 @@ | ||
255 | 243 … | |
256 | 244 … | const prepend = Option({ |
257 | 245 … | selected: page === 'threadNew', |
258 | 246 … | location: {page: 'threadNew', participants}, |
259 | - label: h('Button', strings.threadNew.action.new), | |
247 … | + label: h('Button', strings.threadNew.action.new) | |
260 | 248 … | }) |
261 | 249 … | |
262 | 250 … | var participantsKey = participants.join(' ') // TODO collect this repeated logic |
263 | 251 … | var userLastMsgCache = usersLastMsgCache.get(participantsKey) |
@@ -287,14 +275,14 @@ | ||
287 | 275 … | return Option({ |
288 | 276 … | notifications: notifications(rootMsg.key), |
289 | 277 … | label: api.message.html.subject(rootMsg), |
290 | 278 … | selected: rootMsg.key === root, |
291 | - location: Object.assign(rootMsg, { participants }), | |
279 … | + location: Object.assign(rootMsg, { participants }) | |
292 | 280 … | }) |
293 | 281 … | } |
294 | 282 … | |
295 | 283 … | function updateLastMsgCache (soFar, newMsg) { |
296 | - soFar.transaction(() => { | |
284 … | + soFar.transaction(() => { | |
297 | 285 … | const { timestamp } = newMsg.value |
298 | 286 … | const index = indexOf(soFar, (msg) => timestamp === resolve(msg).value.timestamp) |
299 | 287 … | |
300 | 288 … | if (index >= 0) return |
@@ -312,9 +300,9 @@ | ||
312 | 300 … | } |
313 | 301 … | } |
314 | 302 … | |
315 | 303 … | function Option ({ notifications = 0, imageEl, label, location, selected }) { |
316 | - const className = selected ? '-selected' : '' | |
304 … | + const className = selected ? '-selected' : '' | |
317 | 305 … | function goToLocation (e) { |
318 | 306 … | e.preventDefault() |
319 | 307 … | e.stopPropagation() |
320 | 308 … | api.history.sync.push(resolve(location)) |
@@ -330,9 +318,9 @@ | ||
330 | 318 … | return h('Option', { className }, [ |
331 | 319 … | h('div.circle', [ |
332 | 320 … | when(notifications, h('div.alert', notifications)), |
333 | 321 … | Array.isArray(imageEl) |
334 | - ? h('div.many-images', imageEl.slice(0,4)) // not ideal? not enough space to show more though | |
322 … | + ? h('div.many-images', imageEl.slice(0, 4)) // not ideal? not enough space to show more though | |
335 | 323 … | : imageEl |
336 | 324 … | ]), |
337 | 325 … | h('div.label', { 'ev-click': goToLocation }, label) |
338 | 326 … | ]) |
@@ -355,5 +343,17 @@ | ||
355 | 343 … | } |
356 | 344 … | return -1 |
357 | 345 … | } |
358 | 346 … | |
347 … | +function isSideNavDiscovery (location) { | |
348 … | + if (location.page) { | |
349 … | + if (location.page.match(/^blog/)) return true | |
350 … | + if (location.page.match(/^thread/)) return true | |
351 … | + if (location.page.match(/^user/)) return true | |
352 … | + if (location.page.match(/^channel/)) return true | |
353 … | + } | |
354 … | + if (location.key) { | |
355 … | + return true | |
356 … | + } | |
357 … | + return false | |
358 … | +} | |
359 | 359 … |
app/html/thread.js | ||
---|---|---|
@@ -16,10 +16,10 @@ | ||
16 | 16 … | }) |
17 | 17 … | |
18 | 18 … | exports.create = (api) => { |
19 | 19 … | return nest('app.html.thread', function (thread) { |
20 | - //catch any code that still uses this the old way... | |
21 | - if('string' === typeof thread) throw new Error('thread should be observable') | |
20 … | + // catch any code that still uses this the old way... | |
21 … | + if (typeof thread === 'string') throw new Error('thread should be observable') | |
22 | 22 … | const myId = api.keys.sync.id() |
23 | 23 … | const chunkedMessages = buildChunkedMessages(thread.messages) |
24 | 24 … | |
25 | 25 … | const threadView = h('Thread', |
@@ -53,9 +53,9 @@ | ||
53 | 53 … | function message (msg) { |
54 | 54 … | const raw = get(msg, 'value.content.text') |
55 | 55 … | var unread = api.unread.sync.isUnread(msg) ? ' -unread' : '' |
56 | 56 … | api.unread.sync.markRead(msg) |
57 | - return h('div.msg'+unread, api.message.html.markdown(raw)) | |
57 … | + return h('div.msg' + unread, api.message.html.markdown(raw)) | |
58 | 58 … | } |
59 | 59 … | |
60 | 60 … | threadView.subject = computed(thread.messages, msgs => { |
61 | 61 … | return get(msgs, '[0].value.content.subject') |
@@ -98,8 +98,4 @@ | ||
98 | 98 … | function isSameAuthor (msgA, msgB) { |
99 | 99 … | // TODO (mix) use lodash/get |
100 | 100 … | return msgA.value.author === msgB.value.author |
101 | 101 … | } |
102 | - | |
103 | - | |
104 | - | |
105 | - |
app/html/topNav/topNavAddressBook.js | ||
---|---|---|
@@ -1,29 +1,27 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h, computed, when } = require('mutant') | |
3 | -const get = require('lodash/get') | |
2 … | +const { h } = require('mutant') | |
4 | 3 … | |
5 | 4 … | exports.gives = nest('app.html.topNav') |
6 | 5 … | |
7 | 6 … | exports.needs = nest({ |
8 | - 'translations.sync.strings': 'first', | |
7 … | + 'translations.sync.strings': 'first' | |
9 | 8 … | }) |
10 | 9 … | |
11 | 10 … | exports.create = (api) => { |
12 | 11 … | return nest('app.html.topNav', (location, input) => { |
13 | - if (location.page !== 'addressBook') return | |
12 … | + if (location.page !== 'addressBook') return | |
14 | 13 … | |
15 | 14 … | const strings = api.translations.sync.strings() |
16 | 15 … | |
17 | 16 … | return h('TopNav -addressBook', [ |
18 | 17 … | h('div.search', [ |
19 | 18 … | h('i.fa.fa-search'), |
20 | - h('input', { | |
19 … | + h('input', { | |
21 | 20 … | placeholder: strings.addressBook.action.find[location.section], |
22 | 21 … | autofocus: 'autofocus', |
23 | - 'ev-input': e => input.set(e.target.value) | |
24 | - }), | |
22 … | + 'ev-input': e => input.set(e.target.value) | |
23 … | + }) | |
25 | 24 … | ]) |
26 | 25 … | ]) |
27 | 26 … | }) |
28 | 27 … | } |
29 | - |
app/html/topNav/topNavBlog.js | ||
---|---|---|
@@ -1,36 +1,34 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h, computed, when } = require('mutant') | |
3 | -const get = require('lodash/get') | |
2 … | +const { h } = require('mutant') | |
4 | 3 … | |
5 | 4 … | exports.gives = nest('app.html.topNav') |
6 | 5 … | |
7 | 6 … | exports.needs = nest({ |
8 | 7 … | 'history.sync.push': 'first', |
9 | - 'translations.sync.strings': 'first', | |
8 … | + 'translations.sync.strings': 'first' | |
10 | 9 … | }) |
11 | 10 … | |
12 | 11 … | exports.create = (api) => { |
13 | 12 … | return nest('app.html.topNav', (location) => { |
14 | 13 … | const strings = api.translations.sync.strings() |
15 | 14 … | const goTo = (loc) => () => api.history.sync.push(loc) |
16 | 15 … | |
17 | - if (!['blogIndex', 'blogSearch'].includes(location.page)) return | |
16 … | + if (!['blogIndex', 'blogSearch'].includes(location.page)) return | |
18 | 17 … | |
19 | 18 … | return h('TopNav -blog', [ |
20 | - h('div.left', [ | |
21 | - h('div', { | |
19 … | + h('div.left', [ | |
20 … | + h('div', { | |
22 | 21 … | className: location.page === 'blogIndex' ? '-active' : '', |
23 | - 'ev-click': goTo({ page: 'blogIndex' }) | |
22 … | + 'ev-click': goTo({ page: 'blogIndex' }) | |
24 | 23 … | }, strings.topNav.blogsAll), |
25 | - h('div', { | |
24 … | + h('div', { | |
26 | 25 … | className: location.page === 'blogSearch' ? '-active' : '', |
27 | - 'ev-click': goTo({ page: 'blogSearch' }) | |
28 | - }, strings.topNav.blogSearch), | |
26 … | + 'ev-click': goTo({ page: 'blogSearch' }) | |
27 … | + }, strings.topNav.blogSearch) | |
29 | 28 … | ]), |
30 | - h('div.right', [ | |
31 | - h('Button -strong', { 'ev-click': () => api.history.sync.push({ page: 'blogNew' }) }, strings.blogNew.actions.writeBlog), | |
29 … | + h('div.right', [ | |
30 … | + h('Button -strong', { 'ev-click': () => api.history.sync.push({ page: 'blogNew' }) }, strings.blogNew.actions.writeBlog) | |
32 | 31 … | ]) |
33 | 32 … | ]) |
34 | 33 … | }) |
35 | 34 … | } |
36 | - |
app/html/topNav/zz_topNavBack.js | ||
---|---|---|
@@ -1,29 +1,27 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h, computed, when } = require('mutant') | |
3 | -const get = require('lodash/get') | |
2 … | +const { h } = require('mutant') | |
4 | 3 … | |
5 | 4 … | exports.gives = nest('app.html.topNav') |
6 | 5 … | |
7 | 6 … | exports.needs = nest({ |
8 | 7 … | 'history.sync.back': 'first', |
9 | - 'translations.sync.strings': 'first', | |
8 … | + 'translations.sync.strings': 'first' | |
10 | 9 … | }) |
11 | 10 … | |
12 | 11 … | exports.create = (api) => { |
13 | 12 … | return nest('app.html.topNav', (location) => { |
14 | 13 … | // const strings = api.translations.sync.strings() |
15 | 14 … | const back = () => api.history.sync.back() |
16 | 15 … | |
17 | 16 … | return h('TopNav -back', [ |
18 | - h('div.left', [ | |
19 | - h('div', { 'ev-click': back }, [ | |
20 | - h('i.fa.fa-chevron-left'), | |
17 … | + h('div.left', [ | |
18 … | + h('div', { 'ev-click': back }, [ | |
19 … | + h('i.fa.fa-chevron-left') | |
21 | 20 … | // strings.blogIndex.title |
22 | - ]), | |
21 … | + ]) | |
23 | 22 … | ]), |
24 | - h('div.right', [ | |
23 … | + h('div.right', [ | |
25 | 24 … | ]) |
26 | 25 … | ]) |
27 | 26 … | }) |
28 | 27 … | } |
29 | - |
app/index.js | ||
---|---|---|
@@ -1,7 +1,7 @@ | ||
1 | 1 … | module.exports = { |
2 | 2 … | async: { |
3 | - catchLinkClick: require('./async/catch-link-click'), | |
3 … | + catchLinkClick: require('./async/catch-link-click') | |
4 | 4 … | }, |
5 | 5 … | html: { |
6 | 6 … | app: require('./html/app'), |
7 | 7 … | comments: require('./html/comments'), |
@@ -13,14 +13,14 @@ | ||
13 | 13 … | channelCard: require('./html/channelCard'), |
14 | 14 … | topNav: { |
15 | 15 … | topNavAddressBook: require('./html/topNav/topNavAddressBook'), |
16 | 16 … | topNavBlog: require('./html/topNav/topNavBlog'), |
17 | - topNavBack: require('./html/topNav/zz_topNavBack'), | |
17 … | + topNavBack: require('./html/topNav/zz_topNavBack') | |
18 | 18 … | }, |
19 | 19 … | scroller: require('./html/scroller'), |
20 | 20 … | sideNav: { |
21 | 21 … | addressBook: require('./html/sideNav/sideNavAddressBook'), |
22 | - discovery: require('./html/sideNav/sideNavDiscovery'), | |
22 … | + discovery: require('./html/sideNav/sideNavDiscovery') | |
23 | 23 … | }, |
24 | 24 … | warning: require('./html/warning'), |
25 | 25 … | }, |
26 | 26 … | obs: { |
@@ -47,16 +47,15 @@ | ||
47 | 47 … | // userFind: require('./page/userFind'), |
48 | 48 … | userShow: require('./page/userShow'), |
49 | 49 … | splash: require('./page/splash'), |
50 | 50 … | threadNew: require('./page/threadNew'), |
51 | - threadShow: require('./page/threadShow'), | |
51 … | + threadShow: require('./page/threadShow') | |
52 | 52 … | }, |
53 | 53 … | sync: { |
54 | 54 … | initialize: { |
55 | 55 … | clickHandler: require('./sync/initialize/clickHandler'), |
56 | 56 … | styles: require('./sync/initialize/styles'), |
57 | 57 … | suggests: require('./sync/initialize/suggests'), |
58 | - zoomMemory: require('./sync/initialize/zoomMemory'), | |
59 | - }, | |
58 … | + zoomMemory: require('./sync/initialize/zoomMemory') | |
59 … | + } | |
60 | 60 … | } |
61 | 61 … | } |
62 | - |
app/page/addressBook.js | ||
---|---|---|
@@ -3,9 +3,9 @@ | ||
3 | 3 … | const pull = require('pull-stream') |
4 | 4 … | |
5 | 5 … | exports.gives = nest('app.page.addressBook') |
6 | 6 … | |
7 | -//declare consts to avoid magic-string errors | |
7 … | +// declare consts to avoid magic-string errors | |
8 | 8 … | const FRIENDS = 'friends' |
9 | 9 … | const FOLLOWING = 'following' |
10 | 10 … | const FOLLOWERS = 'followers' |
11 | 11 … | const SEARCH = 'search' |
@@ -21,15 +21,15 @@ | ||
21 | 21 … | 'contact.html.follow': 'first', |
22 | 22 … | 'contact.obs.relationships': 'first', |
23 | 23 … | 'history.sync.push': 'first', |
24 | 24 … | 'keys.sync.id': 'first', |
25 | - 'translations.sync.strings': 'first', | |
25 … | + 'translations.sync.strings': 'first' | |
26 | 26 … | }) |
27 | 27 … | |
28 | 28 … | exports.create = (api) => { |
29 | 29 … | return nest('app.page.addressBook', function (location) { |
30 | 30 … | // location here can expected to be: { page: 'addressBook'} |
31 | - | |
31 … | + | |
32 | 32 … | const strings = api.translations.sync.strings() |
33 | 33 … | const myKey = api.keys.sync.id() |
34 | 34 … | const relationships = api.contact.obs.relationships(myKey) |
35 | 35 … | |
@@ -40,18 +40,15 @@ | ||
40 | 40 … | const input = Value() |
41 | 41 … | |
42 | 42 … | const suggester = api.about.async.suggest() |
43 | 43 … | const users = computed([relationships, input], (relationships, input) => { |
44 | - if (section === SEARCH) | |
45 | - return suggester(input) | |
46 | - else { | |
44 … | + if (section === SEARCH) { return suggester(input) } else { | |
47 | 45 … | const sectionRels = relationships[section] |
48 | 46 … | if (!input) { |
49 | 47 … | return sectionRels // show all e.g. friends |
50 | 48 … | .reverse() |
51 | 49 … | .map(id => { return { id, title: api.about.obs.name(id) } }) |
52 | - } | |
53 | - else { // show suggestions, and filter just the ones we want e.g. friends | |
50 … | + } else { // show suggestions, and filter just the ones we want e.g. friends | |
54 | 51 … | return suggester(input, relationships.followers) // add extraIds to suggester |
55 | 52 … | .filter(user => sectionRels.includes(user.id)) |
56 | 53 … | } |
57 | 54 … | } |
@@ -62,9 +59,9 @@ | ||
62 | 59 … | return h('Page -addressBook', [ |
63 | 60 … | api.app.html.sideNav(location, relationships), |
64 | 61 … | h('Scroller.content', [ |
65 | 62 … | h('section.top', [ |
66 | - api.app.html.topNav(location, input), | |
63 … | + api.app.html.topNav(location, input) | |
67 | 64 … | ]), |
68 | 65 … | h('section.content', [ |
69 | 66 … | h('div.results', map(users, user => { |
70 | 67 … | return h('div.result', { 'ev-click': goTo({page: 'userShow', feed: user.id}) }, [ |
@@ -72,11 +69,10 @@ | ||
72 | 69 … | h('div.alias', user.title), |
73 | 70 … | // h('pre.key', user.id), |
74 | 71 … | api.contact.html.follow(user.id) |
75 | 72 … | ]) |
76 | - })), | |
73 … | + })) | |
77 | 74 … | ]) |
78 | 75 … | ]) |
79 | 76 … | ]) |
80 | 77 … | }) |
81 | 78 … | } |
82 | - |
app/page/blogIndex.js | ||
---|---|---|
@@ -20,9 +20,9 @@ | ||
20 | 20 … | |
21 | 21 … | exports.create = (api) => { |
22 | 22 … | return nest('app.page.blogIndex', function (location) { |
23 | 23 … | // location here can expected to be: { page: 'blogIndex'} |
24 | - | |
24 … | + | |
25 | 25 … | var strings = api.translations.sync.strings() |
26 | 26 … | |
27 | 27 … | var blogs = api.app.html.scroller({ |
28 | 28 … | classList: ['content'], |
@@ -50,15 +50,14 @@ | ||
50 | 50 … | blogs |
51 | 51 … | ]) |
52 | 52 … | }) |
53 | 53 … | |
54 | - | |
55 | 54 … | function update (soFar, newBlog) { |
56 | - soFar.transaction(() => { | |
55 … | + soFar.transaction(() => { | |
57 | 56 … | const { timestamp } = newBlog.value |
58 | 57 … | |
59 | 58 … | var object = newBlog // Value(newBlog) |
60 | - | |
59 … | + | |
61 | 60 … | // Orders by: time received |
62 | 61 … | const justOlderPosition = indexOf(soFar, (msg) => newBlog.timestamp > resolve(msg).timestamp) |
63 | 62 … | |
64 | 63 … | // Orders by: time published BUT the messagesByType stream streams _by time received_ |
@@ -72,14 +71,12 @@ | ||
72 | 71 … | } |
73 | 72 … | }) |
74 | 73 … | } |
75 | 74 … | |
76 | - | |
77 | 75 … | function render (blog) { |
78 | 76 … | const { recps, channel } = blog.value.content |
79 | 77 … | var onClick |
80 | - if (channel && !recps) | |
81 | - onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' })) | |
78 … | + if (channel && !recps) { onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' })) } | |
82 | 79 … | return api.app.html.blogCard(blog, { onClick }) |
83 | 80 … | } |
84 | 81 … | } |
85 | 82 … | |
@@ -90,5 +87,4 @@ | ||
90 | 87 … | } |
91 | 88 … | } |
92 | 89 … | return -1 |
93 | 90 … | } |
94 | - |
app/page/blogIndex.mcss | ||
---|---|---|
@@ -9,8 +9,12 @@ | ||
9 | 9 … | section.content { |
10 | 10 … | div.BlogCard { |
11 | 11 … | flex-basis: 100% |
12 | 12 … | border-bottom: 1px solid rgba(0,0,0, .1) |
13 … | + | |
14 … | + :last-child { | |
15 … | + border-bottom: none | |
16 … | + } | |
13 | 17 … | } |
14 | 18 … | } |
15 | 19 … | |
16 | 20 … | section.bottom { |
app/page/blogNew.js | ||
---|---|---|
@@ -27,9 +27,9 @@ | ||
27 | 27 … | const meta = Struct({ |
28 | 28 … | type: 'blog', |
29 | 29 … | channel: Value(), |
30 | 30 … | title: Value(), |
31 | - summary: Value(), | |
31 … | + summary: Value() | |
32 | 32 … | }) |
33 | 33 … | |
34 | 34 … | const composer = api.message.html.compose( |
35 | 35 … | { |
@@ -43,16 +43,16 @@ | ||
43 | 43 … | |
44 | 44 … | var stream = pull.values([content.text]) |
45 | 45 … | delete content.text |
46 | 46 … | api.sbot.async.addBlob(stream, function (err, hash) { |
47 | - if(err) return cb(err) | |
48 | - if(!hash) throw new Error('missing hash') | |
47 … | + if (err) return cb(err) | |
48 … | + if (!hash) throw new Error('missing hash') | |
49 | 49 … | content.blog = hash |
50 | 50 … | cb(null, content) |
51 | 51 … | }) |
52 | 52 … | } |
53 | 53 … | }, |
54 | - (err, msg) => api.history.sync.push(err ? err : { page: 'blogIndex' }) | |
54 … | + (err, msg) => api.history.sync.push(err || { page: 'blogIndex' }) | |
55 | 55 … | ) |
56 | 56 … | |
57 | 57 … | const channelInput = h('input', { |
58 | 58 … | 'ev-input': e => meta.channel.set(e.target.value), |
@@ -71,16 +71,16 @@ | ||
71 | 71 … | h('div.label', strings.blogNew.field.title), |
72 | 72 … | h('input', { |
73 | 73 … | 'ev-input': e => meta.title.set(e.target.value), |
74 | 74 … | placeholder: strings.blogNew.field.title |
75 | - }), | |
75 … | + }) | |
76 | 76 … | ]), |
77 | 77 … | h('div.field -summary', [ |
78 | 78 … | h('div.label', strings.blogNew.field.summary), |
79 | 79 … | h('input', { |
80 | 80 … | 'ev-input': e => meta.summary.set(e.target.value), |
81 | 81 … | placeholder: strings.blogNew.field.summary |
82 | - }), | |
82 … | + }) | |
83 | 83 … | ]), |
84 | 84 … | composer |
85 | 85 … | ]) |
86 | 86 … | ]) |
@@ -93,10 +93,9 @@ | ||
93 | 93 … | s.value = s.value.replace(/^#/, '') // strip the defualt # prefix here |
94 | 94 … | return s |
95 | 95 … | }) |
96 | 96 … | .map(s => { |
97 | - if (s.subtitle === 'subscribed') | |
98 | - s.subtitle = h('i.fa.fa-heart') // TODO - translation-friendly subscribed | |
97 … | + if (s.subtitle === 'subscribed') { s.subtitle = h('i.fa.fa-heart') } // TODO - translation-friendly subscribed | |
99 | 98 … | return s |
100 | 99 … | }) |
101 | 100 … | |
102 | 101 … | // HACK add the input text if it's not an option already |
@@ -117,9 +116,4 @@ | ||
117 | 116 … | |
118 | 117 … | return page |
119 | 118 … | } |
120 | 119 … | } |
121 | - | |
122 | - | |
123 | - | |
124 | - | |
125 | - |
app/page/blogSearch.js | ||
---|---|---|
@@ -20,31 +20,31 @@ | ||
20 | 20 … | }) |
21 | 21 … | |
22 | 22 … | exports.create = (api) => { |
23 | 23 … | return nest('app.page.blogSearch', blogSearch) |
24 | - | |
24 … | + | |
25 | 25 … | function blogSearch (location) { |
26 | 26 … | // location here can expected to be: { page: 'blogSearch'} |
27 | 27 … | // OR { page: 'blogSearch', channel: 'scuttlebutt', searchVal: 'scutt'} |
28 | - | |
28 … | + | |
29 | 29 … | var strings = api.translations.sync.strings() |
30 | 30 … | |
31 | 31 … | var searchVal = Value(resolve(location.searchVal) || resolve(location.channel) || '') |
32 | - var searchResults = computed([api.channel.obs.recent(), searchVal], (channels, val) => { | |
32 … | + var searchResults = computed([api.channel.obs.recent(), searchVal], (channels, val) => { | |
33 | 33 … | if (val.length < 2) return [] |
34 | 34 … | |
35 | 35 … | return channels.filter(c => c.toLowerCase().indexOf(val.toLowerCase()) > -1) |
36 | 36 … | }) |
37 | 37 … | var searchField = h('div.search', [ |
38 | 38 … | h('div.input', [ |
39 | 39 … | h('i.fa.fa-search'), |
40 | - h('input', { | |
40 … | + h('input', { | |
41 | 41 … | 'ev-input': e => searchVal.set(e.target.value), |
42 | - value: searchVal | |
42 … | + value: searchVal | |
43 | 43 … | }) |
44 | 44 … | ]), |
45 | - when(searchResults, | |
46 | - h('div.results', map(searchResults, channel => { | |
45 … | + when(searchResults, | |
46 … | + h('div.results', map(searchResults, channel => { | |
47 | 47 … | const classList = channel === location.channel |
48 | 48 … | ? ['-channelActive'] |
49 | 49 … | : '' |
50 | 50 … | const newLocation = { |
@@ -89,16 +89,12 @@ | ||
89 | 89 … | blogs |
90 | 90 … | ]) |
91 | 91 … | } |
92 | 92 … | |
93 | - | |
94 | 93 … | function render (blog) { |
95 | 94 … | const { recps, channel } = blog.value.content |
96 | 95 … | var onClick |
97 | - if (channel && !recps) | |
98 | - onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' })) | |
96 … | + if (channel && !recps) { onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' })) } | |
99 | 97 … | |
100 | 98 … | return api.app.html.blogCard(blog, { onClick }) |
101 | 99 … | } |
102 | 100 … | } |
103 | - | |
104 | - |
app/page/blogSearch.mcss | ||
---|---|---|
@@ -47,8 +47,12 @@ | ||
47 | 47 … | div.BlogCard { |
48 | 48 … | flex-basis: 100% |
49 | 49 … | |
50 | 50 … | border-bottom: 1px solid gainsboro |
51 … | + | |
52 … | + :last-child { | |
53 … | + border-bottom: none | |
54 … | + } | |
51 | 55 … | } |
52 | 56 … | } |
53 | 57 … | |
54 | 58 … | section.bottom { |
app/page/blogShow.js | ||
---|---|---|
@@ -1,9 +1,6 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h, computed, when } = require('mutant') | |
3 | -const { title: getTitle } = require('markdown-summary') | |
4 | -const last = require('lodash/last') | |
5 | -const get = require('lodash/get') | |
2 … | +const { h } = require('mutant') | |
6 | 3 … | |
7 | 4 … | exports.gives = nest('app.page.blogShow') |
8 | 5 … | |
9 | 6 … | exports.needs = nest({ |
@@ -14,31 +11,29 @@ | ||
14 | 11 … | 'app.html.sideNav': 'first', |
15 | 12 … | 'contact.html.follow': 'first', |
16 | 13 … | 'message.html.channel': 'first', |
17 | 14 … | 'message.html.likes': 'first', |
18 | - 'message.html.markdown': 'first', | |
19 | 15 … | 'message.html.timeago': 'first', |
20 | 16 … | 'feed.obs.thread': 'first', |
21 | 17 … | 'blog.html.title': 'first', |
22 | - 'blog.html.content': 'first', | |
18 … | + 'blog.html.content': 'first' | |
23 | 19 … | }) |
24 | 20 … | |
25 | 21 … | exports.create = (api) => { |
26 | 22 … | return nest('app.page.blogShow', blogShow) |
27 | 23 … | |
28 | 24 … | function blogShow (blogMsg) { |
29 | 25 … | // blogMsg = a thread (message, may be decorated with replies) |
30 | 26 … | |
31 | - const { author, content } = blogMsg.value | |
27 … | + const { author } = blogMsg.value | |
32 | 28 … | |
33 | 29 … | const blog = api.blog.html.content(blogMsg) |
34 | 30 … | const title = api.blog.html.title(blogMsg) |
35 | 31 … | |
36 | 32 … | const thread = api.feed.obs.thread(blogMsg.key) |
37 | 33 … | const comments = api.app.html.comments(thread) |
38 | - const branch = thread.lastId | |
39 | 34 … | |
40 | - const { timeago, channel, markdown } = api.message.html | |
35 … | + const { timeago, channel } = api.message.html | |
41 | 36 … | |
42 | 37 … | return h('Page -blogShow', [ |
43 | 38 … | api.app.html.sideNav({ page: 'blogShow' }), // HACK to highlight discover |
44 | 39 … | h('Scroller.content', [ |
@@ -57,20 +52,15 @@ | ||
57 | 52 … | h('div.leftCol', api.about.html.avatar(author, 'medium')), |
58 | 53 … | h('div.rightCol', [ |
59 | 54 … | h('div.name', api.about.obs.name(author)), |
60 | 55 … | api.contact.html.follow(author) |
61 | - ]), | |
56 … | + ]) | |
62 | 57 … | ]) |
63 | 58 … | ]), |
64 | 59 … | h('div.break', h('hr')), |
65 | 60 … | h('section.blog', blog), |
66 | - comments, | |
67 | - ]), | |
61 … | + comments | |
62 … | + ]) | |
68 | 63 … | ]) |
69 | 64 … | ]) |
70 | 65 … | } |
71 | 66 … | } |
72 | - | |
73 | - | |
74 | - | |
75 | - | |
76 | - |
app/page/channel.js | ||
---|---|---|
@@ -10,17 +10,16 @@ | ||
10 | 10 … | 'app.html.link': 'first', |
11 | 11 … | 'app.html.blogCard': 'first', |
12 | 12 … | 'history.sync.push': 'first', |
13 | 13 … | 'state.obs.channel': 'first', |
14 | - 'translations.sync.strings': 'first', | |
14 … | + 'translations.sync.strings': 'first' | |
15 | 15 … | }) |
16 | 16 … | |
17 | -function latestUpdate(thread) { | |
17 … | +function latestUpdate (thread) { | |
18 | 18 … | var m = thread.timestamp |
19 | - if(!thread.replies) return m | |
19 … | + if (!thread.replies) return m | |
20 | 20 … | |
21 | - for(var i = 0; i < thread.replies.length; i++) | |
22 | - m = Math.max(thread.replies[i].timestamp, m) | |
21 … | + for (var i = 0; i < thread.replies.length; i++) { m = Math.max(thread.replies[i].timestamp, m) } | |
23 | 22 … | return m |
24 | 23 … | } |
25 | 24 … | |
26 | 25 … | exports.create = (api) => { |
@@ -29,9 +28,9 @@ | ||
29 | 28 … | var strings = api.translations.sync.strings() |
30 | 29 … | |
31 | 30 … | var channelObs = api.state.obs.channel(channel) |
32 | 31 … | |
33 | - //disable "Show More" button when we are at the last thread. | |
32 … | + // disable "Show More" button when we are at the last thread. | |
34 | 33 … | var disableShowMore = computed([channelObs], threads => !!threads.ended) |
35 | 34 … | |
36 | 35 … | var updates = h('div.threads', []) |
37 | 36 … | var threadsHtmlObs = More( |
@@ -56,11 +55,9 @@ | ||
56 | 55 … | Link({ page: 'threadNew', channel }, h('Button -strong', strings.channel.action.newThread)), |
57 | 56 … | h('div.content', [ threadsHtmlObs ]), |
58 | 57 … | h('Button -showMore', { |
59 | 58 … | 'ev-click': threadsHtmlObs.more, |
60 | - disabled: disableShowMore | |
59 … | + disabled: disableShowMore | |
61 | 60 … | }, [strings.showMore]) |
62 | 61 … | ]) |
63 | 62 … | }) |
64 | 63 … | } |
65 | - | |
66 | - |
app/page/channelShow.js | ||
---|---|---|
@@ -1,6 +1,6 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h, Value, computed, map, when, resolve } = require('mutant') | |
2 … | +const { h } = require('mutant') | |
3 | 3 … | const pull = require('pull-stream') |
4 | 4 … | |
5 | 5 … | exports.gives = nest('app.page.channelShow') |
6 | 6 … | |
@@ -8,33 +8,31 @@ | ||
8 | 8 … | 'app.html.sideNav': 'first', |
9 | 9 … | 'app.html.topNav': 'first', |
10 | 10 … | 'app.html.scroller': 'first', |
11 | 11 … | 'app.html.blogCard': 'first', |
12 … | + 'channel.html.subscribe': 'first', | |
12 | 13 … | 'feed.pull.channel': 'first', |
13 | 14 … | 'history.sync.push': 'first', |
14 | - 'translations.sync.strings': 'first', | |
15 | - 'channel.obs.recent': 'first', | |
16 | - 'channel.html.subscribe': 'first' | |
15 … | + 'translations.sync.strings': 'first' | |
17 | 16 … | }) |
18 | 17 … | |
19 | 18 … | exports.create = (api) => { |
20 | 19 … | return nest('app.page.channelShow', channelShow) |
21 | 20 … | |
22 | - function channelShow(location) { | |
23 | - var strings = api.translations.sync.strings() | |
21 … | + function channelShow (location) { | |
22 … | + const strings = api.translations.sync.strings() | |
23 … | + const { channel } = location | |
24 | 24 … | |
25 | - var searchVal = resolve(location.channel) | |
26 | - | |
27 | - createStream = api.feed.pull.channel(location.channel) | |
25 … | + createStream = api.feed.pull.channel(channel) | |
28 | 26 … | |
29 | 27 … | const prepend = [ |
30 | 28 … | api.app.html.topNav(location), |
31 | 29 … | h('section.about', [ |
32 | - h('h1', location.channel), | |
30 … | + h('h1', channel), | |
33 | 31 … | h('div.actions', [ |
34 | - api.channel.html.subscribe(location.channel) | |
32 … | + api.channel.html.subscribe(channel) | |
35 | 33 … | ]) |
36 | - ]), | |
34 … | + ]) | |
37 | 35 … | ] |
38 | 36 … | |
39 | 37 … | var channelPosts = api.app.html.scroller({ |
40 | 38 … | classList: ['content'], |
@@ -54,22 +52,22 @@ | ||
54 | 52 … | // updateBottom: updateRecentMsgCache, |
55 | 53 … | render |
56 | 54 … | }) |
57 | 55 … | |
56 … | + location.page = location.page || 'channelShow' | |
57 … | + // covers case where router.sync.normalise delivers a loc = { channel: '#channelName' } | |
58 … | + // HACK: helps sideNav | |
59 … | + | |
58 | 60 … | return h('Page -channelShow', { title: strings.home }, [ |
59 | 61 … | api.app.html.sideNav(location), |
60 | 62 … | channelPosts |
61 | 63 … | ]) |
62 | 64 … | } |
63 | 65 … | |
64 | - | |
65 | - function render(blog) { | |
66 … | + function render (blog) { | |
66 | 67 … | const { recps, channel } = blog.value.content |
67 | 68 … | var onClick |
68 | - if (channel && !recps) | |
69 | - onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' })) | |
69 … | + if (channel && !recps) { onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' })) } | |
70 | 70 … | |
71 | 71 … | return api.app.html.blogCard(blog, { onClick }) |
72 | 72 … | } |
73 | 73 … | } |
74 | - | |
75 | - |
app/page/channelShow.mcss | ||
---|---|---|
@@ -8,37 +8,34 @@ | ||
8 | 8 … | right: 0 |
9 | 9 … | top: 0 |
10 | 10 … | z-index: 99 |
11 | 11 … | |
12 | - | |
12 … | + padding-bottom: 1rem | |
13 … | + margin-bottom: 1rem | |
13 | 14 … | |
14 | 15 … | section.about { |
15 | - | |
16 … | + padding-bottom: 1rem | |
17 … | + | |
16 | 18 … | display: flex |
17 | 19 … | flex-direction: column |
18 | 20 … | align-items: center |
19 | - padding-bottom: 1rem | |
20 | - | |
21 | 21 … | |
22 | 22 … | h1 { |
23 | 23 … | font-weight: bold |
24 | 24 … | font-size: 1.5rem |
25 | 25 … | padding: 1rem |
26 | 26 … | |
27 | 27 … | margin: auto |
28 | - | |
29 | 28 … | } |
30 | 29 … | |
31 | 30 … | div.actions { |
32 | 31 … | display: flex |
33 | 32 … | |
34 | 33 … | div.Button { |
35 | 34 … | margin: auto |
36 | 35 … | } |
37 | - | |
38 | 36 … | } |
39 | 37 … | } |
40 | - | |
41 | 38 … | } |
42 | 39 … | |
43 | 40 … | section.content { |
44 | 41 … | background-color: #fff |
@@ -52,8 +49,12 @@ | ||
52 | 49 … | div.BlogCard { |
53 | 50 … | flex-basis: 100% |
54 | 51 … | |
55 | 52 … | border-bottom: 1px solid gainsboro |
53 … | + | |
54 … | + :last-child { | |
55 … | + border-bottom: none | |
56 … | + } | |
56 | 57 … | } |
57 | 58 … | } |
58 | 59 … | |
59 | 60 … | section.bottom { |
app/page/channelSubscriptions.js | ||
---|---|---|
@@ -1,6 +1,6 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h, when, Value, Array: MutantArray, onceTrue, computed, map: mutantMap } = require('mutant') | |
2 … | +const { h, when, Value, Array: MutantArray, onceTrue, watch, computed, map: mutantMap } = require('mutant') | |
3 | 3 … | const sortBy = require('lodash/sortBy') |
4 | 4 … | const map = require('lodash/map') |
5 | 5 … | const difference = require('lodash/difference') |
6 | 6 … | |
@@ -14,46 +14,46 @@ | ||
14 | 14 … | 'app.obs.pluginWarnings': 'first', |
15 | 15 … | 'history.sync.push': 'first', |
16 | 16 … | 'keys.sync.id': 'first', |
17 | 17 … | 'channel.obs.subscribed': 'first', |
18 | - 'channel.obs.recent':'first', | |
18 … | + 'channel.obs.recent': 'first', | |
19 | 19 … | 'channel.html.link': 'first', |
20 | 20 … | 'translations.sync.strings': 'first', |
21 | 21 … | 'sbot.async.friendsGet': 'first', |
22 | 22 … | 'sbot.pull.userFeed': 'first', |
23 | 23 … | 'sbot.obs.connection': 'first' |
24 | 24 … | }) |
25 | 25 … | |
26 | 26 … | exports.create = (api) => { |
27 | - const otherChannels = MutantArray () | |
27 … | + const otherChannels = MutantArray() | |
28 | 28 … | |
29 | 29 … | return nest('app.page.channelSubscriptions', function (location) { |
30 | 30 … | const strings = api.translations.sync.strings() |
31 | 31 … | const myId = api.keys.sync.id() |
32 | 32 … | |
33 | 33 … | const rawSubs = api.channel.obs.subscribed(myId) |
34 | - const mySubs = computed(rawSubs, myChannels => [...myChannels.values()].reverse() ) | |
34 … | + const mySubs = computed(rawSubs, myChannels => [...myChannels.values()].reverse()) | |
35 | 35 … | |
36 | - if (location.scope === "user") { | |
37 | - | |
36 … | + if (location.scope === 'user') { | |
38 | 37 … | return h('Page -channelSubscriptions', { title: strings.home }, [ |
39 | 38 … | api.app.html.sideNav(location), |
40 | 39 … | h('div.content', [ |
41 | - when(rawSubs.sync, | |
40 … | + when(rawSubs.sync, | |
42 | 41 … | [ |
43 | 42 … | computed(mySubs, mys => mys.length === 0 ? strings.subscriptions.state.noSubscriptions : ''), |
44 | - mutantMap(mySubs, api.app.html.channelCard), | |
43 … | + mutantMap(mySubs, api.app.html.channelCard) | |
45 | 44 … | ], |
46 | 45 … | h('p', strings.loading) |
47 | 46 … | ) |
48 | 47 … | ]) |
49 | 48 … | ]) |
50 | 49 … | } |
51 | 50 … | |
52 | - if (location.scope === "friends") { | |
51 … | + if (location.scope === 'friends') { | |
53 | 52 … | // update list of other all channels |
54 | - onceTrue( | |
55 | - api.app.obs.pluginWarnings, | |
53 … | + // NOTE can't use onceTrue right now, because warnings are true/ false | |
54 … | + watch( | |
55 … | + api.app.obs.pluginWarnings(), | |
56 | 56 … | isWarnings => { |
57 | 57 … | if (isWarnings) { |
58 | 58 … | return |
59 | 59 … | } |
@@ -63,18 +63,18 @@ | ||
63 | 63 … | |
64 | 64 … | const showMoreCounter = Value(1) |
65 | 65 … | const newChannels = computed([otherChannels, mySubs, showMoreCounter], (other, mine, more) => { |
66 | 66 … | return difference(other, mine) |
67 | - .slice(0, 10*more) | |
67 … | + .slice(0, 10 * more) | |
68 | 68 … | }) |
69 | 69 … | |
70 | 70 … | return h('Page -channelSubscriptions', { title: strings.home }, [ |
71 | 71 … | api.app.html.sideNav(location), |
72 | 72 … | h('div.content', [ |
73 | 73 … | when(otherChannels, |
74 | 74 … | [ |
75 | 75 … | mutantMap(newChannels, api.app.html.channelCard), |
76 | - h('Button', { 'ev-click': () => showMoreCounter.set(showMoreCounter()+1) }, | |
76 … | + h('Button', { 'ev-click': () => showMoreCounter.set(showMoreCounter() + 1) }, | |
77 | 77 … | strings.showMore |
78 | 78 … | ) |
79 | 79 … | ], |
80 | 80 … | h('p', strings.loading) |
@@ -84,8 +84,9 @@ | ||
84 | 84 … | } |
85 | 85 … | }) |
86 | 86 … | |
87 | 87 … | function getChannels (sbot) { |
88 … | + console.log('fetching channel subscriptions') | |
88 | 89 … | sbot.channel.subscriptions((err, c) => { |
89 | 90 … | if (err) throw err |
90 | 91 … | let b = map(c, (v,k) => {return {channel: k, users: v}}) |
91 | 92 … | b = sortBy(b, o => o.users.length) |
app/page/error.js | ||
---|---|---|
@@ -18,5 +18,4 @@ | ||
18 | 18 … | h('pre', [JSON.stringify(location, null, 2)]) |
19 | 19 … | ]) |
20 | 20 … | } |
21 | 21 … | } |
22 | - |
app/page/groupFind.js | ||
---|---|---|
@@ -5,9 +5,9 @@ | ||
5 | 5 … | |
6 | 6 … | exports.needs = nest({ |
7 | 7 … | 'app.html.link': 'first', |
8 | 8 … | 'channel.async.suggest': 'first', |
9 | - 'translations.sync.strings': 'first', | |
9 … | + 'translations.sync.strings': 'first' | |
10 | 10 … | }) |
11 | 11 … | |
12 | 12 … | exports.create = (api) => { |
13 | 13 … | return nest('app.page.groupFind', groupFind) |
@@ -16,30 +16,30 @@ | ||
16 | 16 … | const strings = api.translations.sync.strings() |
17 | 17 … | const input = Value('') |
18 | 18 … | |
19 | 19 … | // CHANNEL != GROUP |
20 | - // note we're using channels in initial approximation of groups | |
20 … | + // note we're using channels in initial approximation of groups | |
21 | 21 … | const suggester = api.channel.async.suggest() |
22 | - const groups = computed(input, input => suggester(input)) | |
22 … | + const groups = computed(input, input => suggester(input)) | |
23 | 23 … | |
24 | 24 … | const Link = api.app.html.link |
25 | 25 … | |
26 | 26 … | return h('Page -groupFind', {title: strings.groupFind.pageTitle}, [ |
27 | 27 … | h('div.content', [ |
28 | 28 … | h('div.search', [ |
29 | 29 … | h('i.fa.fa-search'), |
30 | - h('input', { | |
30 … | + h('input', { | |
31 | 31 … | placeholder: strings.groupFind.action.findAGroup, |
32 | 32 … | autofocus: 'autofocus', |
33 | - 'ev-input': e => input.set(e.target.value) | |
34 | - }), | |
33 … | + 'ev-input': e => input.set(e.target.value) | |
34 … | + }) | |
35 | 35 … | ]), |
36 | 36 … | h('div.results', map(groups, group => { |
37 | 37 … | return Link({ channel: group.title }, |
38 | 38 … | h('div.result', [ |
39 | 39 … | // api.about.html.image(user.id), |
40 | 40 … | h('div.alias', group.id), // channel with # |
41 | - h('pre.key', group.subtitle || ' '), // subscribed or not | |
41 … | + h('pre.key', group.subtitle || ' ') // subscribed or not | |
42 | 42 … | ]) |
43 | 43 … | ) |
44 | 44 … | })), |
45 | 45 … | computed([input, groups], (input, groups) => { |
@@ -56,9 +56,4 @@ | ||
56 | 56 … | ]) |
57 | 57 … | ]) |
58 | 58 … | } |
59 | 59 … | } |
60 | - | |
61 | - | |
62 | - | |
63 | - | |
64 | - |
app/page/groupShow.js | ||
---|---|---|
@@ -3,9 +3,9 @@ | ||
3 | 3 … | |
4 | 4 … | exports.gives = nest('app.page.groupShow') |
5 | 5 … | |
6 | 6 … | exports.needs = nest({ |
7 | - 'translations.sync.strings': 'first', | |
7 … | + 'translations.sync.strings': 'first' | |
8 | 8 … | }) |
9 | 9 … | |
10 | 10 … | exports.create = (api) => { |
11 | 11 … | var strings = api.translations.sync.strings() |
@@ -19,9 +19,4 @@ | ||
19 | 19 … | h('p', `key: ${location.key}`) |
20 | 20 … | ]) |
21 | 21 … | } |
22 | 22 … | } |
23 | - | |
24 | - | |
25 | - | |
26 | - | |
27 | - |
app/page/settings.js | ||
---|---|---|
@@ -15,9 +15,9 @@ | ||
15 | 15 … | 'message.html.markdown': 'first', |
16 | 16 … | 'settings.sync.get': 'first', |
17 | 17 … | 'settings.sync.set': 'first', |
18 | 18 … | 'settings.obs.get': 'first', |
19 | - 'translations.sync.strings': 'first', | |
19 … | + 'translations.sync.strings': 'first' | |
20 | 20 … | }) |
21 | 21 … | |
22 | 22 … | const LANGUAGES = ['zh', 'en'] |
23 | 23 … | |
@@ -30,9 +30,8 @@ | ||
30 | 30 … | exports.create = (api) => { |
31 | 31 … | return nest('app.page.settings', settings) |
32 | 32 … | |
33 | 33 … | function settings (location) { |
34 | - | |
35 | 34 … | // RESET the app when the settings are changed |
36 | 35 … | api.settings.obs.get('language')(() => { |
37 | 36 … | console.log('language changed, resetting view') |
38 | 37 … | |
@@ -50,30 +49,30 @@ | ||
50 | 49 … | const editProfile = () => api.history.sync.push({ |
51 | 50 … | page: 'userEdit', |
52 | 51 … | feed, |
53 | 52 … | callback: (err, didEdit) => { |
54 | - if (err) throw new Error ('Error editing profile', err) | |
53 … | + if (err) throw new Error('Error editing profile', err) | |
55 | 54 … | api.history.sync.push({ page: 'settings' }) |
56 | 55 … | } |
57 | - }) | |
56 … | + }) | |
58 | 57 … | |
59 | 58 … | return h('Page -settings', [ |
60 | 59 … | h('div.content', [ |
61 | 60 … | h('h1', strings.settingsPage.title), |
62 | 61 … | h('section -avatar', [ |
63 | 62 … | h('div.left'), |
64 | - h('div.right', api.about.html.image(feed)), | |
63 … | + h('div.right', api.about.html.image(feed)) | |
65 | 64 … | ]), |
66 | 65 … | h('section -name', [ |
67 | 66 … | h('div.left', strings.settingsPage.section.name), |
68 | - h('div.right', [ | |
67 … | + h('div.right', [ | |
69 | 68 … | api.about.obs.name(feed), |
70 | - h('img', { | |
69 … | + h('img', { | |
71 | 70 … | src: path.join(__dirname, '../../assets', 'edit.png'), |
72 | 71 … | 'ev-click': editProfile |
73 | 72 … | }) |
74 | 73 … | // h('i.fa.fa-pencil', { 'ev-click': editProfile }) |
75 | - ]), | |
74 … | + ]) | |
76 | 75 … | ]), |
77 | 76 … | h('section -introduction', [ |
78 | 77 … | h('div.left', strings.settingsPage.section.introduction), |
79 | 78 … | h('div.right', computed(api.about.obs.description(feed), d => api.message.html.markdown(d || ''))) |
@@ -84,38 +83,37 @@ | ||
84 | 83 … | ]), |
85 | 84 … | h('section -zoom', [ |
86 | 85 … | h('div.left', strings.settingsPage.section.zoom), |
87 | 86 … | h('div.right', [ zoomButton(-0.1, '-'), zoomButton(+0.1, '+') ]) |
88 | - ]), | |
87 … | + ]) | |
89 | 88 … | ]) |
90 | 89 … | ]) |
91 | 90 … | |
92 | 91 … | function Language (lang) { |
93 | 92 … | const selectLang = () => api.settings.sync.set({ language: lang }) |
94 | - const className = currentLanguage === lang ? '-strong' : '' | |
93 … | + const className = currentLanguage === lang ? '-strong' : '' | |
95 | 94 … | |
96 | - return h('Button -language', | |
97 | - { | |
98 | - 'ev-click': () => selectLang(lang), | |
99 | - className | |
100 | - }, | |
95 … | + return h('Button -language', | |
96 … | + { | |
97 … | + 'ev-click': () => selectLang(lang), | |
98 … | + className | |
99 … | + }, | |
101 | 100 … | strings.languages[lang] |
102 | 101 … | ) |
103 | 102 … | } |
104 | 103 … | |
105 | 104 … | function zoomButton (increment, symbol) { |
106 | 105 … | const { getCurrentWebContents } = electron.remote |
107 | - return h('Button -zoom', | |
108 | - { | |
106 … | + return h('Button -zoom', | |
107 … | + { | |
109 | 108 … | 'ev-click': () => { |
110 | 109 … | var zoomFactor = api.settings.sync.get('ticktack.electron.zoomFactor', 1) |
111 | 110 … | var newZoomFactor = zoomFactor + increment |
112 | 111 … | var zoomFactor = api.settings.sync.set('ticktack.electron.zoomFactor', newZoomFactor) |
113 | 112 … | getCurrentWebContents().setZoomFactor(newZoomFactor) |
114 | 113 … | } |
115 | - }, | |
114 … | + }, | |
116 | 115 … | symbol |
117 | 116 … | ) |
118 | 117 … | } |
119 | 118 … | } |
120 | 119 … | } |
121 | - |
app/page/splash.js | ||
---|---|---|
@@ -30,9 +30,9 @@ | ||
30 | 30 … | h('img.logoName', { src: assetPath('logo_and_name.png') }) |
31 | 31 … | ]), |
32 | 32 … | h('div.bottom', { style }, [ |
33 | 33 … | h('div.about', strings.splash.about), |
34 | - h('pre.slogan', strings.splash.slogan), | |
34 … | + h('pre.slogan', strings.splash.slogan) | |
35 | 35 … | ]) |
36 | 36 … | ]) |
37 | 37 … | } |
38 | 38 … | } |
app/page/threadNew.js | ||
---|---|---|
@@ -14,18 +14,17 @@ | ||
14 | 14 … | 'history.sync.push': 'first', |
15 | 15 … | 'keys.sync.id': 'first', |
16 | 16 … | 'message.html.compose': 'first', |
17 | 17 … | 'message.sync.unbox': 'first', |
18 | - 'translations.sync.strings': 'first', | |
18 … | + 'translations.sync.strings': 'first' | |
19 | 19 … | }) |
20 | 20 … | |
21 | 21 … | exports.create = (api) => { |
22 | - | |
23 | 22 … | return nest('app.page.threadNew', threadNew) |
24 | 23 … | |
25 | 24 … | function threadNew (location) { |
26 | 25 … | if (isEmpty(location.participants)) return |
27 | - | |
26 … | + | |
28 | 27 … | return threadNewFeed(location) |
29 | 28 … | } |
30 | 29 … | |
31 | 30 … | function threadNewFeed (location) { |
@@ -35,14 +34,14 @@ | ||
35 | 34 … | const { participants } = location |
36 | 35 … | |
37 | 36 … | const meta = Struct({ |
38 | 37 … | type: 'post', |
39 | - recps: MutantArray ([ | |
38 … | + recps: MutantArray([ | |
40 | 39 … | myId, |
41 | 40 … | ...participants.map(p => { |
42 | - return { | |
43 | - link: p, | |
44 | - name: resolve(api.about.obs.name(p)) | |
41 … | + return { | |
42 … | + link: p, | |
43 … | + name: resolve(api.about.obs.name(p)) | |
45 | 44 … | } |
46 | 45 … | }) |
47 | 46 … | ]), |
48 | 47 … | subject: Value() |
@@ -63,9 +62,9 @@ | ||
63 | 62 … | h('div.label', strings.threadNew.field.subject), |
64 | 63 … | h('input', { |
65 | 64 … | 'ev-input': e => meta.subject.set(e.target.value), |
66 | 65 … | placeholder: strings.optionalField |
67 | - }), | |
66 … | + }) | |
68 | 67 … | ]), |
69 | 68 … | Composer(meta) |
70 | 69 … | ]) |
71 | 70 … | ]) |
@@ -91,10 +90,9 @@ | ||
91 | 90 … | addSuggest() |
92 | 91 … | |
93 | 92 … | input.addEventListener('suggestselect', (e) => { |
94 | 93 … | const { id, title: name } = e.detail |
95 | - if (!recps.find(r => r === id || r.link === id)) | |
96 | - recps.push({ link: id, name }) | |
94 … | + if (!recps.find(r => r === id || r.link === id)) { recps.push({ link: id, name }) } | |
97 | 95 … | |
98 | 96 … | boxActive = false |
99 | 97 … | e.target.value = '' |
100 | 98 … | e.target.placeholder = '' |
@@ -148,7 +146,5 @@ | ||
148 | 146 … | } |
149 | 147 … | ) |
150 | 148 … | } |
151 | 149 … | } |
152 | - | |
153 | 150 … | } |
154 | - |
app/page/threadShow.js | ||
---|---|---|
@@ -22,9 +22,9 @@ | ||
22 | 22 … | const { key, value } = location |
23 | 23 … | const root = get(value, 'content.root', key) |
24 | 24 … | const channel = get(value, 'content.channel') |
25 | 25 … | |
26 | - //unread state is set in here... | |
26 … | + // unread state is set in here... | |
27 | 27 … | const thread = api.feed.obs.thread(root) |
28 | 28 … | const subject = get(location, 'value.content.subject') |
29 | 29 … | const recps = get(location, 'value.content.recps') |
30 | 30 … | |
@@ -41,21 +41,21 @@ | ||
41 | 41 … | api.app.html.sideNav(location), |
42 | 42 … | h('div.content', [ |
43 | 43 … | h('header', [ |
44 | 44 … | when(subject, h('h1', subject)), |
45 | - Recipients(recps), | |
45 … | + Recipients(recps) | |
46 | 46 … | ]), |
47 | 47 … | api.app.html.thread(thread), |
48 | 48 … | composer |
49 | - ]), | |
49 … | + ]) | |
50 | 50 … | ]) |
51 | 51 … | } |
52 | 52 … | |
53 | 53 … | function Recipients (recps) { |
54 | - if (recps && recps.length > 2) | |
54 … | + if (recps && recps.length > 2) { | |
55 | 55 … | return h('div.recps', recps.map(r => { |
56 | 56 … | const recp = typeof r === 'string' ? r : r.link |
57 | 57 … | return api.about.html.avatar(recp, 'tiny') |
58 | 58 … | })) |
59 … | + } | |
59 | 60 … | } |
60 | 61 … | } |
61 | - |
app/page/userEdit.js | ||
---|---|---|
@@ -5,9 +5,9 @@ | ||
5 | 5 … | |
6 | 6 … | exports.needs = nest({ |
7 | 7 … | 'about.page.edit': 'first', |
8 | 8 … | 'history.sync.push': 'first', |
9 | - 'translations.sync.strings': 'first', | |
9 … | + 'translations.sync.strings': 'first' | |
10 | 10 … | }) |
11 | 11 … | |
12 | 12 … | exports.create = (api) => { |
13 | 13 … | return nest('app.page.userEdit', userEdit) |
@@ -26,18 +26,18 @@ | ||
26 | 26 … | description: strings.userEdit.section.introduction, |
27 | 27 … | instructionCrop: strings.userEdit.instruction.crop, |
28 | 28 … | okay: strings.userEdit.action.okay, |
29 | 29 … | cancel: strings.userEdit.action.cancel, |
30 | - save: strings.userEdit.action.save, | |
30 … | + save: strings.userEdit.action.save | |
31 | 31 … | } |
32 | 32 … | }) |
33 | 33 … | |
34 | 34 … | const defaultCallback = (err, didEdit) => { |
35 | - if (err) throw new Error ('Error editing profile', err) | |
35 … | + if (err) throw new Error('Error editing profile', err) | |
36 | 36 … | |
37 | 37 … | api.history.sync.push({ page: 'userShow', feed }) |
38 | 38 … | } |
39 | - callback = typeof callback == 'function' | |
39 … | + callback = typeof callback === 'function' | |
40 | 40 … | ? callback |
41 | 41 … | : defaultCallback |
42 | 42 … | |
43 | 43 … | return h('Page -userEdit', {}, [ |
@@ -46,5 +46,4 @@ | ||
46 | 46 … | ]) |
47 | 47 … | ]) |
48 | 48 … | } |
49 | 49 … | } |
50 | - |
app/page/userFind.js | ||
---|---|---|
@@ -6,9 +6,9 @@ | ||
6 | 6 … | exports.needs = nest({ |
7 | 7 … | 'about.html.image': 'first', |
8 | 8 … | 'app.html.link': 'first', |
9 | 9 … | 'about.async.suggest': 'first', |
10 | - 'translations.sync.strings': 'first', | |
10 … | + 'translations.sync.strings': 'first' | |
11 | 11 … | }) |
12 | 12 … | |
13 | 13 … | exports.create = (api) => { |
14 | 14 … | return nest('app.page.userFind', userFind) |
@@ -17,35 +17,31 @@ | ||
17 | 17 … | const strings = api.translations.sync.strings() |
18 | 18 … | const input = Value() |
19 | 19 … | |
20 | 20 … | const suggester = api.about.async.suggest() |
21 | - const users = computed(input, input => suggester(input)) | |
21 … | + const users = computed(input, input => suggester(input)) | |
22 | 22 … | |
23 | 23 … | const Link = api.app.html.link |
24 | 24 … | |
25 | 25 … | return h('Page -userFind', {title: strings.userFind.pageTitle}, [ |
26 | 26 … | h('div.content', [ |
27 | 27 … | h('div.search', [ |
28 | 28 … | h('i.fa.fa-search'), |
29 | - h('input', { | |
29 … | + h('input', { | |
30 | 30 … | placeholder: strings.userFind.action.findAUser, |
31 | 31 … | autofocus: 'autofocus', |
32 | - 'ev-input': e => input.set(e.target.value) | |
33 | - }), | |
32 … | + 'ev-input': e => input.set(e.target.value) | |
33 … | + }) | |
34 | 34 … | ]), |
35 | 35 … | h('div.results', map(users, user => { |
36 | 36 … | return Link({ feed: user.id }, |
37 | 37 … | h('div.result', [ |
38 | 38 … | api.about.html.image(user.id), |
39 | 39 … | h('div.alias', user.title), |
40 | - h('pre.key', user.id), | |
40 … | + h('pre.key', user.id) | |
41 | 41 … | ]) |
42 | 42 … | ) |
43 | 43 … | })) |
44 | 44 … | ]) |
45 | 45 … | ]) |
46 | 46 … | } |
47 | 47 … | } |
48 | - | |
49 | - | |
50 | - | |
51 | - |
app/page/userShow.js | ||
---|---|---|
@@ -37,9 +37,9 @@ | ||
37 | 37 … | const strings = api.translations.sync.strings() |
38 | 38 … | |
39 | 39 … | const Link = api.app.html.link |
40 | 40 … | const userEditButton = Link( |
41 | - { page: 'userEdit', feed }, | |
41 … | + { page: 'userEdit', feed }, | |
42 | 42 … | // h('i.fa.fa-pencil') |
43 | 43 … | h('img', { src: path.join(__dirname, '../../assets', 'edit.png') }) |
44 | 44 … | ) |
45 | 45 … | const directMessageButton = Link({ page: 'threadNew', participants: [feed] }, h('Button', strings.userShow.action.directMessage)) |
@@ -47,9 +47,9 @@ | ||
47 | 47 … | const BLOG_TYPES = ['blog', 'post'] |
48 | 48 … | |
49 | 49 … | // TODO return some of this ? |
50 | 50 … | // but maybe this shouldn't be done here ? |
51 | - // pull.through(function (blog) { | |
51 … | + // pull.through(function (blog) { | |
52 | 52 … | // if(isUnread(blog)) |
53 | 53 … | // blog.unread = true |
54 | 54 … | // blog.replies.forEach(function (data) { // this was fed rollups |
55 | 55 … | // if(isUnread(data)) |
@@ -69,14 +69,14 @@ | ||
69 | 69 … | ]), |
70 | 70 … | h('div.introduction', computed(api.about.obs.description(feed), d => api.message.html.markdown(d || ''))), |
71 | 71 … | feed !== myId |
72 | 72 … | ? h('div.actions', [ |
73 | - h('div.directMessage', directMessageButton), | |
74 | - api.contact.html.follow(feed), | |
75 | - api.contact.html.block(feed) | |
76 | - ]) | |
77 | - : '', | |
78 | - ]), | |
73 … | + h('div.directMessage', directMessageButton), | |
74 … | + api.contact.html.follow(feed), | |
75 … | + api.contact.html.block(feed) | |
76 … | + ]) | |
77 … | + : '' | |
78 … | + ]) | |
79 | 79 … | ] |
80 | 80 … | |
81 | 81 … | const store = MutantArray() |
82 | 82 … | // store(console.log) |
@@ -84,9 +84,9 @@ | ||
84 | 84 … | return h('Page -userShow', [ |
85 | 85 … | api.app.html.sideNav(location), |
86 | 86 … | api.app.html.scroller({ |
87 | 87 … | classList: ['content'], |
88 | - prepend, | |
88 … | + prepend, | |
89 | 89 … | // stream: api.feed.pull.profile(feed), |
90 | 90 … | stream: opts => api.sbot.pull.userFeed(Object.assign({}, { id: feed }, opts)), |
91 | 91 … | indexProperty: ['value', 'sequence'], |
92 | 92 … | filter: () => pull( |
@@ -102,5 +102,4 @@ | ||
102 | 102 … | }) |
103 | 103 … | ]) |
104 | 104 … | } |
105 | 105 … | } |
106 | - |
app/sync/initialize/clickHandler.js | ||
---|---|---|
@@ -4,9 +4,9 @@ | ||
4 | 4 … | exports.gives = nest('app.sync.initialize') |
5 | 5 … | |
6 | 6 … | exports.needs = nest({ |
7 | 7 … | 'app.async.catchLinkClick': 'first', |
8 | - 'history.sync.push': 'first', | |
8 … | + 'history.sync.push': 'first' | |
9 | 9 … | }) |
10 | 10 … | |
11 | 11 … | exports.create = (api) => { |
12 | 12 … | return nest({ |
@@ -20,5 +20,4 @@ | ||
20 | 20 … | }) |
21 | 21 … | } |
22 | 22 … | }) |
23 | 23 … | } |
24 | - |
app/sync/initialize/suggests.js | ||
---|---|---|
@@ -3,9 +3,9 @@ | ||
3 | 3 … | exports.gives = nest('app.sync.initialize') |
4 | 4 … | |
5 | 5 … | exports.needs = nest({ |
6 | 6 … | 'about.async.suggest': 'first', |
7 | - 'channel.async.suggest': 'first', | |
7 … | + 'channel.async.suggest': 'first' | |
8 | 8 … | // 'channel.obs.recent': 'first' |
9 | 9 … | }) |
10 | 10 … | |
11 | 11 … | exports.create = (api) => { |
@@ -18,5 +18,4 @@ | ||
18 | 18 … | // api.channel.obs.recent()() TODO - figure out how to initialise this store |
19 | 19 … | } |
20 | 20 … | }) |
21 | 21 … | } |
22 | - |
app/sync/initialize/zoomMemory.js | ||
---|---|---|
@@ -10,15 +10,15 @@ | ||
10 | 10 … | |
11 | 11 … | exports.create = (api) => { |
12 | 12 … | return nest('app.sync.initialize', zoomMemory) |
13 | 13 … | |
14 | - function zoomMemory() { | |
14 … | + function zoomMemory () { | |
15 | 15 … | const { getCurrentWebContents, getCurrentWindow } = electron.remote |
16 | 16 … | |
17 | 17 … | window.addEventListener('resize', () => { |
18 | 18 … | var wc = getCurrentWebContents() |
19 | 19 … | wc && wc.getZoomFactor(zf => { |
20 | - console.log(zf) | |
20 … | + console.log(zf) | |
21 | 21 … | api.settings.sync.set({ |
22 | 22 … | ticktack: { |
23 | 23 … | electron: { |
24 | 24 … | zoomFactor: zf, |
@@ -29,13 +29,10 @@ | ||
29 | 29 … | }) |
30 | 30 … | }) |
31 | 31 … | |
32 | 32 … | var zoomFactor = api.settings.sync.get('ticktack.electron.zoomFactor') |
33 | - if (zoomFactor) | |
34 | - getCurrentWebContents().setZoomFactor(zoomFactor) | |
33 … | + if (zoomFactor) { getCurrentWebContents().setZoomFactor(zoomFactor) } | |
35 | 34 … | |
36 | 35 … | var bounds = api.settings.sync.get('ticktack.electron.windowBounds') |
37 | - if (bounds) | |
38 | - getCurrentWindow().setBounds(bounds) | |
36 … | + if (bounds) { getCurrentWindow().setBounds(bounds) } | |
39 | 37 … | } |
40 | 38 … | } |
41 | - |
blog/html/blog.js | ||
---|---|---|
@@ -7,22 +7,21 @@ | ||
7 | 7 … | exports.gives = nest({ |
8 | 8 … | 'blog.html.title': true, |
9 | 9 … | 'blog.html.summary': true, |
10 | 10 … | 'blog.html.thumbnail': true, |
11 | - 'blog.html.content': true, | |
11 … | + 'blog.html.content': true | |
12 | 12 … | }) |
13 | 13 … | |
14 | 14 … | exports.needs = nest({ |
15 | 15 … | 'message.html.markdown': 'first', |
16 | 16 … | 'sbot.pull.stream': 'first', |
17 | 17 … | 'sbot.obs.connection': 'first' |
18 | 18 … | }) |
19 | 19 … | |
20 | - | |
21 | 20 … | exports.create = function (api) { |
22 | 21 … | function loadBlob (data) { |
23 | 22 … | const { blog } = data.value.content |
24 | - if (!isBlob(blog)) { | |
23 … | + if (!isBlob(blog)) { | |
25 | 24 … | console.log(`malformed Blog blog: ${blog}`, data) |
26 | 25 … | return |
27 | 26 … | } |
28 | 27 … | |
@@ -37,33 +36,33 @@ | ||
37 | 36 … | } |
38 | 37 … | |
39 | 38 … | return nest({ |
40 | 39 … | 'blog.html.title': function (data) { |
41 | - if(!isBlog(data)) return | |
40 … | + if (!isBlog(data)) return | |
42 | 41 … | |
43 | 42 … | return data.value.content.title |
44 | 43 … | }, |
45 | 44 … | 'blog.html.summary': function (data) { |
46 | - if(!isBlog(data)) return | |
45 … | + if (!isBlog(data)) return | |
47 | 46 … | |
48 | 47 … | loadBlob(data) |
49 | 48 … | return data.value.content.summary |
50 | 49 … | }, |
51 | 50 … | 'blog.html.thumbnail': function (data) { |
52 | - if(!isBlog(data)) return | |
51 … | + if (!isBlog(data)) return | |
53 | 52 … | return data.value.content.thumbnail |
54 | 53 … | }, |
55 | 54 … | 'blog.html.content': function (data) { |
56 | - if(!isBlog(data)) return | |
55 … | + if (!isBlog(data)) return | |
57 | 56 … | |
58 | 57 … | loadBlob(data) |
59 | 58 … | var div = h('Markdown') |
60 | 59 … | pull( |
61 | 60 … | api.sbot.pull.stream(function (sbot) { |
62 | 61 … | return sbot.blobs.get(data.value.content.blog) |
63 | 62 … | }), |
64 | 63 … | pull.collect(function (err, ary) { |
65 | - if(err) return | |
64 … | + if (err) return | |
66 | 65 … | var md = api.message.html.markdown({text: Buffer.concat(ary).toString()}) |
67 | 66 … | div.innerHTML = md.innerHTML |
68 | 67 … | }) |
69 | 68 … | ) |
@@ -74,5 +73,4 @@ | ||
74 | 73 … | |
75 | 74 … | function isBlog (msg) { |
76 | 75 … | return get(msg, 'value.content.type') === 'blog' |
77 | 76 … | } |
78 | - |
blog/html/post.js | ||
---|---|---|
@@ -4,21 +4,20 @@ | ||
4 | 4 … | exports.gives = nest({ |
5 | 5 … | 'blog.html.title': true, |
6 | 6 … | 'blog.html.summary': true, |
7 | 7 … | 'blog.html.thumbnail': true, |
8 | - 'blog.html.content': true, | |
8 … | + 'blog.html.content': true | |
9 | 9 … | }) |
10 | 10 … | |
11 | 11 … | exports.needs = nest({ |
12 | - 'message.html.markdown': 'first', | |
12 … | + 'message.html.markdown': 'first' | |
13 | 13 … | }) |
14 | 14 … | |
15 | 15 … | exports.create = function (api) { |
16 | - | |
17 | - function fromPost(fn) { | |
16 … | + function fromPost (fn) { | |
18 | 17 … | return function (data) { |
19 | - if('post' !== data.value.content.type) return | |
20 | - return api.message.html.markdown ({text: fn(data.value.content)}) | |
18 … | + if (data.value.content.type !== 'post') return | |
19 … | + return api.message.html.markdown({text: fn(data.value.content)}) | |
21 | 20 … | } |
22 | 21 … | } |
23 | 22 … | |
24 | 23 … | return nest({ |
@@ -30,19 +29,17 @@ | ||
30 | 29 … | if (content.summary) return content.summary |
31 | 30 … | if (content.text) return marksum.summary(content.text) |
32 | 31 … | }), |
33 | 32 … | 'blog.html.thumbnail': function (data) { |
34 | - const { type, thumbnail, text } = data.value.content | |
35 | - if('post' !== type) return | |
33 … | + const { type, thumbnail, text } = data.value.content | |
34 … | + if (type !== 'post') return | |
36 | 35 … | if (thumbnail) return thumbnail |
37 | 36 … | |
38 | 37 … | if (text) { |
39 | 38 … | var img = marksum.image(text) |
40 | 39 … | var m = /\!\[[^]+\]\(([^\)]+)\)/.exec(img) |
41 | - if(m) return m[1] | |
40 … | + if (m) return m[1] | |
42 | 41 … | } |
43 | 42 … | }, |
44 | 43 … | 'blog.html.content': fromPost(content => content.text) |
45 | 44 … | }) |
46 | 45 … | } |
47 | - | |
48 | - |
blog/index.js | ||
---|---|---|
@@ -3,5 +3,4 @@ | ||
3 | 3 … | post: require('./html/post'), |
4 | 4 … | blog: require('./html/blog') |
5 | 5 … | } |
6 | 6 … | } |
7 | - |
channel/async.js | ||
---|---|---|
@@ -3,9 +3,9 @@ | ||
3 | 3 … | |
4 | 4 … | exports.needs = nest({ |
5 | 5 … | 'keys.sync.id': 'first', |
6 | 6 … | 'sbot.async.publish': 'first', |
7 | - 'channel.obs.subscribed': 'first', | |
7 … | + 'channel.obs.subscribed': 'first' | |
8 | 8 … | }) |
9 | 9 … | |
10 | 10 … | exports.gives = nest({ |
11 | 11 … | 'channel.async': ['subscribe', 'unsubscribe'] |
@@ -16,8 +16,9 @@ | ||
16 | 16 … | 'channel.async': {subscribe, unsubscribe} |
17 | 17 … | }) |
18 | 18 … | |
19 | 19 … | function subscribe (channel, cb) { |
20 … | + channel = channel.replace(/^#/, '') | |
20 | 21 … | if (!channel) throw new Error('a channel must be specified') |
21 | 22 … | api.sbot.async.publish({ |
22 | 23 … | type: 'channel', |
23 | 24 … | channel: channel, |
@@ -25,13 +26,13 @@ | ||
25 | 26 … | }, cb) |
26 | 27 … | } |
27 | 28 … | |
28 | 29 … | function unsubscribe (channel, cb) { |
30 … | + channel = channel.replace(/^#/, '') | |
29 | 31 … | if (!channel) throw new Error('a channel must be specified') |
30 | 32 … | api.sbot.async.publish({ |
31 | 33 … | type: 'channel', |
32 | 34 … | channel: channel, |
33 | 35 … | subscribed: false |
34 | 36 … | }, cb) |
35 | 37 … | } |
36 | - | |
37 | 38 … | } |
channel/html/subscribe.js | ||
---|---|---|
@@ -3,25 +3,27 @@ | ||
3 | 3 … | |
4 | 4 … | exports.gives = nest('channel.html.subscribe') |
5 | 5 … | |
6 | 6 … | exports.needs = nest({ |
7 | - 'keys.sync.id': 'first', | |
8 | 7 … | 'translations.sync.strings': 'first', |
9 | 8 … | 'channel.obs.isSubscribedTo': 'first', |
10 | 9 … | 'channel.async.subscribe': 'first', |
11 | - 'channel.async.unsubscribe': 'first', | |
10 … | + 'channel.async.unsubscribe': 'first' | |
12 | 11 … | }) |
13 | 12 … | |
14 | 13 … | exports.create = function (api) { |
15 | - | |
16 | 14 … | return nest('channel.html.subscribe', (channel) => { |
15 … | + channel = channel.replace(/^#/, '') | |
17 | 16 … | const strings = api.translations.sync.strings() |
18 | - const myId = api.keys.sync.id() | |
19 | 17 … | const { subscribe, unsubscribe } = api.channel.async |
20 | - | |
21 | - return when(api.channel.obs.isSubscribedTo(channel, myId), | |
18 … | + const isSubscribed = api.channel.obs.isSubscribedTo(channel) | |
19 … | + | |
20 … | + isSubscribed(val => { | |
21 … | + console.log(channel, 'subscribed:', val) | |
22 … | + }) | |
23 … | + | |
24 … | + return when(isSubscribed, | |
22 | 25 … | h('Button', { 'ev-click': () => unsubscribe(channel) }, strings.channelShow.action.unsubscribe), |
23 | 26 … | h('Button -primary', { 'ev-click': () => subscribe(channel) }, strings.channelShow.action.subscribe) |
24 | 27 … | ) |
25 | 28 … | }) |
26 | 29 … | } |
27 | - |
channel/index.js | ||
---|---|---|
@@ -1,9 +1,7 @@ | ||
1 | -module.exports = { | |
1 … | +module.exports = { | |
2 | 2 … | async: require('./async'), |
3 | 3 … | obs: require('./obs'), |
4 | 4 … | html: { |
5 | 5 … | subscribe: require('./html/subscribe') |
6 | 6 … | } |
7 | 7 … | } |
8 | - | |
9 | - |
channel/obs.js | ||
---|---|---|
@@ -1,11 +1,12 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | 2 … | const ref = require('ssb-ref') |
3 | -const computed = require('mutant/computed') | |
3 … | +const { computed, onceTrue } = require('mutant') | |
4 | 4 … | |
5 | 5 … | exports.needs = nest({ |
6 | 6 … | 'keys.sync.id': 'first', |
7 | 7 … | 'channel.obs.subscribed': 'first', |
8 … | + 'sbot.obs.connection': 'first' | |
8 | 9 … | }) |
9 | 10 … | |
10 | 11 … | exports.gives = nest('channel.obs.isSubscribedTo') |
11 | 12 … | |
@@ -15,24 +16,27 @@ | ||
15 | 16 … | |
16 | 17 … | return nest('channel.obs.isSubscribedTo', isSubscribedTo) |
17 | 18 … | |
18 | 19 … | function isSubscribedTo (channel, id) { |
20 … | + channel = channel.replace(/^#/, '') | |
19 | 21 … | if (!ref.isFeed(id)) { |
20 | 22 … | id = getMyId() |
21 | 23 … | } |
22 | - | |
23 | - return computed(getSubscriptions(id), (v) => v.has(channel)) | |
24 … | + | |
25 … | + // TODO - use ssb-server-channel index to make a better subscribed obs | |
26 … | + return computed(getSubscriptions(id), set => { | |
27 … | + return set.has(channel) | |
28 … | + }) | |
24 | 29 … | } |
25 | 30 … | |
26 | - //cache getters | |
31 … | + // cache getters | |
27 | 32 … | |
28 | 33 … | function getMyId () { |
29 | 34 … | if (!myId) myId = api.keys.sync.id() |
30 | 35 … | return myId |
31 | 36 … | } |
32 | 37 … | |
33 | 38 … | function getSubscriptions (id) { |
34 | - if (!subscriptions[id]) subscriptions[id] = api.channel.obs.subscribed(id) | |
39 … | + if (subscriptions[id] === undefined) subscriptions[id] = api.channel.obs.subscribed(id) | |
35 | 40 … | return subscriptions[id] |
36 | 41 … | } |
37 | 42 … | } |
38 | - |
contact/html/block.js | ||
---|---|---|
@@ -12,9 +12,8 @@ | ||
12 | 12 … | 'app.html.lightbox': 'first' |
13 | 13 … | }) |
14 | 14 … | |
15 | 15 … | exports.create = (api) => { |
16 | - | |
17 | 16 … | return nest('contact.html.block', block) |
18 | 17 … | |
19 | 18 … | function block (feed) { |
20 | 19 … | const strings = api.translations.sync.strings() |
@@ -34,11 +33,11 @@ | ||
34 | 33 … | block(feed) |
35 | 34 … | isOpen.set(false) |
36 | 35 … | } |
37 | 36 … | |
38 | - const confirmationDialog = h("div.dialog", [ | |
39 | - h("div.message",strings.userShow.action.blockConfirmationMessage), | |
40 | - h("div.actions", [ | |
37 … | + const confirmationDialog = h('div.dialog', [ | |
38 … | + h('div.message', strings.userShow.action.blockConfirmationMessage), | |
39 … | + h('div.actions', [ | |
41 | 40 … | h('Button', {'ev-click': () => isOpen.set(false)}, strings.userShow.action.cancel), |
42 | 41 … | h('Button -primary', {'ev-click': () => blockAndClose(feed)}, strings.userShow.action.block) |
43 | 42 … | ]) |
44 | 43 … | ]) |
@@ -50,11 +49,10 @@ | ||
50 | 49 … | when(youBlockThem, |
51 | 50 … | h('Button', { 'ev-click': () => unblock(feed) }, strings.userShow.action.unblock), |
52 | 51 … | h('Button', { 'ev-click': () => isOpen.set(true) }, strings.userShow.action.block) |
53 | 52 … | ), |
54 | - h('Button', { disabled: 'disabled' }, strings.loading ) | |
53 … | + h('Button', { disabled: 'disabled' }, strings.loading) | |
55 | 54 … | ), |
56 | 55 … | lb |
57 | 56 … | ]) |
58 | 57 … | } |
59 | 58 … | } |
60 | - |
contact/html/follow.js | ||
---|---|---|
@@ -7,9 +7,9 @@ | ||
7 | 7 … | 'contact.async.follow': 'first', |
8 | 8 … | 'contact.async.unfollow': 'first', |
9 | 9 … | 'contact.obs.followers': 'first', |
10 | 10 … | 'keys.sync.id': 'first', |
11 | - 'translations.sync.strings': 'first', | |
11 … | + 'translations.sync.strings': 'first' | |
12 | 12 … | }) |
13 | 13 … | |
14 | 14 … | exports.create = (api) => { |
15 | 15 … | return nest('contact.html.follow', follow) |
@@ -32,17 +32,16 @@ | ||
32 | 32 … | const unfollow = (feed) => ev => { |
33 | 33 … | ev.stopPropagation() |
34 | 34 … | api.contact.async.unfollow(feed) |
35 | 35 … | } |
36 | - | |
36 … | + | |
37 | 37 … | return h('Follow', { className }, |
38 | 38 … | when(theirFollowers.sync, |
39 | 39 … | when(youFollowThem, |
40 | 40 … | h('Button', { 'ev-click': unfollow(feed) }, strings.userShow.action.unfollow), |
41 | 41 … | h('Button -strong', { 'ev-click': follow(feed) }, strings.userShow.action.follow) |
42 | 42 … | ), |
43 | - h('Button', { disabled: 'disabled' }, strings.loading ) | |
43 … | + h('Button', { disabled: 'disabled' }, strings.loading) | |
44 | 44 … | ) |
45 | 45 … | ) |
46 | 46 … | } |
47 | 47 … | } |
48 | - |
contact/index.js | ||
---|---|---|
@@ -1,11 +1,9 @@ | ||
1 | -module.exports = { | |
1 … | +module.exports = { | |
2 | 2 … | html: { |
3 | 3 … | follow: require('./html/follow'), |
4 | 4 … | block: require('./html/block') |
5 | 5 … | }, |
6 | 6 … | obs: { |
7 | - relationships: require('./obs/relationships'), | |
8 | - }, | |
7 … | + relationships: require('./obs/relationships') | |
8 … | + } | |
9 | 9 … | } |
10 | - | |
11 | - |
contact/obs/relationships.js | ||
---|---|---|
@@ -26,6 +26,5 @@ | ||
26 | 26 … | |
27 | 27 … | return { friends, followers, following } |
28 | 28 … | }) |
29 | 29 … | } |
30 | -} | |
31 | - | |
30 … | +} |
main.js | ||
---|---|---|
@@ -9,21 +9,21 @@ | ||
9 | 9 … | require('./context-menu') |
10 | 10 … | |
11 | 11 … | // from more specialized to more general |
12 | 12 … | const sockets = combine( |
13 | - //need some modules first | |
14 | - { | |
13 … | + // need some modules first | |
14 … | + { | |
15 | 15 … | settings: require('patch-settings'), |
16 | 16 … | translations: require('./translations/sync'), |
17 | - suggestions: require('patch-suggest'), // so that styles can be over-ridden | |
17 … | + suggestions: require('patch-suggest') // so that styles can be over-ridden | |
18 | 18 … | }, |
19 | 19 … | { |
20 | 20 … | about: require('./about'), |
21 | 21 … | app: require('./app'), |
22 | 22 … | blob: require('./blob'), |
23 | 23 … | blog: require('./blog'), |
24 | 24 … | contact: require('./contact'), |
25 | - //config: require('./ssb-config'), | |
25 … | + // config: require('./ssb-config'), | |
26 | 26 … | config: require('./config'), |
27 | 27 … | // group: require('./group'), |
28 | 28 … | message: require('./message'), |
29 | 29 … | router: require('./router'), |
@@ -39,10 +39,9 @@ | ||
39 | 39 … | } |
40 | 40 … | ) |
41 | 41 … | |
42 | 42 … | const api = entry(sockets, nest({ |
43 | - 'app.html.app': 'first', | |
43 … | + 'app.html.app': 'first' | |
44 | 44 … | })) |
45 | 45 … | |
46 | 46 … | document.body.appendChild(api.app.html.app()) |
47 | 47 … | // console.log(api.config.sync.load()) |
48 | - |
message/html/channel.js | ||
---|---|---|
@@ -9,18 +9,19 @@ | ||
9 | 9 … | |
10 | 10 … | exports.create = function (api) { |
11 | 11 … | return nest('message.html.channel', channel) |
12 | 12 … | |
13 | - function channel (msgOrChannel, opts = {} ) { | |
14 | - const channel = typeof msgOrChannel === 'string' | |
13 … | + function channel (msgOrChannel, opts = {}) { | |
14 … | + var channel = typeof msgOrChannel === 'string' | |
15 | 15 … | ? msgOrChannel |
16 | 16 … | : msgOrChannel.value.content.channel |
17 … | + channel = channel.replace(/^#/, '') | |
17 | 18 … | |
18 | 19 … | if (!channel) return |
19 | 20 … | |
20 | - const { | |
21 … | + const { | |
21 | 22 … | classList = [], |
22 | - location = { page: 'blogSearch', channel } | |
23 … | + location = { page: 'channelShow', channel } | |
23 | 24 … | } = opts |
24 | 25 … | |
25 | 26 … | const goToChannel = (e) => { |
26 | 27 … | e.stopPropagation() |
@@ -33,6 +34,4 @@ | ||
33 | 34 … | classList |
34 | 35 … | }, channel) |
35 | 36 … | } |
36 | 37 … | } |
37 | - | |
38 | - |
message/html/compose.js | ||
---|---|---|
@@ -28,9 +28,9 @@ | ||
28 | 28 … | feedIdsInThread = [], |
29 | 29 … | placeholder, |
30 | 30 … | shrink = true, |
31 | 31 … | canAttach = true, canPreview = true, |
32 | - prepublish, | |
32 … | + prepublish | |
33 | 33 … | } = options |
34 | 34 … | |
35 | 35 … | const strings = api.translations.sync.strings() |
36 | 36 … | const getUserSuggestions = api.about.async.suggest() |
@@ -67,9 +67,9 @@ | ||
67 | 67 … | |
68 | 68 … | textArea.publish = publish // TODO: fix - clunky api for the keyboard shortcut to target |
69 | 69 … | |
70 | 70 … | var fileInput |
71 | - if(!meta.recps) { | |
71 … | + if (!meta.recps) { | |
72 | 72 … | fileInput = api.blob.html.input(file => { |
73 | 73 … | files.push(file) |
74 | 74 … | filesById[file.link] = file |
75 | 75 … | |
@@ -88,18 +88,17 @@ | ||
88 | 88 … | fileInput.onclick = () => hasContent.set(true) |
89 | 89 … | } |
90 | 90 … | // if fileInput is null, send button moves to the left side |
91 | 91 … | // and we don't want that. |
92 | - else | |
93 | - fileInput = h('input', { style: {visibility: 'hidden'} }) | |
92 … | + else { fileInput = h('input', { style: {visibility: 'hidden'} }) } | |
94 | 93 … | |
95 | 94 … | function PreviewSetup (strings) { |
96 | 95 … | var showPreview = Value(false) |
97 | 96 … | var previewBtn = h('Button', |
98 | 97 … | { |
99 | 98 … | className: when(showPreview, '-strong', '-subtle'), |
100 | 99 … | 'ev-click': () => showPreview.set(!showPreview()) |
101 | - }, | |
100 … | + }, | |
102 | 101 … | when(showPreview, strings.blogNew.actions.edit, strings.blogNew.actions.preview) |
103 | 102 … | ) |
104 | 103 … | return { previewBtn, showPreview } |
105 | 104 … | } |
@@ -151,28 +150,25 @@ | ||
151 | 150 … | var content = assign({}, resolve(meta), { |
152 | 151 … | text, |
153 | 152 … | mentions |
154 | 153 … | }) |
155 | - for(var k in content) | |
156 | - content[k] = resolve(content[k]) | |
154 … | + for (var k in content) { content[k] = resolve(content[k]) } | |
157 | 155 … | |
158 | 156 … | if (!content.channel) delete content.channel |
159 | 157 … | if (!mentions.length) delete content.mentions |
160 | 158 … | if (content.recps && content.recps.length === 0) delete content.recps |
161 | 159 … | |
162 | 160 … | if (typeof prepublish === 'function') { |
163 | 161 … | prepublish(content, function (err, content) { |
164 | - if(err) handleErr(err) | |
162 … | + if (err) handleErr(err) | |
165 | 163 … | else api.message.async.publish(content, done) |
166 | 164 … | }) |
167 | - } | |
168 | - else | |
169 | - api.message.async.publish(content, done) | |
165 … | + } else { api.message.async.publish(content, done) } | |
170 | 166 … | |
171 | 167 … | function done (err, msg) { |
172 | 168 … | publishBtn.disabled = false |
173 | 169 … | if (err) handleErr(err) |
174 | - else if (msg) { | |
170 … | + else if (msg) { | |
175 | 171 … | textRaw.set('') |
176 | 172 … | textArea.value = '' |
177 | 173 … | } |
178 | 174 … | if (cb) cb(err, msg) |
@@ -185,6 +181,4 @@ | ||
185 | 181 … | } |
186 | 182 … | } |
187 | 183 … | } |
188 | 184 … | } |
189 | - | |
190 | - |
message/html/likes.js | ||
---|---|---|
@@ -41,5 +41,4 @@ | ||
41 | 41 … | } |
42 | 42 … | api.sbot.async.publish(like) |
43 | 43 … | } |
44 | 44 … | } |
45 | - |
message/html/subject.js | ||
---|---|---|
@@ -2,47 +2,47 @@ | ||
2 | 2 … | const { computed, Value } = require('mutant') |
3 | 3 … | const { title } = require('markdown-summary') |
4 | 4 … | const { isMsg } = require('ssb-ref') |
5 | 5 … | |
6 | - | |
7 | 6 … | exports.gives = nest('message.html.subject') |
8 | 7 … | |
9 | 8 … | exports.needs = nest({ |
10 | 9 … | 'message.html.markdown': 'first', |
11 | 10 … | 'message.sync.unbox': 'first', |
12 | - 'sbot.async.get': 'first', | |
11 … | + 'sbot.async.get': 'first' | |
13 | 12 … | }) |
14 | 13 … | |
15 | 14 … | exports.create = function (api) { |
15 … | + var subjectCache = {} | |
16 … | + | |
16 | 17 … | return nest('message.html.subject', subject) |
17 | 18 … | |
18 | 19 … | function subject (msg) { |
19 | 20 … | if (msg === undefined) debugger |
20 | 21 … | // test if it's a message ref, or a full message object |
22 … | + // a message ref is generally passed in if we're fetching the subject of a root message | |
21 | 23 … | if (isMsg(msg)) { |
24 … | + if (subjectCache[msg]) return subjectCache[msg] | |
25 … | + | |
22 | 26 … | var subject = Value() |
23 | 27 … | |
24 | 28 … | api.sbot.async.get(msg, (err, value) => { |
25 | 29 … | if (err) throw err |
26 | 30 … | |
27 | - subject.set(getMsgSubject({ | |
28 | - key: msg, | |
29 | - value: api.message.sync.unbox(value) | |
30 | - })) | |
31 … | + var _subject = getMsgSubject({ key: msg, value: api.message.sync.unbox(value) }) | |
32 … | + subject.set(_subject) | |
33 … | + subjectCache[msg] = _subject | |
31 | 34 … | }) |
32 | 35 … | |
33 | 36 … | return subject |
34 | - } | |
35 | - else | |
36 | - return getMsgSubject(msg) | |
37 … | + } else { return getMsgSubject(msg) } | |
37 | 38 … | } |
38 | 39 … | |
39 | 40 … | function getMsgSubject (msg) { |
40 | 41 … | const { subject, text } = msg.value.content |
41 | - if(!(subject || text)) return | |
42 … | + if (!(subject || text)) return | |
42 | 43 … | |
43 | 44 … | return subject |
44 | 45 … | ? api.message.html.markdown(subject) |
45 | 46 … | : api.message.html.markdown(title(text)) |
46 | 47 … | } |
47 | 48 … | } |
48 | - |
message/html/timeago.js | ||
---|---|---|
@@ -14,5 +14,4 @@ | ||
14 | 14 … | // perhaps by adding an initializer which sweeps for data-timestamp elements and updates them |
15 | 15 … | return h('Timeago', humanTime(new Date(timestamp))) |
16 | 16 … | } |
17 | 17 … | } |
18 | - |
message/index.js | ||
---|---|---|
@@ -1,7 +1,7 @@ | ||
1 | -module.exports = { | |
1 … | +module.exports = { | |
2 | 2 … | async: { |
3 | - publish: require('./async/publish'), | |
3 … | + publish: require('./async/publish') | |
4 | 4 … | }, |
5 | 5 … | html: { |
6 | 6 … | channel: require('./html/channel'), |
7 | 7 … | compose: require('./html/compose'), |
@@ -9,8 +9,7 @@ | ||
9 | 9 … | subject: require('./html/subject'), |
10 | 10 … | timeago: require('./html/timeago') |
11 | 11 … | }, |
12 | 12 … | sync: { |
13 | - getParticipants: require('./sync/getParticipants'), | |
14 | - }, | |
13 … | + getParticipants: require('./sync/getParticipants') | |
14 … | + } | |
15 | 15 … | } |
16 | - |
message/sync/getParticipants.js | ||
---|---|---|
@@ -3,9 +3,9 @@ | ||
3 | 3 … | |
4 | 4 … | exports.gives = nest('message.sync.getParticipants') |
5 | 5 … | |
6 | 6 … | exports.needs = nest({ |
7 | - 'keys.sync.id': 'first', | |
7 … | + 'keys.sync.id': 'first' | |
8 | 8 … | }) |
9 | 9 … | |
10 | 10 … | exports.create = function (api) { |
11 | 11 … | return nest('message.sync.getParticipants', getParticipants) |
@@ -21,7 +21,4 @@ | ||
21 | 21 … | participants.key = participants.join(' ') |
22 | 22 … | return participants |
23 | 23 … | } |
24 | 24 … | } |
25 | - | |
26 | - | |
27 | - |
router/sync/routes.js | ||
---|---|---|
@@ -26,9 +26,9 @@ | ||
26 | 26 … | 'app.page.splash': 'first', |
27 | 27 … | 'app.page.threadNew': 'first', |
28 | 28 … | 'app.page.threadShow': 'first', |
29 | 29 … | // 'app.page.image': 'first', |
30 | - 'blob.sync.url': 'first', | |
30 … | + 'blob.sync.url': 'first' | |
31 | 31 … | }) |
32 | 32 … | |
33 | 33 … | exports.create = (api) => { |
34 | 34 … | return nest('router.sync.routes', (sofar = []) => { |
@@ -43,19 +43,19 @@ | ||
43 | 43 … | [ location => location.page === 'blogNew', pages.blogNew ], |
44 | 44 … | [ location => location.page === 'blogSearch', pages.blogSearch ], |
45 | 45 … | [ location => location.page === 'blogShow', pages.blogShow ], |
46 | 46 … | [ location => isMsg(location.key) && get(location, 'value.content.type') === 'blog', pages.blogShow ], |
47 | - [ location => { | |
48 | - return isMsg(location.key) | |
49 | - && get(location, 'value.content.type') === 'post' | |
50 | - && !get(location, 'value.private') // treats public posts as 'blogs' | |
47 … | + [ location => { | |
48 … | + return isMsg(location.key) && | |
49 … | + get(location, 'value.content.type') === 'post' && | |
50 … | + !get(location, 'value.private') // treats public posts as 'blogs' | |
51 | 51 … | }, pages.blogShow ], |
52 | 52 … | |
53 | 53 … | // Channel related pages |
54 | 54 … | [ location => location.page === 'channelSubscriptions', pages.channelSubscriptions], |
55 | 55 … | [ location => location.page === 'channelShow', pages.channelShow ], |
56 … | + [ location => location.channel, pages.channelShow ], | |
56 | 57 … | |
57 | - | |
58 | 58 … | // AddressBook pages |
59 | 59 … | [ location => location.page === 'addressBook', pages.addressBook ], |
60 | 60 … | |
61 | 61 … | // Private Thread pages |
@@ -88,5 +88,4 @@ | ||
88 | 88 … | |
89 | 89 … | return [...routes, ...sofar] |
90 | 90 … | }) |
91 | 91 … | } |
92 | - |
state/obs.js | ||
---|---|---|
@@ -25,10 +25,10 @@ | ||
25 | 25 … | var lastTimestamp = opts.last || Date.now() |
26 | 26 … | var firstTimestamp = opts.first || Date.now() |
27 | 27 … | |
28 | 28 … | function unbox (data) { |
29 | - if(data.sync) return data | |
30 | - if(isObject(data.value.content)) return data | |
29 … | + if (data.sync) return data | |
30 … | + if (isObject(data.value.content)) return data | |
31 | 31 … | return api.message.sync.unbox(data) |
32 | 32 … | } |
33 | 33 … | |
34 | 34 … | var obs = PullObv( |
@@ -43,41 +43,39 @@ | ||
43 | 43 … | pull.map(unbox), |
44 | 44 … | pull.filter(Boolean), |
45 | 45 … | api.feed.pull.rollup() |
46 | 46 … | ), |
47 | - //value recovered from localStorage | |
47 … | + // value recovered from localStorage | |
48 | 48 … | initial |
49 | 49 … | ) |
50 | 50 … | |
51 | - //stream live messages. this *should* work. | |
52 | - //there is no back pressure on new events | |
53 | - //only a show more on the top (currently) | |
51 … | + // stream live messages. this *should* work. | |
52 … | + // there is no back pressure on new events | |
53 … | + // only a show more on the top (currently) | |
54 | 54 … | pull( |
55 | 55 … | Next(function () { |
56 | 56 … | return createStream({limit: 500, gt: firstTimestamp, live: true}) |
57 | 57 … | }), |
58 | 58 … | pull.map(unbox), pull.filter(Boolean), |
59 | 59 … | pull.drain(function (data) { |
60 | - if(data.sync) return | |
60 … | + if (data.sync) return | |
61 | 61 … | firstTimestamp = data.timestamp |
62 | 62 … | obs.set(reduce(obs.value, data)) |
63 | 63 … | }) |
64 | 64 … | ) |
65 | 65 … | |
66 | 66 … | return obs |
67 | 67 … | } |
68 | 68 … | |
69 | - | |
70 | 69 … | return nest({ |
71 | - 'state.obs.channel': function (channel) { | |
72 | - | |
70 … | + 'state.obs.channel': function (channel) { | |
73 | 71 … | return createStateObs( |
74 | 72 … | threadReduce, |
75 | 73 … | function (opts) { |
76 | - return opts.reverse ? | |
77 | - api.feed.pull.channel(channel)(opts): | |
78 | - pull(api.sbot.pull.log(opts), pull.filter(function (data) { | |
79 | - if(data.sync) return false | |
74 … | + return opts.reverse | |
75 … | + ? api.feed.pull.channel(channel)(opts) | |
76 … | + : pull(api.sbot.pull.log(opts), pull.filter(function (data) { | |
77 … | + if (data.sync) return false | |
80 | 78 … | return data.value.content.channel === channel |
81 | 79 … | })) |
82 | 80 … | }, |
83 | 81 … | {} |
@@ -86,13 +84,11 @@ | ||
86 | 84 … | // var channelObs = PullObv( |
87 | 85 … | // threadReduce, |
88 | 86 … | // createChannelStream({reverse: true, limit: 1000}) |
89 | 87 … | // ) |
88 … | + }, | |
90 | 89 … | |
91 | - | |
92 | - }, | |
93 | - | |
94 | - 'state.obs.threads': function buildThreadObs() { | |
90 … | + 'state.obs.threads': function buildThreadObs () { | |
95 | 91 … | if (threadsObs) return threadsObs |
96 | 92 … | |
97 | 93 … | // DISABLE localStorage cache. mainly disabling this to make debugging the other stuff |
98 | 94 … | // easier. maybe re-enable this later? also, should this be for every channel too? not sure. |
@@ -105,10 +101,9 @@ | ||
105 | 101 … | |
106 | 102 … | threadsObs = createStateObs(threadReduce, api.sbot.pull.log, initial, {}) |
107 | 103 … | |
108 | 104 … | threadsObs(function (threadsState) { |
109 | - if(threadsState.ended && threadsState.ended !== true) | |
110 | - console.error('threadObs error:', threadsState.ended) | |
105 … | + if (threadsState.ended && threadsState.ended !== true) { console.error('threadObs error:', threadsState.ended) } | |
111 | 106 … | }) |
112 | 107 … | |
113 | 108 … | // var timer |
114 | 109 … | // //keep localStorage up to date |
@@ -125,14 +120,4 @@ | ||
125 | 120 … | return threadsObs |
126 | 121 … | } |
127 | 122 … | }) |
128 | 123 … | } |
129 | - | |
130 | - | |
131 | - | |
132 | - | |
133 | - | |
134 | - | |
135 | - | |
136 | - | |
137 | - | |
138 | - |
styles/css/fontAwesome.js | ||
---|---|---|
@@ -8,5 +8,4 @@ | ||
8 | 8 … | return nest('styles.css', (sofar = {}) => { |
9 | 9 … | return assign(sofar, { css: requireStyle('font-awesome') }) |
10 | 10 … | }) |
11 | 11 … | } |
12 | - |
translations/checker.js | ||
---|---|---|
@@ -9,12 +9,11 @@ | ||
9 | 9 … | function customizer (objVal, srcVal, key, obj, src, stack) { |
10 | 10 … | // See docs https://lodash.com/docs/4.17.4#mergeWith |
11 | 11 … | |
12 | 12 … | if (objVal == undefined) { // implies zh is missing key |
13 | - if (typeof srcVal == 'string') console.log(key, '=', srcVal) | |
13 … | + if (typeof srcVal === 'string') console.log(key, '=', srcVal) | |
14 | 14 … | } |
15 | 15 … | } |
16 | 16 … | |
17 | - | |
18 | 17 … | merge(zh, en, customizer) |
19 | 18 … | // signature: obj, src, customizer |
20 | 19 … | // order matters because of customizer |
translations/en.js | ||
---|---|---|
@@ -13,9 +13,9 @@ | ||
13 | 13 … | ok: 'Okay' |
14 | 14 … | } |
15 | 15 … | }, |
16 | 16 … | blogIndex: { |
17 | - title: 'Discover', | |
17 … | + title: 'Discover' | |
18 | 18 … | }, |
19 | 19 … | topNav: { |
20 | 20 … | blogsAll: 'Dynamics', |
21 | 21 … | blogSearch: 'Search' |
@@ -27,9 +27,9 @@ | ||
27 | 27 … | }, |
28 | 28 … | actions: { |
29 | 29 … | edit: 'Edit', |
30 | 30 … | preview: 'Preview', |
31 | - writeBlog: 'Write a blog', | |
31 … | + writeBlog: 'Write a blog' | |
32 | 32 … | } |
33 | 33 … | }, |
34 | 34 … | channel: 'Channel', |
35 | 35 … | loading: 'Loading...', |
@@ -39,12 +39,12 @@ | ||
39 | 39 … | peopleNearby: 'People nearby', |
40 | 40 … | sendMessage: 'Send', |
41 | 41 … | showMore: 'Show More', |
42 | 42 … | directMessages: 'Direct Messages', |
43 | - home: "Home", | |
44 | - error: "Error", | |
43 … | + home: 'Home', | |
44 … | + error: 'Error', | |
45 | 45 … | errorNotFound: "The page wasn't found", |
46 | - groupNew: "New Group", | |
46 … | + groupNew: 'New Group', | |
47 | 47 … | groupFind: { |
48 | 48 … | action: { |
49 | 49 … | findAGroup: 'Find Group', |
50 | 50 … | newGroup: 'Create this group' |
@@ -55,13 +55,13 @@ | ||
55 | 55 … | flash: { |
56 | 56 … | createFirstThread: 'Start this group by posting the first thread.' |
57 | 57 … | } |
58 | 58 … | }, |
59 | - groupIndex: "Group Index", | |
59 … | + groupIndex: 'Group Index', | |
60 | 60 … | settingsPage: { |
61 | - title: "Settings", | |
61 … | + title: 'Settings', | |
62 | 62 … | action: { |
63 | - edit: 'Edit', | |
63 … | + edit: 'Edit' | |
64 | 64 … | }, |
65 | 65 … | section: { |
66 | 66 … | name: 'Name', |
67 | 67 … | introduction: 'Introduction', |
@@ -75,9 +75,9 @@ | ||
75 | 75 … | find: { |
76 | 76 … | friends: 'Search your friends', |
77 | 77 … | following: "Search people you're following", |
78 | 78 … | followers: 'Search your followers', |
79 | - search: 'Search for a user', | |
79 … | + search: 'Search for a user' | |
80 | 80 … | } |
81 | 81 … | }, |
82 | 82 … | heading: { |
83 | 83 … | people: 'People' |
@@ -91,9 +91,9 @@ | ||
91 | 91 … | threadNew: { |
92 | 92 … | pageTitle: 'New Thread', |
93 | 93 … | field: { |
94 | 94 … | to: 'To', |
95 | - subject: 'Subject', | |
95 … | + subject: 'Subject' | |
96 | 96 … | }, |
97 | 97 … | action: { |
98 | 98 … | new: 'New Message', |
99 | 99 … | addMoreRecps: 'add more recipients (optional)' |
@@ -103,9 +103,9 @@ | ||
103 | 103 … | userEdit: { |
104 | 104 … | section: { |
105 | 105 … | avatar: 'Avatar', |
106 | 106 … | name: 'Name', |
107 | - introduction: 'Introduction', | |
107 … | + introduction: 'Introduction' | |
108 | 108 … | }, |
109 | 109 … | instruction: { |
110 | 110 … | crop: 'Click and drag to crop your avatar' |
111 | 111 … | }, |
@@ -116,9 +116,9 @@ | ||
116 | 116 … | } |
117 | 117 … | }, |
118 | 118 … | userFind: { |
119 | 119 … | action: { |
120 | - findAUser: 'Find a user', | |
120 … | + findAUser: 'Find a user' | |
121 | 121 … | } |
122 | 122 … | }, |
123 | 123 … | userShow: { |
124 | 124 … | action: { |
@@ -133,11 +133,11 @@ | ||
133 | 133 … | state: { |
134 | 134 … | friends: 'You are friends', |
135 | 135 … | youFollow: 'You follow them', |
136 | 136 … | theyFollow: 'They follow you', |
137 | - userIsInGroups: "is in groups:", | |
137 … | + userIsInGroups: 'is in groups:', | |
138 | 138 … | userConversationsWith: 'conversations you\'ve had with', |
139 | - follow: "Follow", | |
139 … | + follow: 'Follow', | |
140 | 140 … | friendsInCommon: 'friends in common' |
141 | 141 … | } |
142 | 142 … | }, |
143 | 143 … | channelShow: { |
@@ -146,10 +146,10 @@ | ||
146 | 146 … | unsubscribe: 'Unsubscribe' |
147 | 147 … | } |
148 | 148 … | }, |
149 | 149 … | subscriptions: { |
150 | - user: "My subscriptions", | |
151 | - friends: "Friends subscriptions", | |
150 … | + user: 'My subscriptions', | |
151 … | + friends: 'Friends subscriptions', | |
152 | 152 … | state: { |
153 | 153 … | noSubscriptions: 'You have no subscriptions yet' |
154 | 154 … | } |
155 | 155 … | }, |
translations/sync.js | ||
---|---|---|
@@ -16,5 +16,4 @@ | ||
16 | 16 … | |
17 | 17 … | return merge({}, languages.en, languages[language]) |
18 | 18 … | }) |
19 | 19 … | } |
20 | - |
translations/zh.js | ||
---|---|---|
@@ -13,32 +13,32 @@ | ||
13 | 13 … | writeComment: '留言', |
14 | 14 … | peopleNearby: '附件的朋友', |
15 | 15 … | addressBook: { |
16 | 16 … | heading: { |
17 | - people: '用户', | |
17 … | + people: '用户' | |
18 | 18 … | }, |
19 | 19 … | section: { |
20 | 20 … | friends: '好友', |
21 | 21 … | following: '我关注的', |
22 | - followers: '关注我的', | |
22 … | + followers: '关注我的' | |
23 | 23 … | }, |
24 | 24 … | action: { |
25 | 25 … | addUser: '添加好友', |
26 | 26 … | find: { |
27 | 27 … | friends: '查找好友', |
28 | 28 … | following: '查找我关注的人', |
29 | 29 … | followers: '查找关注我的人', |
30 | - search: '查找用户', | |
30 … | + search: '查找用户' | |
31 | 31 … | } |
32 | - }, | |
32 … | + } | |
33 | 33 … | }, |
34 | 34 … | blogIndex: { |
35 | 35 … | title: '发现' |
36 | 36 … | }, |
37 | 37 … | blogNew: { |
38 | 38 … | field: { |
39 | 39 … | title: '标题', |
40 | - summary: '序言', | |
40 … | + summary: '序言' | |
41 | 41 … | }, |
42 | 42 … | actions: { |
43 | 43 … | edit: '编辑', |
44 | 44 … | preview: '预览', |
@@ -47,9 +47,9 @@ | ||
47 | 47 … | }, |
48 | 48 … | channelShow: { |
49 | 49 … | action: { |
50 | 50 … | subscribe: '订阅', |
51 | - unsubscribe: '取消订阅', | |
51 … | + unsubscribe: '取消订阅' | |
52 | 52 … | } |
53 | 53 … | }, |
54 | 54 … | topNav: { |
55 | 55 … | blogsAll: '最新', |
@@ -70,9 +70,9 @@ | ||
70 | 70 … | groupIndex: '群组列表', |
71 | 71 … | settingsPage: { |
72 | 72 … | title: '设置', |
73 | 73 … | action: { |
74 | - edit: '编辑', | |
74 … | + edit: '编辑' | |
75 | 75 … | }, |
76 | 76 … | section: { |
77 | 77 … | language: '语言', |
78 | 78 … | profile: '自我介绍', |
@@ -84,13 +84,13 @@ | ||
84 | 84 … | threadNew: { |
85 | 85 … | pageTitle: '新建话题', |
86 | 86 … | field: { |
87 | 87 … | to: '发送给', |
88 | - subject: '主题', | |
88 … | + subject: '主题' | |
89 | 89 … | }, |
90 | 90 … | action: { |
91 | 91 … | new: '创建私信', |
92 | - addMoreRecps: '添加多个用户(可选)', | |
92 … | + addMoreRecps: '添加多个用户(可选)' | |
93 | 93 … | } |
94 | 94 … | }, |
95 | 95 … | threadShow: '所有私信', |
96 | 96 … | userEdit: { |
@@ -104,10 +104,10 @@ | ||
104 | 104 … | }, |
105 | 105 … | action: { |
106 | 106 … | okay: '完成', |
107 | 107 … | cancel: '取消', |
108 | - save: '保存', | |
109 | - }, | |
108 … | + save: '保存' | |
109 … | + } | |
110 | 110 … | }, |
111 | 111 … | userFind: { |
112 | 112 … | action: { |
113 | 113 … | findAUser: '查找用户' |
@@ -120,9 +120,9 @@ | ||
120 | 120 … | directMessage: '创建私信', |
121 | 121 … | block: '拉黑', |
122 | 122 … | unblock: '原谅', |
123 | 123 … | blockConfirmationMessage: '拉黑意味着您再也不会接收到此用户的信息', |
124 | - cancel: '取消', | |
124 … | + cancel: '取消' | |
125 | 125 … | }, |
126 | 126 … | state: { |
127 | 127 … | friends: '你们成为了好友', |
128 | 128 … | youFollow: '你关注了的', |
@@ -136,9 +136,9 @@ | ||
136 | 136 … | subscriptions: { |
137 | 137 … | user: '我的订阅', |
138 | 138 … | friends: '朋友的订阅', |
139 | 139 … | state: { |
140 | - noSubscriptions: '您还没有任何订阅', | |
140 … | + noSubscriptions: '您还没有任何订阅' | |
141 | 141 … | } |
142 | 142 … | }, |
143 | 143 … | languages: { |
144 | 144 … | en: 'English', |
unread.js | ||
---|---|---|
@@ -6,54 +6,51 @@ | ||
6 | 6 … | 'unread.sync.markRead': true, |
7 | 7 … | 'unread.obs.userMessages': true |
8 | 8 … | }) |
9 | 9 … | |
10 | -//load current state of unread messages. | |
10 … | +// load current state of unread messages. | |
11 | 11 … | |
12 | 12 … | exports.create = function (api) { |
13 | - | |
14 | 13 … | var unread = null |
15 | - if(localStorage.unread) { | |
14 … | + if (localStorage.unread) { | |
16 | 15 … | try { |
17 | 16 … | unread = JSON.parse(localStorage.unread) |
18 | 17 … | } catch (err) {} |
19 | 18 … | } |
20 | - if(!unread) | |
21 | - unread = {timestamp: Date.now()} | |
19 … | + if (!unread) { unread = {timestamp: Date.now()} } | |
22 | 20 … | |
23 | 21 … | unread.timestamp = unread.timestamp || Date.now() |
24 | 22 … | |
25 | - if(!unread.filter) | |
26 | - unread.filter = {} | |
23 … | + if (!unread.filter) { unread.filter = {} } | |
27 | 24 … | |
28 | 25 … | var timer |
29 | 26 … | function save () { |
30 | - if(timer) return | |
27 … | + if (timer) return | |
31 | 28 … | |
32 | 29 … | timer = setTimeout(function () { |
33 | 30 … | timer = null |
34 | 31 … | localStorage.unread = JSON.stringify(unread) |
35 | 32 … | }, 2e3) |
36 | 33 … | } |
37 | 34 … | |
38 | - function isUnread(msg) { | |
39 | - if(msg.timestamp && msg.timestamp < unread.timestamp) return false | |
35 … | + function isUnread (msg) { | |
36 … | + if (msg.timestamp && msg.timestamp < unread.timestamp) return false | |
40 | 37 … | return !unread.filter[msg.key] |
41 | 38 … | } |
42 | 39 … | |
43 | - function markRead(msg) { | |
44 | - if(msg && 'string' === typeof msg.key) { | |
45 | - //note: there is a quirk where some messages don't have a timestamp | |
46 | - if(isUnread(msg)) { | |
47 | - var userUser | |
40 … | + function markRead (msg) { | |
41 … | + if (msg && typeof msg.key === 'string') { | |
42 … | + // note: there is a quirk where some messages don't have a timestamp | |
43 … | + if (isUnread(msg)) { | |
44 … | + var userUser | |
48 | 45 … | unread.filter[msg.key] = true |
49 | 46 … | save() |
50 | 47 … | return true |
51 | 48 … | } |
52 | 49 … | } |
53 | 50 … | } |
54 | 51 … | |
55 | - function userMessages(feedId) { | |
52 … | + function userMessages (feedId) { | |
56 | 53 … | |
57 | 54 … | } |
58 | 55 … | |
59 | 56 … | document.body.onunload = save |
@@ -63,5 +60,4 @@ | ||
63 | 60 … | 'unread.sync.markRead': markRead, |
64 | 61 … | 'unread.obs.userMessages': userMessages |
65 | 62 … | }) |
66 | 63 … | } |
67 | - |
Built with git-ssb-web