From a55c7833b81156d3f880140f612c5a784dc0acc0 Mon Sep 17 00:00:00 2001 From: Sean Lang Date: Tue, 7 Jan 2014 04:03:25 -0600 Subject: [PATCH 1/7] add gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87174b6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/public/ From c1b66dd933fd58ec1dc0c998ef40b7eec94c420f Mon Sep 17 00:00:00 2001 From: Sean Lang Date: Tue, 7 Jan 2014 04:04:12 -0600 Subject: [PATCH 2/7] convert it into a roots project --- app.coffee | 17 + assets/css/main.css | 90 ++++++ index.html => assets/js/main.js | 555 ++++++++++++-------------------- config.example.json | 5 - life.example.md => life.md | 0 views/index.jade | 5 + views/layout.jade | 14 + 7 files changed, 338 insertions(+), 348 deletions(-) create mode 100644 app.coffee create mode 100644 assets/css/main.css rename index.html => assets/js/main.js (66%) delete mode 100644 config.example.json rename life.example.md => life.md (100%) create mode 100644 views/index.jade create mode 100644 views/layout.jade diff --git a/app.coffee b/app.coffee new file mode 100644 index 0000000..3e7b925 --- /dev/null +++ b/app.coffee @@ -0,0 +1,17 @@ +fs = require 'fs' + +# roots v2.1.2 +# Files in this list will not be compiled - minimatch supported +ignore_files: ['_*', 'readme*', '.gitignore', '.DS_Store', 'life.md'] +ignore_folders: ['.git'] + +layouts: + default: 'layout.jade' + +locals: + lifeConfig: JSON.stringify( + customStylesheetURL: null + yearLength: 120 + hideAge: false + markdown: String(fs.readFileSync 'life.md') + ) diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..2511eab --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,90 @@ +html{ + font-family: Open Sans, Helvetica, Arial, sans-serif; + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; +} +html{ + height: 100%; +} +body{ + min-height: 100%; + color: #fff; + background-color: #384047; + margin: 0; + padding: 0; + font-size: 12px; + -webkit-text-size-adjust: none; + position: relative; +} +a{ + color: #fff; +} +header{ + position: fixed; + bottom: 0; + margin: 0; + padding: 20px; +} +header a{ + margin-left: 1em; + opacity: .3; + text-decoration: none; +} +header a:hover{ + opacity: .7; + text-decoration: underline; +} +h1{ + display: inline; + font-size: 20px; + font-weight: normal; + line-height: 1em; + opacity: .5; + z-index: 3; + font-weight: 300; + white-space: nowrap; +} +#life{ + padding-top: 40px; + padding-bottom: 5em; +} +#life section.year{ + min-height: 100%; + box-sizing: border-box; + -moz-box-sizing: border-box; + border-left: 1px dashed rgba(255,255,255,.1); + color: rgba(255,255,255,.3); + position: absolute; + top: 0; + bottom: 0; + padding-left: 10px; + padding-top: 10px; + pointer-events: none; + font-weight: 300; + white-space: nowrap; +} +#life .event{ + padding-right: 20px; + padding-bottom: 5px; + vertical-align: middle; + white-space: nowrap; +} +#life .event b{ + font-weight: normal; + color: rgba(255,255,255,.5); +} +#life .event .time{ + display: inline-block; + overflow: hidden; + height: 0; + border: 4px solid #fff; + border-radius: 4px; + margin-right: 10px; + opacity: .3; + position: relative; + left: -2px; +} +#life .event:hover .time{ + opacity: .5; +} diff --git a/index.html b/assets/js/main.js similarity index 66% rename from index.html rename to assets/js/main.js index 900adb9..f3f760c 100644 --- a/index.html +++ b/assets/js/main.js @@ -1,343 +1,212 @@ - - -Life - - - - -
-

Life

- Fork me -
-
- +(function(){ + var life = { + $title: document.getElementById('title'), + $el: document.getElementById('life'), + utils: { + extend: function(object){ + var args = Array.prototype.slice.call(arguments, 1); + for (var i=0, source; source=args[i]; i++){ + if (!source) continue; + for (var property in source){ + object[property] = source[property]; + } + } + return object; + } + }, + config: { + yearLength: 120, // 120px per year + hideAge: false, // Hide age from year axis + customStylesheetURL: null // Custom stylesheet + }, + start: function(){ + life.config = life.utils.extend(life.config, lifeConfig); + if (life.config.customStylesheetURL) life.injectStylesheet(life.config.customStylesheetURL); + + + var data = life.parse(life.config.markdown); + var title = life.parseTitle(life.config.markdown); + life.render(title, data); + }, + injectStylesheet: function(url){ + var link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = url; + document.body.appendChild(link); + }, + parse: function(response){ + var list = response.match(/\-\s+[^\n\r]+/ig); + var data = []; + list.forEach(function(l){ + var matches = l.match(/\-\s+([\d\/\-\~]+)\s(.*)/i); + var time = matches[1]; + var text = matches[2]; + data.push({ + time: life.parseTime(time), + text: text + }); + }); + return data; + }, + parseTitle: function(response){ + return response.match(/[^\r\n]+/i)[0]; + }, + parseTime: function(time, point){ + if (!point) point = 'start'; + var data = {}; + if (/^\~\d+$/.test(time)){ // ~YYYY + data = { + startYear: parseInt(time.slice(1), 10), + estimate: true + }; + } else if (/^\d+$/.test(time)){ // YYYY + data[point + 'Year'] = parseInt(time, 10); + } else if (/^\d+\/\d+$/.test(time)){ // MM/YYYY + var t = time.split('/'); + data[point + 'Month'] = parseInt(t[0], 10); + data[point + 'Year'] = parseInt(t[1], 10); + } else if (/^\d+\/\d+\/\d+$/.test(time)){ // DD/MM/YYYY + var t = time.split('/'); + data[point + 'Date'] = parseInt(t[0], 10); + data[point + 'Month'] = parseInt(t[1], 10); + data[point + 'Year'] = parseInt(t[2], 10); + } else if (/\d\-/.test(time)){ // TIME-TIME + var splitTime = time.split('-'); + var startTime = life.parseTime(splitTime[0]); + var endTime = life.parseTime(splitTime[1], 'end'); + for (var k in startTime) { data[k] = startTime[k] } + for (var k in endTime) { data[k] = endTime[k] } + } else if (time == '~'){ // NOW + var now = new Date(); + data.endYear = now.getFullYear(); + data.endMonth = now.getMonth()+1; + data.endDate = now.getDate(); + } + data.title = time; + return data; + }, + firstYear: null, + renderEvent: function(d){ + var firstYear = life.firstYear; + var yearLength = life.config.yearLength; + var monthLength = yearLength/12; + var dayLength = monthLength/30; + + var time = d.time; + var estimate = time.estimate; + var startYear = time.startYear; + var startMonth = time.startMonth; + var startDate = time.startDate; + var endYear = time.endYear; + var endMonth = time.endMonth; + var endDate = time.endDate; + var width = 0; + + // Calculate offset + var startTime = new Date(firstYear, 0, 1); + var endTime = new Date(startYear, startMonth ? startMonth-1 : 0, startDate || 1); + var daysDiff = (endTime - startTime)/(24*60*60*1000); + offset = daysDiff*dayLength; + + // Calculate width + if (endYear){ + var _endMonth = endMonth ? endMonth-1 : 11; + var _endDate = endDate || new Date(endYear, _endMonth+1, 0).getDate(); + startTime = new Date(startYear, startMonth ? startMonth-1 : 0, startDate || 1); + endTime = new Date(endYear, _endMonth, _endDate); + daysDiff = (endTime - startTime)/(24*60*60*1000); + width = daysDiff*dayLength; + } else { + if (startDate){ + width = dayLength; + } else if (startMonth){ + width = monthLength; + } else { + width = yearLength; + } + } + + // Parse Markdown links in the text + // credit: http://stackoverflow.com/a/9268827 + var link = null; + while(link = d.text.match(/\[([^\]]+)\]\(([^)"]+)(?: \"([^\"]+)\")?\)/)) { + var link_attr = ""; + if (link[3] !== undefined) { + link_attr = " title='" + link[3] + "'"; + } + d.text = d.text.replace(link[0], "" + link[1] + ""); + } + + return '
' + + '
' + + '' + d.time.title + ' ' + d.text + '  ' + + '
'; + return ''; + }, + renderYears: function(firstYear, lastYear){ + var dayLength = life.config.yearLength/12/30; + var html = ''; + var days = 0; + var hideAge = life.config.hideAge; + for (var y=firstYear, age = 0; y<=lastYear+1; y++, age++){ + html += '
' + + y + (hideAge ? '' : (' (' + age + ')')) + + '
'; + days += (y % 4 == 0) ? 366 : 365; + } + return html; + }, + render: function(title, data){ + document.title = title; + life.$title.innerHTML = title; + + // Get the first and last year for the year axis + var firstYear = new Date().getFullYear(); + var lastYear = firstYear; + data.forEach(function(d){ + var time = d.time; + var startYear = time.startYear; + var endYear = time.endYear; + if (startYear && startYear < firstYear) firstYear = startYear; + if (endYear && endYear > lastYear) lastYear = endYear; + }); + life.firstYear = firstYear; + + var html = life.renderYears(firstYear, lastYear); + data.forEach(function(d){ + html += life.renderEvent(d); + }); + life.$el.innerHTML = html; + } + }; + + var slider = { + startingMousePostition: {}, + startingPagePosition: {}, + init: function(){ + window.addEventListener('mousedown', function(event){ + slider.startingMousePostition = { + x: event.clientX, + y: event.clientY + }; + slider.startingPagePosition = { + x: window.pageXOffset, + y: window.pageYOffset + }; + window.addEventListener('mousemove', slider.slide); + }); + window.addEventListener('mouseup', function(event){ + window.removeEventListener('mousemove', slider.slide); + }); + }, + slide: function(event){ + event.preventDefault(); + var x = slider.startingPagePosition.x + (slider.startingMousePostition.x - event.clientX); + var y = slider.startingPagePosition.y + (slider.startingMousePostition.y - event.clientY); + window.scrollTo(x, y); + } + }; + + life.start(); + slider.init(); +})(); diff --git a/config.example.json b/config.example.json deleted file mode 100644 index 83ce44a..0000000 --- a/config.example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "customStylesheetURL": null, - "yearLength": 120, - "hideAge": false -} \ No newline at end of file diff --git a/life.example.md b/life.md similarity index 100% rename from life.example.md rename to life.md diff --git a/views/index.jade b/views/index.jade new file mode 100644 index 0000000..17b548e --- /dev/null +++ b/views/index.jade @@ -0,0 +1,5 @@ +header + h1#title Life + a(href='https://github.com/cheeaun/life') Fork me + +#life diff --git a/views/layout.jade b/views/layout.jade new file mode 100644 index 0000000..632208b --- /dev/null +++ b/views/layout.jade @@ -0,0 +1,14 @@ +doctype html +html + head + meta(charset='UTF-8') + title Life + meta(name='viewport', content='width=device-width, initial-scale=1') + meta(name='format-detection', content='telephone=no') + link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=Open+Sans:400,300') + link(rel='stylesheet', href='/css/main.css') + body + != content + script. + lifeConfig = !{lifeConfig}; + script(src='/js/main.js') From 22382e9088c58d10a353d435c52d7b1d17cb6bb3 Mon Sep 17 00:00:00 2001 From: Sean Lang Date: Tue, 7 Jan 2014 04:18:05 -0600 Subject: [PATCH 3/7] make it compile into 1 file (public/index.html) --- app.coffee | 4 ++-- assets/css/{main.css => _main.css} | 0 assets/js/{main.js => _main.js} | 0 views/layout.jade | 6 +++--- 4 files changed, 5 insertions(+), 5 deletions(-) rename assets/css/{main.css => _main.css} (100%) rename assets/js/{main.js => _main.js} (100%) diff --git a/app.coffee b/app.coffee index 3e7b925..05e65b9 100644 --- a/app.coffee +++ b/app.coffee @@ -2,8 +2,8 @@ fs = require 'fs' # roots v2.1.2 # Files in this list will not be compiled - minimatch supported -ignore_files: ['_*', 'readme*', '.gitignore', '.DS_Store', 'life.md'] -ignore_folders: ['.git'] +ignore_files: ['_*', 'README*', '.gitignore', '.DS_Store', 'life.md'] +ignore_folders: ['.git', 'css', 'js'] layouts: default: 'layout.jade' diff --git a/assets/css/main.css b/assets/css/_main.css similarity index 100% rename from assets/css/main.css rename to assets/css/_main.css diff --git a/assets/js/main.js b/assets/js/_main.js similarity index 100% rename from assets/js/main.js rename to assets/js/_main.js diff --git a/views/layout.jade b/views/layout.jade index 632208b..94f7b15 100644 --- a/views/layout.jade +++ b/views/layout.jade @@ -6,9 +6,9 @@ html meta(name='viewport', content='width=device-width, initial-scale=1') meta(name='format-detection', content='telephone=no') link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=Open+Sans:400,300') - link(rel='stylesheet', href='/css/main.css') + include ../assets/css/_main.css body != content - script. + script lifeConfig = !{lifeConfig}; - script(src='/js/main.js') + include ../assets/js/_main.js From f95ce73fb1693f1b939f85f2e238fa04329d21e7 Mon Sep 17 00:00:00 2001 From: Sean Lang Date: Tue, 7 Jan 2014 04:34:24 -0600 Subject: [PATCH 4/7] update docs to work with roots --- README.md | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 46267cf..02b5479 100644 --- a/README.md +++ b/README.md @@ -26,38 +26,34 @@ How to setup your own *Life* 1. Fork this project. 2. `git checkout -b gh-pages` (or any branch name you like) -3. Make a copy of `life.example.md`, rename it to `life.md`. +3. install [roots](http://roots.cx): `npm install roots -g` 4. Add your life events into `life.md`. -5. Preview it on a local server. Use [`python -m SimpleHTTPServer`](http://docs.python.org/2/library/simplehttpserver.html) or [`http-server`](https://github.com/nodeapps/http-server). -6. Commit `life.md` (not in `master` branch). -7. `git push origin gh-pages -f` and publish to [GitHub Pages](http://pages.github.com/). -8. Update the website link in your GitHub repo description. -9. Tell the world about your Life. -10. Add your Life to the [Lives](https://github.com/cheeaun/life/wiki/Lives) page. +5. Preview your life by running `roots watch` from within the project directory. +6. When you like it, run `roots compile`. +7. `./public/index.html` is the resulting self-contained, compiled life. +8. Commit `life.md` (not in `master` branch). +9. Use `roots deploy --gh-pages` to deploy your life to [GitHub Pages](http://pages.github.com/) +10. Update the website link in your GitHub repo description. +11. Tell the world about your Life. +12. Add your Life to the [Lives](https://github.com/cheeaun/life/wiki/Lives) page. How to upgrade your *Life* -------------------------- -1. `git checkout master` -2. `git remote add cheeaun https://github.com/cheeaun/life.git` -3. `git fetch cheeaun` and `git merge cheeaun/master` to upgrade to latest Life. -4. `git checkout gh-pages` and `git merge master` to sync changes back to GitHub Pages. +Fetch this repo and rebase your configuration on top of it. [Learn more](https://help.github.com/articles/fork-a-repo). -For those who forked the earlier version of Life, these are the steps that I would recommend (requires some Git-fu): +For those who forked the earlier version of Life, these are the steps that I would recommend: 1. Backup your `life.md`. 2. Reset (hard) your fork to this repo's `master` branch. -3. Clean up your `gh-pages`. -4. Re-commit your `life.md` there. -5. Make sure your `master` branch is untouched so that future updates work. +3. Re-commit your `life.md`. How to configure your *Life* ---------------------------- -1. Make a copy of `config.example.json`, rename it to `config.json`. -2. Only commit it in `gh-pages` branch. +Edit `lifeConfig` in `app.coffee`. The configuration: From 34d1e3b023248ed0ab012a24acc5b0bd1d58a8d2 Mon Sep 17 00:00:00 2001 From: Sean Lang Date: Tue, 7 Jan 2014 04:38:10 -0600 Subject: [PATCH 5/7] add license --- LICENSE | 20 ++++++++++++++++++++ app.coffee | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..111ecab --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Lim Chee Aun + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/app.coffee b/app.coffee index 05e65b9..cfbf9a6 100644 --- a/app.coffee +++ b/app.coffee @@ -2,7 +2,7 @@ fs = require 'fs' # roots v2.1.2 # Files in this list will not be compiled - minimatch supported -ignore_files: ['_*', 'README*', '.gitignore', '.DS_Store', 'life.md'] +ignore_files: ['_*', 'README*', '.gitignore', '.DS_Store', 'life.md', 'LICENSE'] ignore_folders: ['.git', 'css', 'js'] layouts: From c527752873f8ef6bf097a0f998fe564b75260e93 Mon Sep 17 00:00:00 2001 From: Sean Lang Date: Tue, 7 Jan 2014 04:40:07 -0600 Subject: [PATCH 6/7] little fix in readme --- README.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 02b5479..c0efd3c 100644 --- a/README.md +++ b/README.md @@ -25,17 +25,16 @@ How to setup your own *Life* ---------------------------- 1. Fork this project. -2. `git checkout -b gh-pages` (or any branch name you like) -3. install [roots](http://roots.cx): `npm install roots -g` -4. Add your life events into `life.md`. -5. Preview your life by running `roots watch` from within the project directory. -6. When you like it, run `roots compile`. -7. `./public/index.html` is the resulting self-contained, compiled life. -8. Commit `life.md` (not in `master` branch). -9. Use `roots deploy --gh-pages` to deploy your life to [GitHub Pages](http://pages.github.com/) -10. Update the website link in your GitHub repo description. -11. Tell the world about your Life. -12. Add your Life to the [Lives](https://github.com/cheeaun/life/wiki/Lives) page. +2. install [roots](http://roots.cx): `npm install roots -g` +3. Add your life events into `life.md`. +4. Preview your life by running `roots watch` from within the project directory. +5. When you like it, run `roots compile`. +6. `./public/index.html` is the resulting self-contained, compiled life. +7. Commit `life.md`. +8. Use `roots deploy --gh-pages` to deploy your life to [GitHub Pages](http://pages.github.com/) +9. Update the website link in your GitHub repo description. +10. Tell the world about your Life. +11. Add your Life to the [Lives](https://github.com/cheeaun/life/wiki/Lives) page. How to upgrade your *Life* -------------------------- From cfbd714233cbb5b0cb50af5aa45642935de83ba3 Mon Sep 17 00:00:00 2001 From: Sean Lang Date: Tue, 7 Jan 2014 05:05:44 -0600 Subject: [PATCH 7/7] deal with customStylesheetURL via jade --- app.coffee | 2 +- assets/js/_main.js | 11 +---------- views/layout.jade | 3 +++ 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/app.coffee b/app.coffee index cfbf9a6..43e5da0 100644 --- a/app.coffee +++ b/app.coffee @@ -10,8 +10,8 @@ layouts: locals: lifeConfig: JSON.stringify( - customStylesheetURL: null yearLength: 120 hideAge: false markdown: String(fs.readFileSync 'life.md') ) + customStylesheetURL: null diff --git a/assets/js/_main.js b/assets/js/_main.js index f3f760c..f7b40a8 100644 --- a/assets/js/_main.js +++ b/assets/js/_main.js @@ -16,24 +16,15 @@ }, config: { yearLength: 120, // 120px per year - hideAge: false, // Hide age from year axis - customStylesheetURL: null // Custom stylesheet + hideAge: false // Hide age from year axis }, start: function(){ life.config = life.utils.extend(life.config, lifeConfig); - if (life.config.customStylesheetURL) life.injectStylesheet(life.config.customStylesheetURL); - var data = life.parse(life.config.markdown); var title = life.parseTitle(life.config.markdown); life.render(title, data); }, - injectStylesheet: function(url){ - var link = document.createElement('link'); - link.rel = 'stylesheet'; - link.href = url; - document.body.appendChild(link); - }, parse: function(response){ var list = response.match(/\-\s+[^\n\r]+/ig); var data = []; diff --git a/views/layout.jade b/views/layout.jade index 94f7b15..904e180 100644 --- a/views/layout.jade +++ b/views/layout.jade @@ -6,6 +6,9 @@ html meta(name='viewport', content='width=device-width, initial-scale=1') meta(name='format-detection', content='telephone=no') link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=Open+Sans:400,300') + if customStylesheetURL + link(rel='stylesheet', href!=customStylesheetURL) + include ../assets/css/_main.css body != content