31 | );
32 | }
33 | })
34 |
35 | export default App;
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Mitul Shah
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | table, td, th {
2 | border: 1px solid #ddd;
3 | font-size: 14px;
4 | }
5 |
6 | table {
7 | border-collapse: collapse;
8 | text-align: center;
9 | width: 100%;
10 | margin-bottom: 20px;
11 | }
12 |
13 | th, td {
14 | padding: 15px;
15 | }
16 |
17 | th.time {
18 | width: 20%;
19 | }
20 |
21 | th.task {
22 | width: 80%;
23 | }
24 |
25 | .task-creator {
26 | display: flex;
27 | margin-bottom: 10px;
28 | }
29 |
30 | .task-creator__task-name {
31 | display: flex;
32 | flex-grow: 10;
33 | padding-right: 5px;
34 | }
35 |
36 | .task-creator__duration {
37 | display: flex;
38 | padding-right: 5px;
39 | }
40 |
41 | .task-creator__add-btn {
42 | display: flex;
43 | }
44 |
45 | .task-creator__start-time {
46 | flex-grow: 1;
47 | display: flex;
48 | padding-right: 5px;
49 | }
50 |
51 | .task-creator__task-name input {
52 | flex-grow: 1;
53 | }
54 |
55 | .task-creator__duration select {
56 | flex-grow: 1;
57 | }
58 |
59 | .task-creator__add-btn button {
60 | flex-grow: 1;
61 | }
62 |
63 | .task-creator__start-time select{
64 | flex-grow: 1;
65 | }
66 |
67 | .time-slot__task {
68 | position: relative;
69 | text-align: left;
70 | }
71 |
72 | .time-slot__task:hover {
73 | cursor: pointer;
74 | }
75 |
76 | .time-slot__remove-btn {
77 | display: none;
78 |
79 | float: right;
80 | position: absolute;
81 | top: 15px;
82 | right: 15px;
83 | }
84 |
85 | .time-slot__task:hover .time-slot__remove-btn {
86 | display: block;
87 | }
88 |
89 | .time-slot__task--done {
90 | color: #CECECE;
91 | }
92 |
93 | .time-slot--active {
94 | background-color: aliceblue;
95 | }
96 |
97 | .header {
98 | margin-left: 5%;
99 | }
100 |
101 | .header__text {
102 | display: inline-block;
103 | height: 35px;
104 | vertical-align: super;
105 | }
106 |
107 | .header__logo {
108 | width: 35px;
109 | }
110 |
111 | .header__logo img {
112 | width: 35px;
113 | }
114 |
115 | .time-slot__task__name {
116 | padding-left: 15px;
117 | }
118 |
119 | .other-tasks__input {
120 | width: 100%;
121 | }
122 |
123 | .other-tasks__task-list {
124 | font-size: 14px;
125 | padding-left: 12px;
126 | }
127 |
128 | .other-tasks__task-list__item {
129 | margin: 5px;
130 | }
131 |
132 | .container {
133 | margin-left: 5%;
134 | margin-right: 5%;
135 | }
136 |
137 | .container--left {
138 | width: 70%;
139 | display: inline-block;
140 | }
141 |
142 | .container--right {
143 | width: 25%;
144 | float: right;
145 | }
146 |
147 | .time-slot__task__name--input {
148 | width: 80%;
149 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 📋 ta - calendar
2 | An app to plan your day, _every minute of your day_. Have you ever felt the day is about to be over and you haven't even started on the first thing to do?
3 |
4 | ## Motivation
5 | _"One of the most valuable skills in our economy is becoming increasingly rare."_ - [Cal Newport](http://calnewport.com/).
6 |
7 | [Deep work](https://www.goodreads.com/book/show/25744928-deep-work) is the ability to focus without distraction on a cognitively demanding task. It’s a skill that allows you to quickly master complicated information and produce better results in less time. Deep work will make you better at what you do and provide the sense of true fulfillment that comes from craftsmanship. It's like a superpower in our increasingly competitive twenty-first-century economy.
8 |
9 | One way to achieve deep work is to spend time only on things that matter. We spend much of our day on autopilot mode. To avoid this, we have to drain the shallows, we have to take control of our time, we have to _schedule every minute of the day_. We must prioritize ruthlessly, and strike out everything that isn't worth the time.
10 |
11 | This app helps you to achieve exactly that. It allows you to plan your day in intervals of 30 minutes. There is small to-do list widget on the right side which is to dump everything else that comes in-between. The idea is to focus only on one and one thing at a time - what are we doing today.
12 |
13 | ## Why not any other todo list?
14 | Most of the to-do lists help you list down things you want to do without considering the most important factor - how long will it take? And within a couple of days, that list becomes wishlist of things we want to achieve (sometime in future). ta - calendar helps by considering that task duration. Whenever you plan task you have to specify when you will do and how long it will take, this way your today's list does not become a dump of things to do.
15 |
16 | Of course, the idea is not to keep working for 9 hours a day deeply. But to keep track of your own time. You can (and should) always add entries like `Lunch`, `Foosball game`, etc to keep list concise.
17 |
18 | ## What does ta - calendar mean?
19 | It's just a word I came up with. Probably a mixture of `task list`, `todo list`, and `calendar`.
20 |
21 | ## Technology
22 | This app is built using [React](https://facebook.github.io/react/), and everything is stored in browser's `localStorage`. There is no server. The app, tasks, everything lives in your browser. So don't worry about privacy and other stuff. It uses GA to gather some fun stats.
23 |
24 | ## Check it out
25 | https://mitul45.github.io/ta-calendar/
26 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ta – calendar
7 |
8 |
9 |
10 |
20 |
21 |
22 |
23 |
24 |
33 |
34 |
--------------------------------------------------------------------------------
/src/TaskCreator.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Module for adding task, consisting input box for task name,
3 | * and two select fields for duration and start time.
4 | *
5 | * Calls parents addTask method on creation of task
6 | */
7 | import React from 'react';
8 | import Utils from './Utils'
9 |
10 | const START_TIME = Utils.START_TIME;
11 | const END_TIME = Utils.END_TIME;
12 |
13 | var TaskCreator = React.createClass({
14 |
15 | getInitialState() {
16 | return {
17 | startTime: START_TIME,
18 | taskName: "",
19 | taskDuration: 0.5,
20 | }
21 | },
22 |
23 | /**
24 | * Onclick handler for `Add` button
25 | */
26 | addTask() {
27 | this.props.addTask(this.state.taskName, this.state.taskDuration, this.state.startTime);
28 | this.setState(this.getInitialState());
29 | },
30 |
31 | /**
32 | * Handlers for keeping internal state, and view in sync
33 | */
34 |
35 | handleTaskNameChange(event) {
36 | this.setState({
37 | taskName: event.target.value
38 | })
39 | },
40 |
41 | handleTaskDurationChange(event) {
42 | this.setState({
43 | taskDuration: event.target.value
44 | })
45 | },
46 |
47 | handleStartTimeChange(event) {
48 | this.setState({
49 | startTime: event.target.value
50 | })
51 | },
52 |
53 | render() {
54 |
55 | const startTimes = [];
56 | for (let i = START_TIME; i < END_TIME; i += 0.5) {
57 | startTimes.push();
58 | }
59 |
60 | return (
61 |
89 | )
90 | }
91 | })
92 |
93 | export default TaskCreator;
94 |
--------------------------------------------------------------------------------
/src/TimeSlot.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Utils from './Utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | var TimeSlot = React.createClass({
6 |
7 | getInitialState() {
8 | return {
9 | taskName: this.props.timeSlot.taskName,
10 | editable: false,
11 | }
12 | },
13 |
14 | /**
15 | * Format a slot object to human readable time.
16 | * @param {Object} slot
17 | * @returns {String}
18 | */
19 | formatSlot(slot) {
20 | return Utils.formatTime(slot.startTime);
21 | },
22 |
23 | deleteTask() {
24 | this.props.deleteTask(this.props.timeSlot);
25 | },
26 |
27 | handleCheckboxChange(event) {
28 | this.props.completeTask(this.props.timeSlot, event.target.checked);
29 | },
30 |
31 | /**
32 | * Mark this slot as editable, and show input field.
33 | */
34 | handleDoubleClick() {
35 | this.setState({
36 | editable: true,
37 | newTask: this.props.timeSlot.taskName,
38 | })
39 | },
40 |
41 | /**
42 | * Keep view and state in sync
43 | */
44 | handleTextChange(event) {
45 | this.setState({
46 | newTask: event.target.value,
47 | })
48 | },
49 |
50 | /**
51 | * Save task on enter and restore to previous on esc.
52 | */
53 | handleKeyDown(event) {
54 | if (event.keyCode === 13 ) {
55 | this.createTask(this.state.newTask);
56 | } else if (event.keyCode === 27) {
57 | this.setState({
58 | editable: false,
59 | })
60 | }
61 | },
62 |
63 | /**
64 | * create task in parent scope.
65 | * @param {any} taskName
66 | */
67 | createTask(taskName) {
68 | this.props.createTask(this.props.timeSlot, taskName);
69 | this.setState({
70 | editable: false,
71 | })
72 | },
73 |
74 | render() {
75 | return (
76 |