git ssb

16+

Dominic / patchbay



Tree: 7a1861362de764504e02614b8c8bc5837fdc089d

Files: 7a1861362de764504e02614b8c8bc5837fdc089d / app / page / calendar.js

4758 bytesRaw
1const nest = require('depnest')
2const { h, Array: MutantArray, Struct, computed, watch, throttle } = require('mutant')
3const pull = require('pull-stream')
4const { isMsg } = require('ssb-ref')
5
6exports.gives = nest('app.page.calendar')
7
8exports.needs = nest({
9 'sbot.pull.stream': 'first'
10})
11
12exports.create = (api) => {
13 return nest('app.page.calendar', calendarPage)
14
15 function calendarPage (location) {
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 })
22
23 watch(state.year, year => getEvents(year, state.events))
24
25 return h('CalendarPage', { title: '/calendar' }, [
26 Calendar(state)
27 ])
28 }
29
30 function getEvents (year, events) {
31 const query = [{
32 $filter: {
33 value: {
34 timestamp: {$gt: Number(new Date(year, 0, 1))}, // ordered by published time
35 content: {
36 type: 'about',
37 startDateTime: {
38 epoch: {$gt: 0}
39 }
40 }
41 }
42 }
43 }, {
44 $map: {
45 key: ['value', 'content', 'about'], // gathering
46 date: ['value', 'content', 'startDateTime', 'epoch']
47 }
48 }]
49
50 const opts = {
51 reverse: false,
52 live: true,
53 query
54 }
55
56 pull(
57 api.sbot.pull.stream(server => server.query.read(opts)),
58 pull.filter(m => !m.sync),
59 pull.filter(r => isMsg(r.key) && Number.isInteger(r.date)),
60 pull.map(r => {
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 } })
68 })
69 )
70 }
71}
72
73// ////////////////// extract below into a module ///////////////////////
74
75// Thanks to nomand for the inspiration and code (https://github.com/nomand/Letnice),
76// they formed the foundation of this work
77
78const MONTHS = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]
79const DAYS = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ]
80
81function Calendar (state) {
82 // TODO assert events is an Array of object
83 // of form { date, data }
84
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 })
91 }))
92 ])
93}
94
95function Header (year) {
96 return h('div.header', [
97 h('div.year', [
98 year,
99 h('a', { 'ev-click': () => year.set(year() - 1) }, '-'),
100 h('a', { 'ev-click': () => year.set(year() + 1) }, '+')
101 ])
102 ])
103}
104
105function Month ({ month, monthIndex, today, year, events }) {
106 const monthLength = new Date(year, monthIndex + 1, 0).getDate()
107 // NOTE Date takes month as a monthIndex i.e. april = 3
108 // and day = 0 goes back a day
109 const days = Array(monthLength).fill().map((_, i) => i + 1)
110
111 var date
112 var dateEnd
113 var weekday
114 var week
115 var offset = getDay(new Date(year, monthIndex, 1)) - 1
116
117 return h('CalendarMonth', [
118 h('div.month-name', month.substr(0, 2)),
119 h('div.days', { style: {display: 'grid'} }, [
120 DAYS.map((day, i) => DayName(day, i)),
121 days.map(Day)
122 ])
123 ])
124
125 function Day (day) {
126 date = new Date(year, monthIndex, day)
127 dateEnd = new Date(year, monthIndex, day + 1)
128 weekday = getDay(date)
129 week = Math.ceil((day + offset) / 7)
130
131 const eventsOnDay = events.filter(e => {
132 return e.date >= date && e.date < dateEnd
133 })
134
135 const opts = {
136 attributes: {
137 'title': `${year}-${monthIndex + 1}-${day}`,
138 'data-date': `${year}-${monthIndex + 1}-${day}`
139 },
140 style: {
141 'grid-row': `${weekday} / ${weekday + 1}`,
142 'grid-column': `${week + 1} / ${week + 2}`
143 // column moved by 1 to make space for labels
144 },
145 classList: [
146 date < today ? '-past' : '-future',
147 eventsOnDay.length ? '-events' : ''
148 ]
149 }
150
151 if (!eventsOnDay.length) return h('CalendarDay', opts)
152
153 return h('CalendarDay', opts, [
154 // TODO try a FontAwesome circle
155 h('div', [
156 // Math.random() > 0.3 ? h('div') : ''
157 ])
158 ])
159 }
160}
161
162function DayName (day, index) {
163 return h('CalendarDayName', {
164 style: {
165 'grid-row': `${index + 1} / ${index + 2}`,
166 'grid-column': '1 / 2'
167 }
168 }, day.substr(0, 1))
169}
170
171function getDay (date) {
172 const dayIndex = date.getDay()
173 return dayIndex === 0 ? 7 : dayIndex
174
175 // Weeks run 0...6 (Sun - Sat)
176 // this shifts those days around by 1
177}
178
179

Built with git-ssb-web