git ssb

2+

mixmix / ticktack



Tree: 4affbf9d002205c0d8fe516be4f046bf898ea555

Files: 4affbf9d002205c0d8fe516be4f046bf898ea555 / app / page / home.js

4178 bytesRaw
1const nest = require('depnest')
2const { h } = require('mutant')
3const {threadReduce} = require('ssb-reduce-stream')
4const pull = require('pull-stream')
5const isObject = require('lodash/isObject')
6const isString = require('lodash/isString')
7const last = require('lodash/last')
8const get = require('lodash/get')
9const More = require('hypermore')
10exports.gives = nest('app.page.home')
11const morphdom = require('morphdom')
12const Next = require('pull-next')
13
14exports.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
22function firstLine (text) {
23 if(text.length < 80 && !~text.indexOf('\n')) return text
24
25 return text.split('\n')[0].substring(0, 80)
26}
27
28exports.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