Files: 4affbf9d002205c0d8fe516be4f046bf898ea555 / app / page / home.js
4178 bytesRaw
1 | const nest = require('depnest') |
2 | const { h } = require('mutant') |
3 | const {threadReduce} = require('ssb-reduce-stream') |
4 | const pull = require('pull-stream') |
5 | const isObject = require('lodash/isObject') |
6 | const isString = require('lodash/isString') |
7 | const last = require('lodash/last') |
8 | const get = require('lodash/get') |
9 | const More = require('hypermore') |
10 | exports.gives = nest('app.page.home') |
11 | const morphdom = require('morphdom') |
12 | const Next = require('pull-next') |
13 | |
14 | exports.needs = nest({ |
15 | 'about.html.image': 'first', |
16 | 'app.html.nav': 'first', |
17 | 'sbot.pull.log': 'first', |
18 | 'history.sync.push': 'first', |
19 | 'message.sync.unbox': 'first', |
20 | }) |
21 | |
22 | function firstLine (text) { |
23 | if(text.length < 80 && !~text.indexOf('\n')) return text |
24 | |
25 | return text.split('\n')[0].substring(0, 80) |
26 | } |
27 | |
28 | exports.create = (api) => { |
29 | return nest('app.page.home', function (location) { |
30 | // location here can expected to be: { page: 'home' } |
31 | |
32 | var container = h('div.container', []) |
33 | |
34 | function subject (msg) { |
35 | const { subject, text } = msg.value.content |
36 | return firstLine(subject|| text) |
37 | } |
38 | |
39 | function link(location) { |
40 | return {'ev-click': () => api.history.sync.push(location)} |
41 | } |
42 | |
43 | function item (name, thread) { |
44 | if(!thread.value) return |
45 | const lastReply = thread.replies && last(thread.replies) |
46 | |
47 | return h('div.threadLink', link(thread), [ |
48 | name, |
49 | h('div.subject', [subject(thread)]), |
50 | lastReply ? h('div.reply', [subject(lastReply)]) : null |
51 | ]) |
52 | } |
53 | |
54 | function threadGroup (threads, obj, toName) { |
55 | // threads = a state object for all the types of threads |
56 | // obj = a map of keys to root ids, where key ∈ (channel | group | concatenated list of pubkeys) |
57 | // toName = fn that derives a name from a particular thread |
58 | |
59 | var groupEl = h('div.group') |
60 | for(var k in obj) { |
61 | var id = obj[k] |
62 | var thread = get(threads, ['roots', id]) |
63 | if(thread && thread.value) { |
64 | var el = item(toName(k, thread), thread) |
65 | if(el) groupEl.appendChild(el) |
66 | } |
67 | } |
68 | return groupEl |
69 | } |
70 | |
71 | var initial |
72 | try { initial = JSON.parse(localStorage.threadsState) } |
73 | catch (_) { } |
74 | var lastTimestamp = initial ? initial.last : Date.now() |
75 | |
76 | var timer |
77 | function update (threadsState) { |
78 | clearTimeout(timer) |
79 | setTimeout(function () { |
80 | threadsState.last = lastTimestamp |
81 | localStorage.threadsState = JSON.stringify(threadsState) |
82 | }, 1000) |
83 | } |
84 | |
85 | var threadsObs = More( |
86 | threadReduce, |
87 | pull( |
88 | Next(function () { |
89 | return api.sbot.pull.log({reverse: true, limit: 500, lte: lastTimestamp}) |
90 | }), |
91 | pull.map(function (data) { |
92 | lastTimestamp = data.timestamp |
93 | if(isObject(data.value.content)) return data |
94 | return api.message.sync.unbox(data) |
95 | }), |
96 | pull.filter(Boolean), |
97 | function (read) { |
98 | return function (abort, cb) { |
99 | read(abort, function (err, data) { |
100 | try { |
101 | cb(err, data) |
102 | } catch (err) { |
103 | console.error(err) |
104 | read(err, function () {}) |
105 | } |
106 | }) |
107 | } |
108 | } |
109 | ), |
110 | function render (threadsState) { |
111 | update(threadsState) |
112 | morphdom(container, |
113 | h('div.container', [ |
114 | threadGroup( |
115 | threadsState, |
116 | threadsState.private, |
117 | function (_, msg) { |
118 | // NB: msg passed in is actually a 'thread', but only care about root msg |
119 | return h('div.recps', [ |
120 | msg.value.content.recps.map(function (link) { |
121 | return api.about.html.image(isString(link) ? link : link.link) |
122 | }) |
123 | ]) |
124 | } |
125 | ), |
126 | threadGroup( |
127 | threadsState, |
128 | threadsState.channels, |
129 | ch => h('h2.title', '#'+ch) |
130 | ) |
131 | ]) |
132 | ) |
133 | return container |
134 | }, |
135 | initial |
136 | ) |
137 | |
138 | return h('Page -home', [ |
139 | h('h1', 'Home'), |
140 | api.app.html.nav(), |
141 | threadsObs, |
142 | h('button', {'ev-click': threadsObs.more}, ['Show More']) |
143 | ]) |
144 | }) |
145 | } |
146 | |
147 |
Built with git-ssb-web