git ssb

2+

mixmix / ticktack



Commit e2016e7e072aaa1539f05778a0610bd68e812782

wip

mix irving committed on 4/23/2018, 8:05:50 AM
Parent: 0d44fc79a12ebf427d26a10693fcfce4fa2e7451

Files changed

app/page/statsShow.jschanged
app/page/statsShow.mcsschanged
app/page/statsShow.jsView
@@ -1,11 +1,12 @@
11 const nest = require('depnest')
2-const { h, resolve, when, Value, Struct, Array: MutantArray, Dict, onceTrue, map, computed, dictToCollection, throttle } = require('mutant')
2+const { h, resolve, when, Value, Struct, Array: MutantArray, Dict, onceTrue, map, computed, dictToCollection, throttle, watchAll } = require('mutant')
33 const pull = require('pull-stream')
44 const marksum = require('markdown-summary')
55 const Chart = require('chart.js')
66 const groupBy = require('lodash/groupBy')
7-const merge = require('lodash/merge')
7+const mergeWith = require('lodash/mergeWith')
8+const flatMap = require('lodash/flatMap')
89
910 exports.gives = nest('app.page.statsShow')
1011
1112 exports.needs = nest({
@@ -21,80 +22,111 @@
2122 blogs: MutantArray([]),
2223 comments: Dict(),
2324 likes: Dict()
2425 })
26+ onceTrue(api.sbot.obs.connection, server => {
27+ fetchBlogs({ server, store })
28+ })
2529
2630 var howFarBack = Value(0)
2731 // stats show a moving window of 30 days
2832 const THIRTY_DAYS = 30 * 24 * 60 * 60 * 1000
2933
30- // TODO
31- var range = computed([howFarBack], howFarBack => {
32- const now = Date.now()
33- return {
34- upper: now - howFarBack * THIRTY_DAYS,
35- lower: now - (howFarBack + 1) * THIRTY_DAYS
36- }
34+ const COMMENTS = 'comments'
35+ const LIKES = 'likes'
36+ var context = Struct({
37+ focus: Value(COMMENTS),
38+ blog: Value(),
39+ range: computed([howFarBack], howFarBack => {
40+ const now = Date.now()
41+ return {
42+ upper: now - howFarBack * THIRTY_DAYS,
43+ lower: now - (howFarBack + 1) * THIRTY_DAYS
44+ }
45+ })
3746 })
3847
39- var commentsAll = computed(throttle(dictToCollection(store.comments), 1000), (comments) => {
40- return comments
48+ var commentsAll = computed(throttle(dictToCollection(store.comments), 1000), (msgs) => {
49+ return msgs
4150 .map(c => c.value)
4251 .reduce((n, sofar) => [...n, ...sofar], [])
4352 })
53+ // var commentsAll = computed([throttle(store.comments, 1000)], (msgs) => {
54+ // return flatMap(msgs, (val, key) => {
55+ // console.log(key, val)
56+ // return val
57+ // })
58+ // })
4459
45- // this should perhaps be reduced to just return commentsContextCount
46- var visibleComments = computed([commentsAll, range], (comments, range) => {
47- return comments
60+ var visibleCommentsCount = computed([commentsAll, context.range], (msgs, range) => {
61+ return msgs
4862 .filter(msg => {
4963 const ts = msg.value.timestamp
5064 return ts >= range.lower && ts <= range.upper
5165 })
66+ .length
5267 })
5368
54- var rangeLikes = computed([throttle(dictToCollection(store.likes), 1000), range], (likes, range) => {
55- return likes
69+ var likesAll = computed(throttle(dictToCollection(store.likes), 1000), (msgs) => {
70+ return msgs
5671 .map(c => c.value)
5772 .reduce((n, sofar) => [...n, ...sofar], [])
58- // .filter(msg => {
59- // const ts = msg.value.timestamp
60- // return ts >= range.lower && ts <= range.upper
61- // })
6273 })
6374
64- onceTrue(api.sbot.obs.connection, server => {
65- fetchBlogs({ server, store })
75+ var visibleLikesCount = computed([likesAll, context.range], (msgs, range) => {
76+ return msgs
77+ .filter(msg => {
78+ const ts = msg.value.timestamp
79+ return ts >= range.lower && ts <= range.upper
80+ })
81+ .length
82+ })
6683
67- // const query = {
68- // gt: ['C', null, range().lower],
69- // lt: ['C', undefined, range().upper],
70- // reverse: true,
71- // values: true,
72- // keys: false,
73- // seqs: false
74- // }
75- // console.log('test query', query)
76- // pull(server.blogStats.read(query), pull.log(() => console.log('DONE')))
84+ var focused = Struct({
85+ [LIKES]: commentsAll,
86+ [COMMENTS]: likesAll
7787 })
88+
7889 const canvas = h('canvas', { height: 200, width: 600, style: { height: '200px', width: '600px' } })
7990
91+ const displayComments = () => context.focus.set(COMMENTS)
92+ const displayLikes = () => context.focus.set(LIKES)
93+
8094 const page = h('Page -statsShow', [
8195 h('Scroller.content', [
82- h('div.content', [
96+ h('div.content', [
8397 h('h1', 'Stats'),
8498 h('section.totals', [
85- h('div.comments', [
86- h('div.count', computed(visibleComments, msgs => msgs.length)),
87- h('strong', 'Comments'),
88- '(30 days)'
89- ]),
90- h('div.likes', [
91- h('div.count', computed(rangeLikes, msgs => msgs.length)),
92- h('strong', 'Likes'),
93- '(30 days)'
94- ]),
95- h('div.shares', [
96- ])
99+ h('div.comments',
100+ {
101+ className: computed(context.focus, focus => focus === COMMENTS ? '-selected' : ''),
102+ 'ev-click': displayComments
103+ }, [
104+ h('div.count', visibleCommentsCount),
105+ h('strong', 'Comments'),
106+ '(30 days)'
107+ ]),
108+ h('div.likes',
109+ {
110+ className: computed(context.focus, focus => focus === LIKES ? '-selected' : ''),
111+ 'ev-click': displayLikes
112+ }, [
113+ h('div.count', visibleLikesCount),
114+ h('strong', 'Likes'),
115+ '(30 days)'
116+ ]
117+ ),
118+ h('div.shares',
119+ {
120+ className: when(context.shares, '-selected')
121+ // 'ev-click': displayShares
122+ }, [
123+ // h('div.count', computed(rangeLikes, msgs => msgs.length)),
124+ h('div.count', '--'),
125+ h('strong', 'Shares'),
126+ '(30 days)'
127+ ]
128+ )
97129 ]),
98130 h('section.graph', [
99131 canvas,
100132 h('div.changeRange', [
@@ -135,17 +167,25 @@
135167 ])
136168 ])
137169 ])
138170
139- // Chart.scaleService.updateScaleDefaults('linear', {
140- // ticks: { min: 0 }
141- // })
142- var chart = new Chart(canvas.getContext('2d'), chartConfig({ range, chartData: [] }))
171+ var chart = new Chart(canvas.getContext('2d'), chartConfig({ context, chartData: [] }))
143172
144173 const toDay = ts => Math.floor(ts / (24 * 60 * 60 * 1000))
145174
146- // TODO take in context (comments/ likes / shares)
147- const chartData = computed(commentsAll, msgs => {
175+ // HACK - if the focus has changed, then zero the data
176+ // this prevents the graph from showing some confusing animations when transforming between foci
177+ var lastFocus = context.focus()
178+ const zeroGraphOnFocusChange = (focus) => {
179+ if (focus !== lastFocus) {
180+ chart.data.datasets[0].data = []
181+ chart.update()
182+ lastFocus = focus
183+ }
184+ }
185+ const chartData = computed([context.focus, focused], (focus, focused) => {
186+ zeroGraphOnFocusChange(focus)
187+ const msgs = focused[focus]
148188 const grouped = groupBy(msgs, m => toDay(m.value.timestamp))
149189
150190 var data = Object.keys(grouped)
151191 .map(day => {
@@ -156,18 +196,39 @@
156196 })
157197 return data
158198 })
159199
160- chartData(() => {
161- chart = merge(chart, chartConfig({ range, chartData }))
200+ chartData(data => {
201+ chart.data.datasets[0].data = data
202+
162203 chart.update()
163204 })
164205
165- range(() => {
166- chart = merge(chart, chartConfig({ range, chartData }))
206+ const graphHeight = computed([chartData, context.range], (data, range) => {
207+ const { lower, upper } = range
208+ const slice = data
209+ .filter(d => d.t >= lower && d.t <= upper)
210+ .map(d => d.y)
211+ .sort((a, b) => a < b)
212+ const localMax = slice[0] ? Math.max(slice[0], 10) : 10
213+
214+ return localMax + (5 - localMax % 5)
215+ })
216+ graphHeight(h => {
217+ chart.options.scales.yAxes[0].ticks.max = h
218+
167219 chart.update()
168220 })
169221
222+ context.range(range => {
223+ const { lower, upper } = range
224+
225+ chart.options.scales.xAxes[0].time.min = new Date(lower)
226+ chart.options.scales.xAxes[0].time.max = new Date(upper)
227+
228+ chart.update()
229+ })
230+
170231 return page
171232 }
172233
173234 function viewBlog (blog) {
@@ -218,10 +279,10 @@
218279 })
219280 )
220281 }
221282
222-function chartConfig ({ range, chartData }) {
223- const { lower, upper } = resolve(range)
283+function chartConfig ({ context, chartData }) {
284+ const { lower, upper } = resolve(context.range)
224285
225286 const data = resolve(chartData) || []
226287 const slice = data
227288 .filter(d => d.t >= lower && d.t <= upper)
@@ -232,12 +293,11 @@
232293 return {
233294 type: 'bar',
234295 data: {
235296 datasets: [{
236- // label: 'My First dataset',
237- backgroundColor: 'hsla(215, 57%, 60%, 1)', // 'hsla(215, 57%, 43%, 1)',
297+ backgroundColor: 'hsla(215, 57%, 60%, 1)',
298+ // Ticktack Primary color:'hsla(215, 57%, 43%, 1)',
238299 borderColor: 'hsla(215, 57%, 60%, 1)',
239- // TODO set initial data as empty to make a good range
240300 data
241301 }]
242302 },
243303 options: {
@@ -267,15 +327,16 @@
267327
268328 yAxes: [{
269329 ticks: {
270330 min: 0,
271- max: Math.max(localMax, 10),
331+ suggestedMax: 10,
332+ // max: Math.max(localMax, 10),
272333 stepSize: 5
273334 }
274335 }]
275336 },
276337 animation: {
277- // duration: 300
338+ // duration: 300
278339 }
279340 }
280341 }
281342 }
app/page/statsShow.mcssView
@@ -15,11 +15,30 @@
1515 }
1616
1717 section.totals {
1818 display: flex
19- justify-content: space-between
2019
2120 div {
21+ flex-grow: 1
22+
23+ cursor: pointer
24+ padding: 0 0 .5rem .5rem
25+ $colorFontSubtle
26+ padding: 0 0 .5rem .5rem
27+ border-bottom: 1px solid gainsboro
28+ border-right: 1px solid gainsboro
29+
30+ transition: all ease-out .5s
31+ :hover {
32+ $colorFontBasic
33+ transition: all ease-out .5s
34+ }
35+
36+ -selected {
37+ $colorFontBasic
38+ border-bottom: 1px solid #fff
39+ }
40+
2241 div.count {
2342 font-size: 3rem
2443 font-weight: 600
2544 margin-right: .5rem
@@ -27,8 +46,13 @@
2746 strong {
2847 margin-right: .5rem
2948 }
3049 }
50+
51+
52+ div.shares {
53+ border-right: none
54+ }
3155 }
3256
3357 section.graph {
3458 display: flex

Built with git-ssb-web