Commit 130d9b2d4b5cccafdcbb5d697ab3007a90c9741a
/calendar : minimal year display
mixmix committed on 7/19/2018, 9:11:08 PMParent: 9b9ae32751d87f8c75ee8da7d23f22f5b9250a74
Files changed
app/page/calendar.js | added |
app/page/calendar.mcss | added |
router/sync/routes.js | changed |
app/page/calendar.js | ||
---|---|---|
@@ -1,0 +1,171 @@ | ||
1 … | +const nest = require('depnest') | |
2 … | +const { h, Value, computed } = require('mutant') | |
3 … | + | |
4 … | +exports.gives = nest('app.page.calendar') | |
5 … | + | |
6 … | +exports.needs = nest({ | |
7 … | +}) | |
8 … | + | |
9 … | +exports.create = (api) => { | |
10 … | + return nest('app.page.calendar', calendarPage) | |
11 … | + | |
12 … | + function calendarPage (location) { | |
13 … | + const cal = Cal() | |
14 … | + | |
15 … | + return h('CalendarPage', { title: '/calendar' }, cal) | |
16 … | + } | |
17 … | +} | |
18 … | + | |
19 … | +const MONTHS = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ] | |
20 … | +const DAYS = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ] | |
21 … | + | |
22 … | +function Cal () { | |
23 … | + const year = Value(new Date().getFullYear()) | |
24 … | + const today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate() - 1, 0) | |
25 … | + | |
26 … | + const root = computed(year, year => { | |
27 … | + return h('Calendar', [ | |
28 … | + Header(year), | |
29 … | + MONTHS.map((month, i) => { | |
30 … | + return h('div.month', [ | |
31 … | + h('div.label', month.substr(0, 3)), | |
32 … | + h('div.graph', [ | |
33 … | + // Labels(), | |
34 … | + Month(year, i) | |
35 … | + ]) | |
36 … | + ]) | |
37 … | + }) | |
38 … | + ]) | |
39 … | + }) | |
40 … | + | |
41 … | + return root | |
42 … | + | |
43 … | + function Header (year) { | |
44 … | + return h('div.header', [ | |
45 … | + h('p.year', [ | |
46 … | + year, | |
47 … | + h('a', { 'ev-click': () => year.set(year() - 1) }, '-'), | |
48 … | + h('a', { 'ev-click': () => year.set(year() + 1) }, '+') | |
49 … | + ]) | |
50 … | + // h('p.percentage', yearProgress(year)) | |
51 … | + ]) | |
52 … | + } | |
53 … | + | |
54 … | + // function yearProgress (year) { | |
55 … | + // const diff = new Date() - new Date(year, 0, 1, 0) | |
56 … | + // const progress = ((diff / 31536000000) * 100).toFixed(2) | |
57 … | + // const yd = Math.abs((progress / 100).toFixed(2)) | |
58 … | + | |
59 … | + // return progress < 0 ? yd + ` YEARS AWAY` : progress > 100 ? yd + ` YEARS AGO` : progress + '%' | |
60 … | + // } | |
61 … | + | |
62 … | + // function doLabels () { | |
63 … | + // let html = '' | |
64 … | + // let y = 0 | |
65 … | + | |
66 … | + // for (var i = 0; i < 7; i++) { | |
67 … | + // y = (i * 14) | |
68 … | + // html += `<text class="dayLabel" x="5" y='${y}' dy="10">${DAYS[i].substr(0, 1)}</text>` | |
69 … | + // } | |
70 … | + // return html | |
71 … | + // } | |
72 … | + | |
73 … | + function Month (year, monthIndex) { | |
74 … | + const monthLength = new Date(year, monthIndex + 1, 0).getDate() | |
75 … | + // NOTE Date takes month as a monthIndex i.e. april = 3 | |
76 … | + // and day = 0 goes back a day | |
77 … | + const days = Array(monthLength).fill().map((_, i) => i + 1) | |
78 … | + | |
79 … | + const style = { | |
80 … | + display: 'grid', | |
81 … | + 'grid-gap': '.2rem' | |
82 … | + } | |
83 … | + | |
84 … | + var date | |
85 … | + var weekday | |
86 … | + var week | |
87 … | + var offset = getDay(new Date(year, monthIndex, 1)) - 1 | |
88 … | + | |
89 … | + return h('div', { style }, days.map(day => { | |
90 … | + date = new Date(year, monthIndex, day) | |
91 … | + weekday = getDay(date) | |
92 … | + if (weekday === 0) weekday = 7 // urghh I want monday to be the start of the week | |
93 … | + week = Math.ceil((day + offset) / 7) | |
94 … | + | |
95 … | + return h('div.day', { | |
96 … | + attributes: { 'data-day': day }, | |
97 … | + style: { | |
98 … | + 'grid-row': `${weekday} / ${weekday + 1}`, | |
99 … | + 'grid-column': `${week} / ${week + 1}` | |
100 … | + } | |
101 … | + }) | |
102 … | + })) | |
103 … | + } | |
104 … | + | |
105 … | + function getDay (date) { | |
106 … | + const d = date.getDay() | |
107 … | + return d === 0 ? 7 : d | |
108 … | + | |
109 … | + // Weeks run 0...6 (Sun - Sat) | |
110 … | + // this shifts those days around by 1 | |
111 … | + } | |
112 … | + | |
113 … | + function doMonth (moxsd ........ | |
114 … | + .th) { | |
115 … | + var html = '' | |
116 … | + const monthLength = new Date(year, month + 1, 0).getDate() | |
117 … | + let date = 0 | |
118 … | + let x = 0 | |
119 … | + let y = 0 | |
120 … | + | |
121 … | + while (date < monthLength) { | |
122 … | + x += 14 | |
123 … | + let week = 0 | |
124 … | + | |
125 … | + while (week < 7 && date !== monthLength) { | |
126 … | + y = week * 14 | |
127 … | + let day = new Date(year, month, date, 0) | |
128 … | + let dotab = `tabIndex="0"` | |
129 … | + | |
130 … | + if (day.getDay() !== week) { | |
131 … | + style = 'null' | |
132 … | + dotab = '' | |
133 … | + date-- | |
134 … | + } else if (String(day) === String(today)) { | |
135 … | + style = 'today' | |
136 … | + } else if (day < today) { | |
137 … | + style = 'gone' | |
138 … | + } else if (day.getDay() === 5 || day.getDay() === 6) { | |
139 … | + style = 'weekend' | |
140 … | + } else { | |
141 … | + style = 'day' | |
142 … | + } | |
143 … | + | |
144 … | + html += `<rect id="square" class='${style}' x='${x}' y='${y}' title='${(date + 1) === 0 ? 'null' : DAYS[week] + ' ' + (date + 1)}' width="12px" height="12px" rx="2" ry="2" onclick=" | |
145 … | + UpdateFooter(${year}, ${month}, ${(date + 1)}, ${week}, this)" onblur="" ${dotab}></rect>` | |
146 … | + | |
147 … | + week++ | |
148 … | + date++ | |
149 … | + } | |
150 … | + } | |
151 … | + return html | |
152 … | + } | |
153 … | +} | |
154 … | + | |
155 … | +function UpdateFooter (year, month, date, week, obj) { | |
156 … | + obj.addEventListener('blur', () => { footer.innerHTML = '' }) | |
157 … | + let diff = ((new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate(), 0) - new Date(year, month, date)) / 86400000) | |
158 … | + let num = Math.abs(diff).toFixed() | |
159 … | + let calc | |
160 … | + | |
161 … | + diff < 0 ? calc = `In ${num} Day${num > 1 ? 's' : ''}.` : diff == 0 ? calc = `Today.` : calc = `${num} Day${num > 1 ? 's' : ''} ago.` | |
162 … | + footer.innerHTML = `${MONTHS[month]} ${date}, ${DAYS[week]}. ${calc}` | |
163 … | +} | |
164 … | + | |
165 … | +function getYear (diff) { | |
166 … | + location.hash = parseInt(location.hash.replace('#', '')) + parseInt(diff) | |
167 … | +} | |
168 … | + | |
169 … | +// window.onhashchange = function () { | |
170 … | +// Year(parseInt(location.hash.replace('#', ''))) | |
171 … | +// } |
app/page/calendar.mcss | ||
---|---|---|
@@ -1,0 +1,115 @@ | ||
1 … | +CalendarPage { | |
2 … | + width: 100% | |
3 … | + | |
4 … | + display: grid | |
5 … | + justify-content: center | |
6 … | +} | |
7 … | + | |
8 … | + | |
9 … | +Calendar { | |
10 … | + font-family: 'input_mono_regular', monospace | |
11 … | + text-transform: uppercase | |
12 … | + | |
13 … | + display: block | |
14 … | + height: 100% | |
15 … | + min-height: 400px | |
16 … | + width: 100% | |
17 … | + | |
18 … | + padding: 0 | |
19 … | + margin: 0 | |
20 … | + | |
21 … | + section { | |
22 … | + position: relative | |
23 … | + top: 50% | |
24 … | + margin: 0 auto | |
25 … | + user-select: none | |
26 … | + -webkit-user-select: none | |
27 … | + -ms-user-select: none | |
28 … | + -webkit-transform: translateY(-50%) | |
29 … | + -ms-transform: translateY(-50%) | |
30 … | + transform: translateY(-50%) | |
31 … | + text-align: center | |
32 … | + } | |
33 … | + | |
34 … | + div.header { | |
35 … | + margin: 0 10px 40px 10px | |
36 … | + text-align: left | |
37 … | + align-content: flex-start | |
38 … | + | |
39 … | + p.year { | |
40 … | + font-size: 40px | |
41 … | + font-weight: bold | |
42 … | + | |
43 … | + a { | |
44 … | + text-align: center | |
45 … | + color: #000 | |
46 … | + width: 30px | |
47 … | + display: inline-block | |
48 … | + margin-left: 10px | |
49 … | + | |
50 … | + :hover { | |
51 … | + color: #ffffff | |
52 … | + background: #000 | |
53 … | + cursor: pointer | |
54 … | + } | |
55 … | + } | |
56 … | + } | |
57 … | + | |
58 … | + p.percentage { | |
59 … | + font-size: 20px | |
60 … | + color: #8b8b8b | |
61 … | + } | |
62 … | + } | |
63 … | + | |
64 … | + div.month { | |
65 … | + margin: 10px | |
66 … | + display: inline-block | |
67 … | + /* width:100px */ | |
68 … | + /* height: 130px */ | |
69 … | + | |
70 … | + div.label { | |
71 … | + font-size: 20px | |
72 … | + font-weight: bold | |
73 … | + text-align: left | |
74 … | + margin-bottom: 5px | |
75 … | + } | |
76 … | + | |
77 … | + div.graph { | |
78 … | + | |
79 … | + div { | |
80 … | + div.day { | |
81 … | + background: #000 | |
82 … | + height: .8rem | |
83 … | + width: .8rem | |
84 … | + | |
85 … | + border-radius: .1rem | |
86 … | + } | |
87 … | + } | |
88 … | + } | |
89 … | + } | |
90 … | + | |
91 … | + | |
92 … | + /* p { margin: 0px; } */ | |
93 … | + | |
94 … | + /* svg.graph { color:white; width: 100%; height: 100px; } */ | |
95 … | + /* svg.graph text {font-family: 'input_mono_regular'; stroke:none; fill:#8b8b8b; font-size:14px; text-anchor: middle; } */ | |
96 … | + /* svg.graph text.dayLabel { font-size: 10px; } */ | |
97 … | + /* svg.graph rect { stroke:none; outline: none; } */ | |
98 … | + /* svg.graph rect:hover, rect:focus { fill: #ff1e00 !important; cursor:pointer; } */ | |
99 … | + | |
100 … | + /* svg.graph rect.null { fill: none; stroke: none;} */ | |
101 … | + /* svg.graph rect.today { fill:#ff1e00; } */ | |
102 … | + /* svg.graph rect.day { fill:#8b8b8b; } */ | |
103 … | + /* svg.graph rect.weekend { fill:#747474 } */ | |
104 … | + /* svg.graph rect.gone { fill:#000000 } */ | |
105 … | + /* svg.graph path { stroke-linecap: butt; stroke-dasharray: 1,1; fill:none; stroke:#333; stroke-width:13px } */ | |
106 … | + | |
107 … | + /* @media only screen and (min-width: 1440px) */ | |
108 … | + /* { section { width: 1440px; }} */ | |
109 … | + | |
110 … | + /* @media only screen and (max-width: 1440px) */ | |
111 … | + /* { section { width: 720px; }} */ | |
112 … | + | |
113 … | + /* @media only screen and (max-width: 720px) */ | |
114 … | + /* { section { width: 360px; }} */ | |
115 … | +} |
router/sync/routes.js | ||
---|---|---|
@@ -4,10 +4,11 @@ | ||
4 | 4 … | exports.gives = nest('router.sync.routes') |
5 | 5 … | |
6 | 6 … | exports.needs = nest({ |
7 | 7 … | 'app.page': { |
8 … | + 'calendar': 'first', | |
9 … | + 'blob': 'first', | |
8 | 10 … | 'errors': 'first', |
9 | - 'blob': 'first', | |
10 | 11 … | 'channel': 'first', |
11 | 12 … | 'imageSearch': 'first', |
12 | 13 … | 'notifications': 'first', |
13 | 14 … | 'posts': 'first', |
@@ -28,8 +29,9 @@ | ||
28 | 29 … | const pages = api.app.page |
29 | 30 … | |
30 | 31 … | // loc = location |
31 | 32 … | const routes = [ |
33 … | + [ loc => loc.page === 'calendar', pages.calendar ], | |
32 | 34 … | [ loc => loc.page === 'errors', pages.errors ], |
33 | 35 … | [ loc => loc.page === 'imageSearch', pages.imageSearch ], |
34 | 36 … | [ loc => loc.page === 'notifications', pages.notifications ], |
35 | 37 … | [ loc => loc.page === 'posts', pages.posts ], |
Built with git-ssb-web