git ssb

2+

mixmix / ticktack



Commit ee8e82af460b4067e37ca225319fad117e33b584

add notifications page, notifications sideNav, wip comments source

mix irving committed on 4/30/2018, 6:39:33 AM
Parent: 290057bfce673063c5629dd99de5b67dab52483a

Files changed

app/html/sideNav/sideNavNotifications.jsadded
app/html/sideNav/sideNavNotifications.mcssadded
app/index.jschanged
app/page/addressBook.jschanged
app/page/statsShow.jschanged
app/page/notifications.jsadded
package.jsonchanged
router/sync/routes.jschanged
ssb-server-blog-stats.jschanged
translations/en.jschanged
app/html/sideNav/sideNavNotifications.jsView
@@ -1,0 +1,69 @@
1+const nest = require('depnest')
2+const { h, computed } = require('mutant')
3+
4+exports.gives = nest({
5+ 'app.html.sideNav': true
6+})
7+
8+exports.needs = nest({
9+ 'history.sync.push': 'first',
10+ 'translations.sync.strings': 'first'
11+})
12+
13+const SECTIONS = ['comments', 'likes', 'shares']
14+
15+const ICONS = {
16+ stats: 'bar-chart',
17+ comments: 'commenting-o',
18+ likes: 'heart-o',
19+ shares: 'share-alt'
20+}
21+
22+exports.create = (api) => {
23+ return nest({
24+ 'app.html.sideNav': sideNav
25+ })
26+
27+ function sideNav (location) {
28+ if (location.page !== 'statsShow' && location.page !== 'notifications') return
29+ if (location.page === 'notifications' && !SECTIONS.includes(location.section)) return
30+
31+ const strings = api.translations.sync.strings()
32+ const goTo = (loc) => () => api.history.sync.push(loc)
33+
34+ return h('SideNav -notifications', [
35+ LevelOneSideNav()
36+ ])
37+
38+ function LevelOneSideNav () {
39+ return h('div.level.-one', [
40+ h('section', [
41+ h('Option',
42+ {
43+ className: location.page === 'statsShow' ? '-selected' : '',
44+ 'ev-click': goTo({page: 'statsShow'})
45+ },
46+ [
47+ h('i.fa', { className: `fa-${ICONS['stats']}` }),
48+ strings['stats']
49+ ]
50+ ),
51+ SECTIONS.map(section => SectionOption(section))
52+ ])
53+ ])
54+ }
55+
56+ function SectionOption (section) {
57+ return h('Option',
58+ {
59+ className: location.section === section ? '-selected' : '',
60+ 'ev-click': goTo({page: 'notifications', section})
61+ },
62+ [
63+ h('i.fa', { className: `fa-${ICONS[section]}` }),
64+ strings[section]
65+ ]
66+ )
67+ }
68+ }
69+}
app/html/sideNav/sideNavNotifications.mcssView
@@ -1,0 +1,30 @@
1+SideNav -notifications {
2+ div.level {
3+ section{
4+ header {
5+ font-size: .8rem
6+ }
7+
8+ div.Option {
9+ display: flex
10+
11+ div.Button {
12+ flex-grow: 1
13+ margin: .5rem 0
14+ }
15+
16+ i.fa {
17+ margin-right: .5rem
18+ }
19+
20+ div.count {
21+ flex-grow: 1
22+
23+ display: flex
24+ justify-content: flex-end
25+ }
26+ }
27+ }
28+ }
29+}
30+
app/index.jsView
@@ -18,9 +18,10 @@
1818 },
1919 scroller: require('./html/scroller'),
2020 sideNav: {
2121 addressBook: require('./html/sideNav/sideNavAddressBook'),
22- discovery: require('./html/sideNav/sideNavDiscovery')
22+ discovery: require('./html/sideNav/sideNavDiscovery'),
23+ notifications: require('./html/sideNav/sideNavNotifications')
2324 },
2425 warning: require('./html/warning'),
2526 },
2627 obs: {
@@ -32,21 +33,22 @@
3233 blogNew: require('./page/blogNew'),
3334 blogSearch: require('./page/blogSearch'),
3435 blogShow: require('./page/blogShow'),
3536 channelShow: require('./page/channelShow'),
36- error: require('./page/error'),
37- settings: require('./page/settings'),
3837 channelSubscriptions: require('./page/channelSubscriptions'),
3938 // channel: require('./page/channel'),
4039 // image: require('./page/image'),
4140 // groupFind: require('./page/groupFind'),
4241 // groupIndex: require('./page/groupIndex'),
4342 // groupNew: require('./page/groupNew'),
4443 // groupShow: require('./page/groupShow'),
4544 // threadShow: require('./page/threadShow'),
45+ notifications: require('./page/notifications'),
46+ error: require('./page/error'),
4647 userEdit: require('./page/userEdit'),
4748 // userFind: require('./page/userFind'),
4849 userShow: require('./page/userShow'),
50+ settings: require('./page/settings'),
4951 splash: require('./page/splash'),
5052 statsShow: require('./page/statsShow'),
5153 threadNew: require('./page/threadNew'),
5254 threadShow: require('./page/threadShow')
app/page/addressBook.jsView
@@ -1,7 +1,6 @@
11 const nest = require('depnest')
22 const { h, Value, computed, map } = require('mutant')
3-const pull = require('pull-stream')
43
54 exports.gives = nest('app.page.addressBook')
65
76 // declare consts to avoid magic-string errors
@@ -13,10 +12,8 @@
1312 exports.needs = nest({
1413 'about.html.avatar': 'first',
1514 'about.async.suggest': 'first',
1615 'about.obs.name': 'first',
17- 'app.html.topNav': 'first',
18- // 'app.html.scroller': 'first',
1916 'app.html.sideNav': 'first',
2017 'app.html.topNav': 'first',
2118 'contact.html.follow': 'first',
2219 'contact.obs.relationships': 'first',
@@ -26,9 +23,9 @@
2623 })
2724
2825 exports.create = (api) => {
2926 return nest('app.page.addressBook', function (location) {
30- // location here can expected to be: { page: 'addressBook'}
27+ // location here can expected to be: { page: 'addressBook', section: '...'}
3128
3229 const strings = api.translations.sync.strings()
3330 const myKey = api.keys.sync.id()
3431 const relationships = api.contact.obs.relationships(myKey)
app/page/statsShow.jsView
@@ -9,11 +9,12 @@
99
1010 exports.gives = nest('app.page.statsShow')
1111
1212 exports.needs = nest({
13- 'sbot.obs.connection': 'first',
13+ 'app.html.sideNav': 'first',
1414 'history.sync.push': 'first',
1515 'message.html.markdown': 'first',
16+ 'sbot.obs.connection': 'first',
1617 'translations.sync.strings': 'first'
1718 })
1819
1920 const COMMENTS = 'comments'
@@ -91,8 +92,9 @@
9192
9293 const canvas = h('canvas', { height: 200, width: 600, style: { height: '200px', width: '600px' } })
9394
9495 const page = h('Page -statsShow', [
96+ api.app.html.sideNav(location),
9597 h('Scroller.content', [
9698 h('div.content', [
9799 h('h1', t.title),
98100 h('section.totals', [COMMENTS, LIKES, SHARES].map(focus => {
app/page/notifications.jsView
@@ -1,0 +1,140 @@
1+const nest = require('depnest')
2+const { h, onceTrue, throttle, Value, Array: MutantArray, map, resolve } = require('mutant')
3+const pull = require('pull-stream')
4+
5+exports.gives = nest('app.page.notifications')
6+
7+exports.needs = nest({
8+ // 'app.html.blogCard': 'first',
9+ // 'app.html.topNav': 'first',
10+ // 'app.html.scroller': 'first',
11+ 'app.html.sideNav': 'first',
12+ // 'blog.sync.isBlog': 'first',
13+ // 'feed.pull.public': 'first',
14+ // 'feed.pull.type': 'first',
15+ // 'history.sync.push': 'first',
16+ // 'keys.sync.id': 'first',
17+ // 'message.sync.isBlocked': 'first',
18+ 'sbot.obs.connection': 'first',
19+ 'translations.sync.strings': 'first'
20+ // 'unread.sync.isUnread': 'first'
21+})
22+
23+exports.create = (api) => {
24+ // var blogsCache = MutantArray()
25+
26+ return nest('app.page.notifications', function (location) {
27+ // location here can expected to be: { page: 'notifications'}
28+
29+ var strings = api.translations.sync.strings()
30+
31+ var commentsStore = MutantArray([])
32+
33+ onceTrue(api.sbot.obs.connection, server => {
34+ console.log('methods', server.blogStats)
35+ pull(
36+ server.blogStats.readAllComments(),
37+ pull.drain(m => {
38+ commentsStore.push(m)
39+ })
40+ )
41+ })
42+
43+ // server.blogStats.getBlogs({ keys: true, values: false }, (err, data) => {
44+ // if (err) throw err
45+
46+ // const blogIds = data.map(d => d[1])
47+
48+ // var source = server.blogStats.read({
49+ // // live: true,
50+ // gte: [ 'C', undefined, undefined ],
51+ // lte: [ 'C~', null, null ],
52+ // reverse: true,
53+ // values: true,
54+ // keys: true,
55+ // seqs: false
56+ // })
57+ // console.log(blogIds)
58+
59+ // pull(
60+ // source,
61+ // pull.filter(result => {
62+ // return blogIds.includes(result.key[1])
63+ // }),
64+ // pull.map(result => result.value),
65+ // pull.drain(m => {
66+ // commentsStore.push(m)
67+ // })
68+ // )
69+ // })
70+ // })
71+
72+ // var blogs = api.app.html.scroller({
73+ // classList: ['content'],
74+ // prepend: api.app.html.topNav(location),
75+ // // stream: api.feed.pull.public,
76+ // stream: api.feed.pull.type('blog'),
77+ // filter: () => pull(
78+ // // pull.filter(api.blog.sync.isBlog),
79+ // pull.filter(msg => !msg.value.content.root), // show only root messages
80+ // pull.filter(msg => !api.message.sync.isBlocked(msg))
81+ // ),
82+ // // FUTURE : if we need better perf, we can add a persistent cache. At the moment this page is fast enough though.
83+ // // See implementation of app.html.sideNav for example
84+ // store: blogsCache,
85+ // updateTop: update,
86+ // updateBottom: update,
87+ // render
88+ // })
89+
90+ return h('Page -notifications', [
91+ api.app.html.sideNav(location),
92+ h('div.content', map(throttle(commentsStore, 300), comment => {
93+ const text = comment.value.content.text
94+
95+ return h('p', { style: { margin: '1rem' } }, text)
96+ }))
97+ ])
98+ })
99+
100+/* function update (soFar, newBlog) { */
101+// soFar.transaction(() => {
102+// const { timestamp } = newBlog.value
103+
104+// var object = newBlog // Value(newBlog)
105+
106+// const index = indexOf(soFar, (blog) => newBlog.key === resolve(blog).key)
107+// // if blog already in cache, not needed again
108+// if (index >= 0) return
109+
110+// // Orders by: time received
111+// const justOlderPosition = indexOf(soFar, (msg) => newBlog.timestamp > resolve(msg).timestamp)
112+
113+// // Orders by: time published BUT the messagesByType stream streams _by time received_
114+// // TODO - we need an index of all blogs otherwise the scroller doesn't work...
115+// // const justOlderPosition = indexOf(soFar, (msg) => timestamp > resolve(msg).value.timestamp)
116+
117+// if (justOlderPosition > -1) {
118+// soFar.insert(object, justOlderPosition)
119+// } else {
120+// soFar.push(object)
121+// }
122+// })
123+// }
124+
125+// function render (blog) {
126+// const { recps, channel } = blog.value.content
127+// var onClick
128+// if (channel && !recps) { onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' })) }
129+// return api.app.html.blogCard(blog, { onClick })
130+// }
131+// }
132+
133+// function indexOf (array, fn) {
134+// for (var i = 0; i < array.getLength(); i++) {
135+// if (fn(array.get(i))) {
136+// return i
137+// }
138+// }
139+// return -1
140+}
package.jsonView
@@ -49,8 +49,9 @@
4949 "patch-profile": "^1.0.4",
5050 "patch-settings": "^1.0.0",
5151 "patch-suggest": "^1.1.0",
5252 "patchcore": "^1.23.3",
53+ "pull-defer": "^0.2.2",
5354 "pull-next": "^1.0.1",
5455 "pull-next-step": "^1.0.0",
5556 "pull-obv": "^1.3.0",
5657 "pull-stream": "^3.6.0",
router/sync/routes.jsView
@@ -14,8 +14,9 @@
1414 'app.page.blogShow': 'first',
1515 'app.page.settings': 'first',
1616 'app.page.channelSubscriptions': 'first',
1717 'app.page.channelShow': 'first',
18+ 'app.page.notifications': 'first',
1819 // 'app.page.channel': 'first',
1920 // 'app.page.groupFind': 'first',
2021 // 'app.page.groupIndex': 'first',
2122 // 'app.page.groupNew': 'first',
@@ -55,10 +56,11 @@
5556 [ location => location.page === 'channelSubscriptions', pages.channelSubscriptions ],
5657 [ location => location.page === 'channelShow', pages.channelShow ],
5758 [ location => location.channel, pages.channelShow ],
5859
59- // Stats pages
60+ // Stats / Notifications pages
6061 [ location => location.page === 'statsShow', pages.statsShow ],
62+ [ location => location.page === 'notifications', pages.notifications ],
6163
6264 // AddressBook pages
6365 [ location => location.page === 'addressBook', pages.addressBook ],
6466
ssb-server-blog-stats.jsView
@@ -1,7 +1,8 @@
11 const FlumeView = require('flumeview-level')
22 const get = require('lodash/get')
33 const pull = require('pull-stream')
4+const defer = require('pull-defer')
45 const isBlog = require('scuttle-blog/isBlog')
56 const { isMsg: isMsgRef } = require('ssb-ref')
67
78 const getType = (msg) => get(msg, 'value.content.type')
@@ -20,8 +21,9 @@
2021 read: 'source',
2122 readBlogs: 'source',
2223 getBlogs: 'async',
2324 readComments: 'source',
25+ readAllComments: 'source', // TEMP
2426 readLikes: 'source'
2527 },
2628 init: (server, config) => {
2729 console.log('initialising blog-stats plugin')
@@ -37,8 +39,9 @@
3739 read: view.read,
3840 readBlogs,
3941 getBlogs,
4042 readComments,
43+ readAllComments,
4144 readLikes
4245 // readShares
4346 }
4447
@@ -95,8 +98,13 @@
9598 return view.read(query)
9699 }
97100
98101 function getBlogs (options, cb) {
102+ if (typeof options === 'function') {
103+ cb = options
104+ options = {}
105+ }
106+
99107 pull(
100108 readBlogs(options),
101109 pull.collect(cb)
102110 )
@@ -117,8 +125,45 @@
117125
118126 return view.read(query)
119127 }
120128
129+ function readAllComments () {
130+ var source = defer.source()
131+
132+ getBlogs({ keys: true, values: false }, (err, data) => {
133+ if (err) throw err
134+
135+ const blogIds = data.map(d => d[1])
136+
137+ const _source = pull(
138+ view.read({
139+ // live: true,
140+ gt: [ 'B~', undefined, undefined ],
141+ lt: [ 'C~', null, null ],
142+ reverse: true,
143+ values: true,
144+ keys: true,
145+ seqs: false
146+ }),
147+ pull.filter(result => {
148+ return blogIds.includes(result.key[1])
149+ }),
150+ pull.map(result => result.value)
151+ )
152+
153+ // pull(
154+ // _source,
155+ // pull.log()
156+ // )
157+ source.resolve(_source)
158+ // source.resolve(pull.values([1, 2, 3, 4, ':)']))
159+ })
160+
161+ return pull(
162+ source
163+ )
164+ }
165+
121166 function readLikes (blog, options = {}) {
122167 var key = getBlogKey(blog)
123168
124169 const query = Object.assign({}, {
translations/en.jsView
@@ -1,5 +1,6 @@
11 module.exports = {
2+ stats: 'Stats',
23 comments: 'Comments',
34 likes: 'Likes',
45 shares: 'Shares',
56 splash: {

Built with git-ssb-web