app/page/calendar.jsView |
---|
1 | 1 … | const nest = require('depnest') |
2 | | -const { h, Value, computed, Dict, throttle, dictToCollection } = require('mutant') |
| 2 … | +const { h, Array: MutantArray, Struct, computed, watch, throttle } = require('mutant') |
3 | 3 … | const pull = require('pull-stream') |
4 | 4 … | const { isMsg } = require('ssb-ref') |
5 | 5 … | |
6 | 6 … | exports.gives = nest('app.page.calendar') |
12 | 12 … | exports.create = (api) => { |
13 | 13 … | return nest('app.page.calendar', calendarPage) |
14 | 14 … | |
15 | 15 … | function calendarPage (location) { |
16 | | - const store = Dict({}) |
17 | | - pull( |
18 | | - pullGatherings(2018), |
19 | | - pull.drain( |
20 | | - ({ key, date }) => store.put(key, date), |
21 | | - (err) => { |
22 | | - if (err) console.error(err) |
23 | | - else console.log('DONE') |
24 | | - } |
25 | | - ) |
26 | | - ) |
| 16 … | + const d = new Date() |
| 17 … | + const state = Struct({ |
| 18 … | + today: new Date(d.getFullYear(), d.getMonth(), d.getDate()), |
| 19 … | + year: d.getFullYear(), |
| 20 … | + events: MutantArray([]) |
| 21 … | + }) |
27 | 22 … | |
|
| 23 … | + watch(state.year, year => getEvents(year, state.events)) |
| 24 … | + |
28 | 25 … | return h('CalendarPage', { title: '/calendar' }, [ |
29 | | - computed(throttle(dictToCollection(store), 150), collection => { |
30 | | - const events = collection.map(item => { |
31 | | - return { |
32 | | - date: item.value, |
33 | | - data: { key: item.key } |
34 | | - } |
35 | | - }) |
36 | | - |
37 | | - return Calendar(events) |
38 | | - }) |
| 26 … | + Calendar(state) |
39 | 27 … | ]) |
40 | 28 … | } |
41 | 29 … | |
42 | | - function pullGatherings (year) { |
| 30 … | + function getEvents (year, events) { |
43 | 31 … | const query = [{ |
44 | 32 … | $filter: { |
45 | 33 … | value: { |
46 | 34 … | timestamp: {$gt: Number(new Date(year, 0, 1))}, |
60 | 48 … | }] |
61 | 49 … | |
62 | 50 … | const opts = { |
63 | 51 … | reverse: false, |
| 52 … | + live: true, |
64 | 53 … | query |
65 | 54 … | } |
66 | 55 … | |
67 | | - return pull( |
| 56 … | + pull( |
68 | 57 … | api.sbot.pull.stream(server => server.query.read(opts)), |
| 58 … | + pull.filter(m => !m.sync), |
69 | 59 … | pull.filter(r => isMsg(r.key) && Number.isInteger(r.date)), |
70 | 60 … | pull.map(r => { |
71 | 61 … | return { key: r.key, date: new Date(r.date) } |
| 62 … | + }), |
| 63 … | + pull.drain(({ key, date }) => { |
| 64 … | + var target = events.find(ev => ev.data.key === key) |
| 65 … | + if (target && target.date <= date) events.delete(target) |
| 66 … | + |
| 67 … | + events.push({ date, data: { key } }) |
72 | 68 … | }) |
73 | 69 … | ) |
74 | 70 … | } |
75 | 71 … | } |
76 | 72 … | |
77 | 73 … | |
78 | 74 … | |
79 | 75 … | |
80 | | - |
| 76 … | + |
81 | 77 … | |
82 | 78 … | const MONTHS = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ] |
83 | 79 … | const DAYS = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ] |
84 | 80 … | |
85 | | -function Calendar (events) { |
| 81 … | +function Calendar (state) { |
86 | 82 … | |
87 | 83 … | |
88 | 84 … | |
89 | | - const year = Value(new Date().getFullYear()) |
90 | | - const today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()) |
91 | | - |
92 | | - |
93 | | - const root = h('Calendar', [ |
94 | | - Header(year), |
95 | | - h('div.months', computed(year, year => { |
96 | | - return MONTHS.map((month, monthIndex) => Month({ month, monthIndex, year, today, events })) |
| 85 … | + return h('Calendar', [ |
| 86 … | + Header(state.year), |
| 87 … | + h('div.months', computed(throttle(state, 100), ({ today, year, events }) => { |
| 88 … | + return MONTHS.map((month, monthIndex) => { |
| 89 … | + return Month({ month, monthIndex, today, year, events }) |
| 90 … | + }) |
97 | 91 … | })) |
98 | 92 … | ]) |
99 | | - |
100 | | - return root |
101 | 93 … | } |
102 | 94 … | |
103 | 95 … | function Header (year) { |
104 | 96 … | return h('div.header', [ |
106 | 98 … | year, |
107 | 99 … | h('a', { 'ev-click': () => year.set(year() - 1) }, '-'), |
108 | 100 … | h('a', { 'ev-click': () => year.set(year() + 1) }, '+') |
109 | 101 … | ]) |
110 | | - |
111 | 102 … | ]) |
112 | 103 … | } |
113 | 104 … | |
114 | | -function Month ({ month, monthIndex, year, today, events }) { |
| 105 … | +function Month ({ month, monthIndex, today, year, events }) { |
115 | 106 … | const monthLength = new Date(year, monthIndex + 1, 0).getDate() |
116 | 107 … | |
117 | 108 … | |
118 | 109 … | const days = Array(monthLength).fill().map((_, i) => i + 1) |
140 | 131 … | const eventsOnDay = events.filter(e => { |
141 | 132 … | return e.date >= date && e.date < dateEnd |
142 | 133 … | }) |
143 | 134 … | |
144 | | - return h('CalendarDay', { |
145 | | - attributes: { 'data-date': `${year}-${monthIndex + 1}-${day}` }, |
| 135 … | + const opts = { |
| 136 … | + attributes: { |
| 137 … | + 'title': `${year}-${monthIndex + 1}-${day}`, |
| 138 … | + 'data-date': `${year}-${monthIndex + 1}-${day}` |
| 139 … | + }, |
146 | 140 … | style: { |
147 | 141 … | 'grid-row': `${weekday} / ${weekday + 1}`, |
148 | 142 … | 'grid-column': `${week + 1} / ${week + 2}` |
149 | 143 … | |
151 | 145 … | classList: [ |
152 | 146 … | date < today ? '-past' : '-future', |
153 | 147 … | eventsOnDay.length ? '-events' : '' |
154 | 148 … | ] |
155 | | - }) |
| 149 … | + } |
| 150 … | + |
| 151 … | + if (!eventsOnDay.length) return h('CalendarDay', opts) |
| 152 … | + |
| 153 … | + return h('CalendarDay', opts, [ |
| 154 … | + |
| 155 … | + h('div', [ |
| 156 … | + |
| 157 … | + ]) |
| 158 … | + ]) |
156 | 159 … | } |
157 | 160 … | } |
158 | 161 … | |
159 | 162 … | function DayName (day, index) { |