Files: e586183460b048c4129a99bab2a2b74d23041492 / index.js
3460 bytesRaw
1 | const h = require('mutant/h') |
2 | |
3 | const MONTH_NAMES = [ 'Ja', 'Fe', 'Ma', 'Ap', 'Ma', 'Ju', 'Ju', 'Au', 'Se', 'Oc', 'No', 'De' ] |
4 | const DAYS = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ] |
5 | |
6 | module.exports = function Marama (opts = {}) { |
7 | const d = startOfDay() |
8 | const { |
9 | year = d.getFullYear(), |
10 | month = d.getMonth() + 1, // month number (common defn) |
11 | today = d, |
12 | events = [], |
13 | range, |
14 | setRange = () => {}, |
15 | monthNames = MONTH_NAMES |
16 | } = opts |
17 | |
18 | const monthIndex = month - 1 // month number (Date API defn) |
19 | const monthLength = new Date(year, monthIndex + 1, 0).getDate() |
20 | // NOTE Date takes month as a monthIndex i.e. april = 3 |
21 | // and day = 0 goes back a day |
22 | const days = Array(monthLength).fill().map((_, i) => i + 1) |
23 | |
24 | var weekday |
25 | var week |
26 | const offset = getDay(new Date(year, monthIndex, 1)) - 1 |
27 | |
28 | const setMonthRange = (ev) => { |
29 | setRange({ |
30 | gte: new Date(year, monthIndex, 1), |
31 | lt: new Date(year, monthIndex + 1, 1) |
32 | }) |
33 | } |
34 | |
35 | return h('Marama', [ |
36 | h('div.month-name', { 'ev-click': setMonthRange }, monthNames[monthIndex]), |
37 | h('div.days', |
38 | { |
39 | style: { display: 'grid' } |
40 | }, |
41 | [ |
42 | DAYS.map((day, i) => DayName(day, i)), |
43 | days.map(Day) |
44 | ] |
45 | ) |
46 | ]) |
47 | |
48 | function Day (day) { |
49 | const date = new Date(year, monthIndex, day) |
50 | const dateEnd = new Date(year, monthIndex, day + 1) |
51 | weekday = getDay(date) |
52 | week = Math.ceil((day + offset) / 7) |
53 | |
54 | const eventsOnDay = events.filter(e => { |
55 | return e.date >= date && e.date < dateEnd |
56 | }) |
57 | |
58 | const attending = eventsOnDay.some(e => { |
59 | return e.data.attending |
60 | }) |
61 | |
62 | const opts = { |
63 | attributes: { |
64 | 'title': `${year}-${month}-${day}`, |
65 | 'data-date': `${year}-${month}-${day}` |
66 | }, |
67 | style: { |
68 | 'grid-row': `${weekday} / ${weekday + 1}`, |
69 | 'grid-column': `${week + 1} / ${week + 2}` |
70 | // column moved by 1 to make space for labels |
71 | }, |
72 | classList: [ |
73 | date < today ? '-past' : '-future', |
74 | eventsOnDay.length ? '-events' : '', |
75 | inRange(date) ? '-range' : '', |
76 | attending ? '-attending' : '' |
77 | ], |
78 | 'ev-click': (ev) => { |
79 | if (ev.shiftKey) { |
80 | dateEnd >= range.lt |
81 | ? setRange({ lt: dateEnd }) |
82 | : setRange({ gte: date }) |
83 | return |
84 | } |
85 | |
86 | setRange({ |
87 | gte: date, |
88 | lt: dateEnd |
89 | }) |
90 | } |
91 | } |
92 | |
93 | if (!eventsOnDay.length) return h('MaramaDay', opts) |
94 | |
95 | return h('MaramaDay', opts, [ |
96 | // TODO add awareness of whether I'm going to events |
97 | // TODO try a FontAwesome circle |
98 | h('div.dot', [ |
99 | // Math.random() > 0.3 ? h('div') : '' |
100 | ]) |
101 | ]) |
102 | } |
103 | |
104 | function inRange (date) { |
105 | if (!range || (!range.gte && !range.lt)) return false |
106 | return (date >= range.gte) && (date < range.lt) |
107 | } |
108 | } |
109 | |
110 | function DayName (day, index) { |
111 | return h('MaramaDayName', { |
112 | style: { |
113 | 'grid-row': `${index + 1} / ${index + 2}`, |
114 | 'grid-column': '1 / 2' |
115 | } |
116 | }, day.substr(0, 1)) |
117 | } |
118 | |
119 | function getDay (date) { |
120 | const dayIndex = date.getDay() |
121 | return dayIndex === 0 ? 7 : dayIndex |
122 | |
123 | // Weeks run 0...6 (Sun - Sat) |
124 | // this shifts those days around by 1 |
125 | } |
126 | |
127 | function startOfDay (d = new Date()) { |
128 | return new Date(d.getFullYear(), d.getMonth(), d.getDate()) |
129 | } |
130 | |
131 | // function endOfDay (d = new Date()) { |
132 | // return new Date(d.getFullYear(), d.getMonth(), d.getDate() + 1) |
133 | // } |
134 |
Built with git-ssb-web