Life begins
This commit is contained in:
commit
b9172370f2
41
README.md
Normal file
41
README.md
Normal file
@ -0,0 +1,41 @@
|
||||
Life
|
||||
====
|
||||
|
||||
This is something that I've wanted to build for a long time. It's a **timeline of important events** in my life, visualized in a way my mind always imagine it. There was something called [**Lifepath.me**](http://dcurt.is/facebook-timelines-and-lifepath-me-4) but now it's gone. How about Facebook timeline? Meh.
|
||||
|
||||
So, this is it. Have a look at [cheeaun.github.io/life](http://cheeaun.github.io/life).
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Super simple
|
||||
- No fancy formatting
|
||||
- No fancy setup
|
||||
- No fancy effects
|
||||
- Flexible datetimes because sometimes you don't remember the exact date of an event
|
||||
|
||||
How to contribute
|
||||
-----------------
|
||||
|
||||
1. Fork this project.
|
||||
2. Write code.
|
||||
3. Make pull requests.
|
||||
|
||||
How to setup your own *Life*
|
||||
----------------------------
|
||||
|
||||
1. Fork this project.
|
||||
2. Edit `life.md`.
|
||||
3. Push to `gh-pages` branch and publish to [GitHub Pages](http://pages.github.com/).
|
||||
|
||||
Special datetime formats
|
||||
------------------------
|
||||
|
||||
- `2001-2005`, `10/2001-02/03/2005` - Within the two dates
|
||||
- `~2005` - Around the time in that year
|
||||
- `2005-~` - From that year and beyond (now).
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
[MIT](http://cheeaun.mit-license.org/)
|
233
index.html
Normal file
233
index.html
Normal file
@ -0,0 +1,233 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="UTF-8">
|
||||
<title>Life</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Open+Sans:400,300">
|
||||
<style>
|
||||
*{
|
||||
font-family: Open Sans, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
body{
|
||||
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{
|
||||
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;
|
||||
}
|
||||
#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{
|
||||
vertical-align: middle;
|
||||
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;
|
||||
}
|
||||
</style>
|
||||
<header>
|
||||
<h1 id="title">Life</h1>
|
||||
<a href="https://github.com/cheeaun/life">Fork me</a>
|
||||
</header>
|
||||
<div id="life"></div>
|
||||
<script>
|
||||
(function(){
|
||||
var life = {
|
||||
$title: document.getElementById('title'),
|
||||
$el: document.getElementById('life'),
|
||||
yearLength: 120, // 120px per year
|
||||
start: function(){
|
||||
life.fetch(function(response){
|
||||
var data = life.parse(response);
|
||||
var title = life.parseTitle(response);
|
||||
life.render(title, data);
|
||||
});
|
||||
},
|
||||
fetch: function(fn){
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'life.md', true);
|
||||
xhr.onload = function(){
|
||||
if (xhr.status == 200) fn(xhr.responseText);
|
||||
};
|
||||
xhr.send();
|
||||
},
|
||||
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.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;
|
||||
}
|
||||
}
|
||||
|
||||
return '<div class="event" style="margin-left: ' + offset.toFixed(2) + 'px"><div class="time" style="width: ' + width.toFixed(2) + 'px"></div><b>' + d.time.title + '</b> ' + d.text + ' </div>';
|
||||
return '';
|
||||
},
|
||||
render: function(title, data){
|
||||
document.title = title;
|
||||
life.$title.innerHTML = title;
|
||||
|
||||
var firstYear = life.firstYear = data[0].time.startYear;
|
||||
var nowYear = new Date().getFullYear();
|
||||
var dayLength = life.yearLength/12/30;
|
||||
|
||||
html = '';
|
||||
var days = 0;
|
||||
for (var y=firstYear; y<=nowYear+1; y++){
|
||||
html += '<section class="year" style="left: ' + (days*dayLength) + 'px">' + y + '</section>';
|
||||
days += (y % 4 == 0) ? 366 : 365;
|
||||
}
|
||||
data.forEach(function(d){
|
||||
html += life.renderEvent(d);
|
||||
});
|
||||
life.$el.innerHTML = html;
|
||||
}
|
||||
}
|
||||
|
||||
life.start();
|
||||
})();
|
||||
</script>
|
22
life.md
Normal file
22
life.md
Normal file
@ -0,0 +1,22 @@
|
||||
@cheeaun's life
|
||||
===============
|
||||
|
||||
- 20/06/1985 Born
|
||||
- 1991 Kindergarten
|
||||
- 1992-1997 Primary school - SKSJ
|
||||
- 1998-2000 Secondary school - SMKTI
|
||||
- ~2000 First computer
|
||||
- 2001-2002 Secondary school - SMKDOB
|
||||
- 04/11/2002 Phoenity is born
|
||||
- 2003-2004 Secondary school (Form 6) - SMKDOB
|
||||
- 01/2005-03/2005 First (non-technical) job
|
||||
- 08/2005-08/2008 University - UTAR
|
||||
- 11/2005 Dead hard drive of first computer
|
||||
- 07/2006-05/2007 CSS Web Designer - MindValley
|
||||
- 18/12/2006 First tweet
|
||||
- 04/2007 First laptop (HP)
|
||||
- 06/2008-07/2009 Web Developer at ZoeCity
|
||||
- 24/08/2009-26/06/2013 Front-End Developer - Wego
|
||||
- 07/2010 Second laptop (Dell)
|
||||
- 04/03/2012 HackerWeb featured on Hacker News' front page
|
||||
- 01/07/2013-~ Software Engineer - Viki
|
Loading…
Reference in New Issue
Block a user