git ssb

0+

mixmix / marama



Commit 0ae77ce854723c6cb0d10cdf9f28bcf53f3fc587

-refactor styles, add ability for different grpah orientation, styling, improve README

mixmix committed on 8/20/2018, 5:13:07 AM
Parent: 6dc2c1a4ab70782adb3bd7e9c7dff831c072e153

Files changed

README.mdchanged
index.jschanged
lib/styles-inject.jschanged
lib/styles-write.jschanged
lib/styles-compile.jsdeleted
lib/get-css.jsadded
lib/get-day.jsadded
lib/get-mcss.jsadded
styles/marama-day-name.mcssdeleted
styles/day-label.mcssadded
styles/marama-day-tile.mcssdeleted
styles/day-tile.mcssadded
styles/marama.mcssdeleted
styles/index.mcssadded
test/index.jsdeleted
test/index-classic-cal.jsadded
test/index-letnice.jsadded
day-label.jsadded
day-tile.jsadded
marama.jpgadded
README.mdView
@@ -1,3 +1,60 @@
11 # Marama
22
3-_from te reo maori: [marama](http://maoridictionary.co.nz/search?keywords=moon) - 1. moon, 2. month_
3 +![](./marama.jpg)
4 +
5 +_From te reo maori: [marama](http://maoridictionary.co.nz/search?keywords=moon) - 1. moon, 2. month_
6 +
7 +## Uasge
8 +
9 +```js
10 +var Marama = require('marama')
11 +require('marama/lib/styles-inject')()
12 +
13 +const marama = Marama({
14 + events: [
15 + { date: new Date(2018, 3, 4), data: { attending: false } },
16 + { date: new Date(2018, 7, 21), data: { attending: true } }
17 + // NOTE Date has signatute (Year, monthIndex, day)
18 + ],
19 + range: {
20 + gte: new Date(2018, 7, 13),
21 + lt: new Date(2018, 7, 20) // range of highlighted dates
22 + },
23 + styles: {
24 + tileRadius: 18,
25 + tileGap: 4
26 + }
27 +})
28 +
29 +document.body.appendChild(marama)
30 +```
31 +
32 +
33 +## API
34 +
35 +Marama can take the following options:
36 +
37 +```js
38 +{
39 + month, // month number (by common defn, e.g. 4 is April)
40 + events // (optional) an Array of form: [{ date: Date, data: { ... } }]
41 + year, // (optional) defaults to current year
42 + monthNames, // (optional) an Array of month names
43 + range, // (optional) an Object of form { gte: Date, lt: Date } to highlight
44 + setRange, // (optional) a callback which receives a range on clicks { gte, lt }
45 + styles, // (optional) Object, _see below_
46 + today // (optional) a Date which can be used to over-ride the definition of today
47 +}
48 +```
49 +
50 +The `styles` option can be used to change how Marama looks programmatically
51 +
52 +```js
53 +{
54 + tileRadius, // (optional) Number, half-width of a day-tile, in px (default 6)
55 + tileGap, // (optional) Number, gap between day-tiles, in px (default: 1)
56 + dotRadius, // (optional) Number, radius of the 'attendance' dot in px (default: tileRadius/2)
57 + dotBorder, // (optional) Number, depth of outline on an event not attending (default: 1)
58 + weekFormat, // (optional) String(rows|columns), which direction weeks run in (default: rows)
59 +}
60 +```
index.jsView
@@ -1,130 +1,91 @@
11 const h = require('mutant/h')
2 +const DayTile = require('./day-tile')
3 +const DayLabel = require('./day-label')
4 +const getDay = require('./lib/get-day')
25
36 const MONTH_NAMES = [ 'Ja', 'Fe', 'Ma', 'Ap', 'Ma', 'Ju', 'Ju', 'Au', 'Se', 'Oc', 'No', 'De' ]
47 const DAYS = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ]
8 +const DEFAULT_FORMAT = 'rows'
59
610 module.exports = function Marama (opts = {}) {
7- const d = startOfDay()
11 + const day = opts.today || startOfDay()
812 const {
9- year = d.getFullYear(),
10- month = d.getMonth() + 1, // month number (common defn)
11- today = d,
1213 events = [],
14 + month = day.getMonth() + 1, // month number (common defn)
15 + year = day.getFullYear(),
16 + monthNames = MONTH_NAMES,
1317 range,
1418 setRange = () => {},
15- monthNames = MONTH_NAMES
19 + styles = {},
20 + today = day
1621 } = opts
22 + if (opts.style) console.error('Marama: you have passed in **style** instead of styles!')
1723
1824 const monthIndex = month - 1 // month number (Date API defn)
1925 const monthLength = new Date(year, monthIndex + 1, 0).getDate()
2026 // NOTE Date takes month as a monthIndex i.e. april = 3
2127 // and day = 0 goes back a day
2228 const days = Array(monthLength).fill().map((_, i) => i + 1)
29 + const dayOpts = {
30 + events,
31 + year,
32 + monthIndex,
33 + // day TBD
34 + today,
35 + offset: getDay(new Date(year, monthIndex, 1)) - 1, // how far into the week the month starts
36 + weekFormat: getWeekFormat(styles),
37 + range,
38 + setRange
39 + }
2340
24- var weekday
25- var week
26- const offset = getDay(new Date(year, monthIndex, 1)) - 1
27-
2841 const setMonthRange = (ev) => {
2942 setRange({
3043 gte: new Date(year, monthIndex, 1),
3144 lt: new Date(year, monthIndex + 1, 1)
3245 })
3346 }
3447
3548 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- )
49 + // h('div.month-name', { 'ev-click': setMonthRange }, monthNames[monthIndex]),
50 + h('div.days', { style: getStyles(styles) }, [
51 + DAYS.map((day, i) => DayLabel(day, i, dayOpts.weekFormat)),
52 + days.map(day => {
53 + dayOpts.day = day // note we're mutating this object (might save memory?)
54 + return DayTile(dayOpts)
55 + })
56 + ])
4657 ])
58 +}
4759
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)
60 +function getStyles (styles = {}) {
61 + const {
62 + tileRadius = 6,
63 + tileGap = 1,
64 + dotRadius,
65 + dotBorder = 1
66 + } = styles
67 + const format = getWeekFormat(styles)
5368
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('MaramaDayTile', opts)
94-
95- return h('MaramaDayTile', 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- ])
69 + const _styles = {
70 + '--tile-radius': `${tileRadius}px`,
71 + '--tile-gap': `${tileGap}px`,
72 + '--dot-radius': `${dotRadius || Math.floor(tileRadius / 2)}px`,
73 + '--dot-border': `${dotBorder}px`,
74 + display: 'grid',
75 + [`grid-template-${format}`]: '2 * calc(var(--tile-radius) + 2 * var(--tile-gap)) repeat(6, calc(2 * var(--tile-radius)))'
10276 }
10377
104- function inRange (date) {
105- if (!range || (!range.gte && !range.lt)) return false
106- return (date >= range.gte) && (date < range.lt)
107- }
78 + return _styles
10879 }
10980
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))
81 +function getWeekFormat (styles) {
82 + if (styles.weekFormat && !['rows', 'columns'].includes(styles.weekFormat)) {
83 + throw new Error('marama styles.weekFormat must be either "rows" or "columns"')
84 + }
85 + return styles.weekFormat || DEFAULT_FORMAT
11786 }
11887
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-
12788 function startOfDay (d = new Date()) {
12889 return new Date(d.getFullYear(), d.getMonth(), d.getDate())
12990 }
13091
lib/styles-inject.jsView
@@ -1,12 +1,8 @@
11 const { h } = require('mutant')
2-const getCSS = require('./styles-compile')
2 +const getCSS = require('./get-css')
33
44 module.exports = () => {
5- getCSS((err, css) => {
6- if (err) return console.error(err)
7-
8- document.head.appendChild(
9- h('style', { innerHTML: css })
10- )
11- })
5 + document.head.appendChild(
6 + h('style', { innerHTML: getCSS() })
7 + )
128 }
lib/styles-write.jsView
@@ -1,18 +1,14 @@
11 const getCSS = require('./styles-compile')
22 const fs = require('fs')
33 const { join } = require('path')
44
5-function buildStyles () {
6- getCSS((err, css) => {
5 +function stylesWrite () {
6 + fs.writeFile(join(__dirname, '../marama.css'), getCSS(), (err, done) => {
77 if (err) throw err
8-
9- fs.writeFile(join(__dirname, '../marama.css'), css, (err, done) => {
10- if (err) throw err
11- console.log('mcss built')
12- })
8 + console.log('mcss built')
139 })
1410 }
1511
16-module.exports = buildStyles
12 +module.exports = stylesWrite
1713
18-if (!module.parent) buildStyles()
14 +if (!module.parent) stylesWrite()
lib/styles-compile.jsView
@@ -1,20 +1,0 @@
1-const readDir = require('read-directory')
2-const compile = require('micro-css')
3-const { join } = require('path')
4-
5-module.exports = function compileStyles (cb) {
6- readDir(join(__dirname, '../styles'), (err, files) => {
7- if (err) return cb(err)
8-
9- const mcss = values(files).join('\n\n')
10-
11- console.log(compile(mcss))
12-
13- cb(null, compile(mcss))
14- })
15-}
16-
17-function values (obj) {
18- return Object.keys(obj)
19- .map(key => obj[key])
20-}
lib/get-css.jsView
@@ -1,0 +1,6 @@
1 +const compile = require('micro-css')
2 +const getMCSS = require('./get-mcss')
3 +
4 +module.exports = function getCSS () {
5 + return compile(getMCSS())
6 +}
lib/get-day.jsView
@@ -1,0 +1,7 @@
1 +module.exports = function getDay (date) {
2 + const dayIndex = date.getDay()
3 + return dayIndex === 0 ? 7 : dayIndex
4 +
5 + // Weeks run 0...6 (Sun - Sat)
6 + // this shifts those days around by 1
7 +}
lib/get-mcss.jsView
@@ -1,0 +1,13 @@
1 +const readDir = require('read-directory')
2 +const { join } = require('path')
3 +
4 +module.exports = function getMcss (cb) {
5 + const collection = readDir.sync(join(__dirname, '../styles'))
6 +
7 + return values(collection).reverse().join('\n\n')
8 +}
9 +
10 +function values (obj) {
11 + return Object.keys(obj)
12 + .map(key => obj[key])
13 +}
styles/marama-day-name.mcssView
@@ -1,13 +1,0 @@
1-MaramaDayName {
2- color: hsl(0, 0%, 40%)
3- font-family: arial
4- font-size: calc(2 * var(--day-radius) - 3px)
5- /* line-height: calc(2 * var(--day-radius) - 2px) */
6-
7- width: calc(2 * var(--day-radius))
8- height: calc(2 * var(--day-radius))
9-
10- display: flex
11- align-items: center
12- justify-content: center
13-}
styles/day-label.mcssView
@@ -1,0 +1,12 @@
1 +MaramaDayLabel {
2 + color: hsl(0, 0%, 40%)
3 + font-family: arial
4 + font-size: calc(2 * var(--tile-radius) - 4px)
5 +
6 + width: calc(2 * var(--tile-radius))
7 + height: calc(2 * var(--tile-radius))
8 +
9 + display: flex
10 + align-items: center
11 + justify-content: center
12 +}
styles/marama-day-tile.mcssView
@@ -1,52 +1,0 @@
1-MaramaDayTile {
2- width: calc(2 * var(--day-radius))
3- height: calc(2 * var(--day-radius))
4- cursor: pointer
5-
6- border-radius: var(--day-border-radius)
7-
8- display: flex
9- justify-content: center
10- align-items: center
11-
12- -past {
13- background: hsl(0, 0%, 20%)
14- }
15-
16- -future {
17- background: hsl(0, 0%, 80%)
18- }
19-
20- -range {
21- background: deeppink
22-
23- -future {
24- background: deepskyblue
25- }
26- }
27-
28- -events {
29- /* border-radius: var(--day-radius) */
30- /* background: hsla(277, 57%, 45%, 1) */
31-
32- div.dot {
33- background: none
34- width: 4px
35- height: 4px
36- border: 1px solid #fff
37- border-radius: 8px
38- }
39-
40- -past {
41- }
42-
43- -attending {
44- div.dot {
45- background: #fff
46- width: 6px
47- height: 6px
48- border: none
49- }
50- }
51- }
52-}
styles/day-tile.mcssView
@@ -1,0 +1,46 @@
1 +MaramaDayTile {
2 + width: calc(2 * var(--tile-radius))
3 + height: calc(2 * var(--tile-radius))
4 + cursor: pointer
5 +
6 + border-radius: 2px
7 +
8 + display: flex
9 + justify-content: center
10 + align-items: center
11 +
12 + -past {
13 + background: hsl(0, 0%, 20%)
14 + }
15 +
16 + -future {
17 + background: hsl(0, 0%, 80%)
18 + }
19 +
20 + -range {
21 + background: deeppink
22 +
23 + -future {
24 + background: deepskyblue
25 + }
26 + }
27 +
28 + -events {
29 + div.dot {
30 + background: none
31 + width: calc(2 * var(--dot-radius) - 2 * var(--dot-border))
32 + height: calc(2 * var(--dot-radius) - 2 * var(--dot-border))
33 + border: var(--dot-border) solid #fff
34 + border-radius: calc(2 * var(--dot-radius))
35 + }
36 +
37 + -attending {
38 + div.dot {
39 + background: #fff
40 + width: calc(2 * var(--dot-radius))
41 + height: calc(2 * var(--dot-radius))
42 + border: none
43 + }
44 + }
45 + }
46 +}
styles/marama.mcssView
@@ -1,24 +1,0 @@
1-Marama {
2- --day-radius: 6px
3- --day-border-radius: 2px
4- --day-gap: 1px
5-
6- width: calc(7 * 2 * var(--day-radius) + 6 * var(--day-gap))
7- /* max of 6 weeks + day labels, with gaps between each */
8-
9- div.month-name {
10- font-size: 20px
11- font-weight: bold
12- text-align: left
13- cursor: pointer
14- margin-bottom: 5px
15- }
16-
17- div.days {
18- grid-gap: var(--day-gap)
19- justify-content: start
20- align-content: start
21-
22- div.MaramaDay {}
23- }
24-}
styles/index.mcssView
@@ -1,0 +1,17 @@
1 +Marama {
2 + div.month-name {
3 + font-size: 20px
4 + font-weight: bold
5 + text-align: left
6 + cursor: pointer
7 + margin-bottom: 5px
8 + }
9 +
10 + div.days {
11 + grid-gap: var(--tile-gap)
12 + justify-content: start
13 + align-content: start
14 +
15 + div.MaramaDay {}
16 + }
17 +}
test/index.jsView
@@ -1,18 +1,0 @@
1-// run this from the terminal using :
2-// npx electro test/index.js
3-
4-const { h } = require('mutant')
5-
6-const Marama = require('../')
7-require('../lib/styles-inject')()
8-
9-const page = h('div',
10- {
11- style: {
12- margin: '4rem'
13- }
14- },
15- Marama()
16-)
17-
18-document.body.appendChild(page)
test/index-classic-cal.jsView
@@ -1,0 +1,37 @@
1 +// run this from the terminal using :
2 +// npx electro test/index-classic-cal.js
3 +
4 +const { h } = require('mutant')
5 +
6 +const Marama = require('../')
7 +require('../lib/styles-inject')()
8 +
9 +const marama = Marama({
10 + today: new Date(2018, 6, 12),
11 + events: [
12 + { date: new Date(2018, 3, 4), data: { attending: true } },
13 + { date: new Date(2018, 6, 5), data: { attending: true } },
14 + { date: new Date(2018, 6, 7), data: { attending: false } },
15 + { date: new Date(2018, 6, 17), data: { attending: true } },
16 + { date: new Date(2018, 6, 21), data: { attending: false } },
17 + { date: new Date(2018, 6, 27), data: { attending: true } }
18 + ],
19 + range: {
20 + gte: new Date(2018, 6, 9),
21 + lt: new Date(2018, 6, 23)
22 + },
23 + styles: {
24 + weekFormat: 'rows',
25 + tileRadius: 18,
26 + tileGap: 4
27 + }
28 +})
29 +
30 +const page = h('div',
31 + {
32 + style: { margin: '3rem' }
33 + },
34 + marama
35 +)
36 +
37 +document.body.appendChild(page)
test/index-letnice.jsView
@@ -1,0 +1,32 @@
1 +// run this from the terminal using :
2 +// npx electro test/index-letnice.js
3 +
4 +const { h } = require('mutant')
5 +
6 +const Marama = require('../')
7 +require('../lib/styles-inject')()
8 +
9 +const marama = Marama({
10 + today: new Date(2018, 7, 19),
11 + events: [
12 + { date: new Date(2018, 3, 4), data: { attending: true } },
13 + { date: new Date(2018, 7, 19), data: { attending: true } },
14 + { date: new Date(2018, 7, 21), data: { attending: false } }
15 + ],
16 + range: {
17 + gte: new Date(2018, 7, 13),
18 + lt: new Date(2018, 7, 20)
19 + },
20 + styles: {
21 + weekFormat: 'columns'
22 + }
23 +})
24 +
25 +const page = h('div',
26 + {
27 + style: { margin: '3rem' }
28 + },
29 + marama
30 +)
31 +
32 +document.body.appendChild(page)
day-label.jsView
@@ -1,0 +1,15 @@
1 +const h = require('mutant/h')
2 +
3 +module.exports = function DayLabel (day, index, weekFormat) {
4 + const style = weekFormat === 'rows'
5 + ? {
6 + 'grid-row': '1 / 2',
7 + 'grid-column': `${index + 1} / ${index + 2}`
8 + }
9 + : {
10 + 'grid-row': `${index + 1} / ${index + 2}`,
11 + 'grid-column': '1 / 2'
12 + }
13 +
14 + return h('MaramaDayLabel', { style }, day.substr(0, 1))
15 +}
day-tile.jsView
@@ -1,0 +1,72 @@
1 +const h = require('mutant/h')
2 +const getDay = require('./lib/get-day')
3 +
4 +module.exports = function Day ({ today, year, monthIndex, day, offset, weekFormat, events, range, setRange }) {
5 + const date = new Date(year, monthIndex, day)
6 + const dateEnd = new Date(year, monthIndex, day + 1)
7 + const weekday = getDay(date)
8 + const week = Math.ceil((day + offset) / 7)
9 +
10 + const eventsOnDay = events.filter(e => {
11 + return e.date >= date && e.date < dateEnd
12 + })
13 +
14 + const attending = eventsOnDay.some(e => {
15 + return e.data.attending
16 + })
17 +
18 + const style = weekFormat === 'rows'
19 + ? {
20 + 'grid-row': `${week + 1} / ${week + 2}`, // new weeks on each col (leaving space for labels col)
21 + 'grid-column': `${weekday} / ${weekday + 1}` // new weekdays on each row
22 + // moved by 1 to make space for labels
23 + }
24 + : {
25 + 'grid-row': `${weekday} / ${weekday + 1}`, // new weekdays on each row
26 + 'grid-column': `${week + 1} / ${week + 2}` // new weeks on each col (leaving space for labels col)
27 + }
28 +
29 + const opts = {
30 + attributes: {
31 + 'title': `${year}-${monthIndex + 1}-${day}`,
32 + 'data-date': `${year}-${monthIndex + 1}-${day}`
33 + },
34 + style,
35 + classList: [
36 + date < today ? '-past' : '-future',
37 + eventsOnDay.length ? '-events' : '',
38 + inRange(range, date) ? '-range' : '',
39 + attending ? '-attending' : ''
40 + ],
41 + 'ev-click': handleRangeSetting
42 + }
43 +
44 + if (!eventsOnDay.length) return h('MaramaDayTile', opts)
45 +
46 + return h('MaramaDayTile', opts, [
47 + // TODO add awareness of whether I'm going to events
48 + // TODO try a FontAwesome circle
49 + h('div.dot', [
50 + // Math.random() > 0.3 ? h('div') : ''
51 + ])
52 + ])
53 +
54 + function handleRangeSetting (ev) {
55 + if (ev.shiftKey && range && range.lt) {
56 + dateEnd >= range.lt
57 + ? setRange({ lt: dateEnd })
58 + : setRange({ gte: date })
59 + return
60 + }
61 +
62 + setRange({
63 + gte: date,
64 + lt: dateEnd
65 + })
66 + }
67 +}
68 +
69 +function inRange (range, date) {
70 + if (!range || (!range.gte && !range.lt)) return false
71 + return (date >= range.gte) && (date < range.lt)
72 +}
marama.jpg
marama.jpg

Built with git-ssb-web