mirror of
https://github.com/morris/vanilla-todo.git
synced 2025-08-21 05:11:20 +02:00
add date picker, refactor event names, cleanups
This commit is contained in:
@@ -804,6 +804,7 @@ Thanks!
|
||||
- Refactored for event-driven communication exclusively
|
||||
- Moved original ES5-based version of the study to [/es5](./es5)
|
||||
- Added assessment regarding library development
|
||||
- Added date picker
|
||||
|
||||
### 01/2021
|
||||
|
||||
|
38
package-lock.json
generated
38
package-lock.json
generated
@@ -89,19 +89,19 @@
|
||||
}
|
||||
},
|
||||
"@eslint/eslintrc": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz",
|
||||
"integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==",
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz",
|
||||
"integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
"espree": "^9.3.1",
|
||||
"espree": "^9.3.2",
|
||||
"globals": "^13.9.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"minimatch": "^3.1.2",
|
||||
"strip-json-comments": "^3.1.1"
|
||||
}
|
||||
},
|
||||
@@ -532,12 +532,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"eslint": {
|
||||
"version": "8.14.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz",
|
||||
"integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==",
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz",
|
||||
"integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint/eslintrc": "^1.2.2",
|
||||
"@eslint/eslintrc": "^1.2.3",
|
||||
"@humanwhocodes/config-array": "^0.9.2",
|
||||
"ajv": "^6.10.0",
|
||||
"chalk": "^4.0.0",
|
||||
@@ -548,7 +548,7 @@
|
||||
"eslint-scope": "^7.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"eslint-visitor-keys": "^3.3.0",
|
||||
"espree": "^9.3.1",
|
||||
"espree": "^9.3.2",
|
||||
"esquery": "^1.4.0",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
@@ -564,7 +564,7 @@
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.4.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.0.4",
|
||||
"minimatch": "^3.1.2",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.1",
|
||||
"regexpp": "^3.2.0",
|
||||
@@ -624,13 +624,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"espree": {
|
||||
"version": "9.3.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz",
|
||||
"integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==",
|
||||
"version": "9.3.2",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz",
|
||||
"integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^8.7.0",
|
||||
"acorn-jsx": "^5.3.1",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
@@ -882,9 +882,9 @@
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"version": "13.13.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz",
|
||||
"integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==",
|
||||
"version": "13.14.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.14.0.tgz",
|
||||
"integrity": "sha512-ERO68sOYwm5UuLvSJTY7w7NP2c8S4UcXs3X1GBX8cwOr+ShOcDBbCY5mH4zxz0jsYCdJ8ve8Mv9n2YGJMB1aeg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"type-fest": "^0.20.2"
|
||||
|
@@ -26,7 +26,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/morris/vanilla-todo#readme",
|
||||
"devDependencies": {
|
||||
"eslint": "^8.14.0",
|
||||
"eslint": "^8.15.0",
|
||||
"eslint-plugin-compat": "^4.0.2",
|
||||
"http-server": "^14.1.0",
|
||||
"prettier": "^2.6.2",
|
||||
|
@@ -12,9 +12,11 @@
|
||||
<link rel="stylesheet" href="styles/base.css" />
|
||||
<link rel="stylesheet" href="styles/app-button.css" />
|
||||
<link rel="stylesheet" href="styles/app-collapsible.css" />
|
||||
<link rel="stylesheet" href="styles/app-date-picker.css" />
|
||||
<link rel="stylesheet" href="styles/app-footer.css" />
|
||||
<link rel="stylesheet" href="styles/app-header.css" />
|
||||
<link rel="stylesheet" href="styles/app-icon.css" />
|
||||
<link rel="stylesheet" href="styles/todo-app.css" />
|
||||
<link rel="stylesheet" href="styles/todo-custom-list.css" />
|
||||
<link rel="stylesheet" href="styles/todo-day.css" />
|
||||
<link rel="stylesheet" href="styles/todo-frame.css" />
|
||||
|
158
public/scripts/AppDatePicker.js
Normal file
158
public/scripts/AppDatePicker.js
Normal file
@@ -0,0 +1,158 @@
|
||||
import { AppIcon } from './AppIcon.js';
|
||||
import { formatMonth } from './util.js';
|
||||
|
||||
const datesCell = `
|
||||
<td><button class="app-button"></button></td>
|
||||
`;
|
||||
|
||||
const datesRow = `
|
||||
<tr>
|
||||
${datesCell}
|
||||
${datesCell}
|
||||
${datesCell}
|
||||
${datesCell}
|
||||
${datesCell}
|
||||
${datesCell}
|
||||
${datesCell}
|
||||
</tr>
|
||||
`;
|
||||
|
||||
export function AppDatePicker(el) {
|
||||
const now = new Date();
|
||||
const state = {
|
||||
year: now.getFullYear(),
|
||||
month: now.getMonth() + 1,
|
||||
show: false,
|
||||
};
|
||||
|
||||
el.innerHTML = `
|
||||
<h4 class="header">
|
||||
<button class="app-button -circle previousmonth">
|
||||
<i class="app-icon" data-id="chevron-left-16"></i>
|
||||
</button>
|
||||
<span class="month"></span>
|
||||
<button class="app-button -circle nextmonth">
|
||||
<i class="app-icon" data-id="chevron-right-16"></i>
|
||||
</button>
|
||||
</h4>
|
||||
<table class="dates">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Su</th>
|
||||
<th>Mo</th>
|
||||
<th>Tu</th>
|
||||
<th>We</th>
|
||||
<th>Th</th>
|
||||
<th>Fr</th>
|
||||
<th>Sa</th>
|
||||
<tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${datesRow}
|
||||
${datesRow}
|
||||
${datesRow}
|
||||
${datesRow}
|
||||
${datesRow}
|
||||
</tbody>
|
||||
</div>
|
||||
`;
|
||||
|
||||
el.querySelectorAll('.app-icon').forEach(AppIcon);
|
||||
|
||||
el.addEventListener('toggleDatePicker', (e) =>
|
||||
update({ show: e.detail ?? !state.show })
|
||||
);
|
||||
|
||||
el.addEventListener('setMonth', (e) => update(e.detail));
|
||||
|
||||
el.querySelector('.previousmonth').addEventListener('click', previousMonth);
|
||||
el.querySelector('.nextmonth').addEventListener('click', nextMonth);
|
||||
|
||||
el.addEventListener('click', (e) => {
|
||||
if (!e.target.matches('.app-button')) return;
|
||||
|
||||
update({ show: false });
|
||||
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('pickDate', {
|
||||
detail: new Date(
|
||||
e.target.dataset.year,
|
||||
e.target.dataset.month - 1,
|
||||
e.target.dataset.day
|
||||
),
|
||||
bubbles: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
function previousMonth() {
|
||||
update(
|
||||
state.month > 1
|
||||
? {
|
||||
year: state.year,
|
||||
month: state.month - 1,
|
||||
}
|
||||
: {
|
||||
year: state.year - 1,
|
||||
month: 12,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function nextMonth() {
|
||||
update(
|
||||
state.month < 12
|
||||
? {
|
||||
year: state.year,
|
||||
month: state.month + 1,
|
||||
}
|
||||
: {
|
||||
year: state.year + 1,
|
||||
month: 1,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function update(next) {
|
||||
Object.assign(state, next);
|
||||
|
||||
el.classList.toggle('-show', state.show);
|
||||
|
||||
const now = new Date();
|
||||
const first = new Date(state.year, state.month - 1, 1);
|
||||
|
||||
el.querySelector('.month').innerHTML = `${formatMonth(
|
||||
first
|
||||
)} ${first.getFullYear()}`;
|
||||
|
||||
let current = new Date(first);
|
||||
current.setDate(1 - current.getDay());
|
||||
|
||||
const datesBody = el.querySelector('.dates > tbody');
|
||||
|
||||
for (let i = 0; i < 35; ++i) {
|
||||
const row = Math.floor(i / 7);
|
||||
const column = i % 7;
|
||||
|
||||
const cell = datesBody.children[row].children[column];
|
||||
const button = cell.children[0];
|
||||
|
||||
button.innerHTML = current.getDate();
|
||||
|
||||
button.dataset.year = current.getFullYear();
|
||||
button.dataset.month = current.getMonth() + 1;
|
||||
button.dataset.day = current.getDate();
|
||||
|
||||
button.classList.toggle(
|
||||
'-highlight',
|
||||
current.getFullYear() === now.getFullYear() &&
|
||||
current.getMonth() === now.getMonth() &&
|
||||
current.getDate() === now.getDate()
|
||||
);
|
||||
|
||||
current.setDate(current.getDate() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
@@ -23,7 +23,9 @@ export function TodoApp(el) {
|
||||
<div class="todo-frame -days"></div>
|
||||
<div class="app-collapsible">
|
||||
<p class="bar">
|
||||
<button class="app-button -circle toggle"><i class="app-icon" data-id="chevron-up-24"></i></button>
|
||||
<button class="app-button -circle toggle">
|
||||
<i class="app-icon" data-id="chevron-up-24"></i>
|
||||
</button>
|
||||
</p>
|
||||
<div class="body">
|
||||
<div class="todo-frame -custom"></div>
|
||||
@@ -101,7 +103,7 @@ export function TodoApp(el) {
|
||||
el.addEventListener('draggableCancel', flip);
|
||||
el.addEventListener('draggableDrop', flip);
|
||||
|
||||
el.dispatchEvent(new CustomEvent('loadStore'));
|
||||
el.dispatchEvent(new CustomEvent('loadTodoStore'));
|
||||
|
||||
function update(next) {
|
||||
Object.assign(state, next);
|
||||
|
@@ -76,7 +76,7 @@ export function TodoCustomList(el) {
|
||||
}
|
||||
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('deleteList', {
|
||||
new CustomEvent('deleteTodoList', {
|
||||
detail: state.list,
|
||||
bubbles: true,
|
||||
})
|
||||
@@ -100,11 +100,11 @@ export function TodoCustomList(el) {
|
||||
});
|
||||
});
|
||||
|
||||
el.addEventListener('addItem', (e) => {
|
||||
el.addEventListener('addTodoItem', (e) => {
|
||||
e.detail.listId = state.list.id;
|
||||
});
|
||||
|
||||
el.addEventListener('moveItem', (e) => {
|
||||
el.addEventListener('moveTodoItem', (e) => {
|
||||
e.detail.listId = state.list.id;
|
||||
e.detail.index = e.detail.index ?? 0;
|
||||
});
|
||||
@@ -113,7 +113,7 @@ export function TodoCustomList(el) {
|
||||
|
||||
function save() {
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('saveList', {
|
||||
new CustomEvent('saveTodoList', {
|
||||
detail: { list: state.list, title: inputEl.value.trim() },
|
||||
bubbles: true,
|
||||
})
|
||||
|
@@ -17,11 +17,11 @@ export function TodoDay(el) {
|
||||
|
||||
TodoList(el.querySelector('.todo-list'));
|
||||
|
||||
el.addEventListener('addItem', (e) => {
|
||||
el.addEventListener('addTodoItem', (e) => {
|
||||
e.detail.listId = state.dateId;
|
||||
});
|
||||
|
||||
el.addEventListener('moveItem', (e) => {
|
||||
el.addEventListener('moveTodoItem', (e) => {
|
||||
e.detail.listId = state.dateId;
|
||||
e.detail.index = e.detail.index ?? 0;
|
||||
});
|
||||
|
@@ -31,13 +31,13 @@ export function TodoFrameCustom(el) {
|
||||
|
||||
el.querySelector('.back').addEventListener('click', () => {
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('customSeek', { detail: -1, bubbles: true })
|
||||
new CustomEvent('seekCustomTodoLists', { detail: -1, bubbles: true })
|
||||
);
|
||||
});
|
||||
|
||||
el.querySelector('.forward').addEventListener('click', () => {
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('customSeek', { detail: 1, bubbles: true })
|
||||
new CustomEvent('seekCustomTodoLists', { detail: 1, bubbles: true })
|
||||
);
|
||||
});
|
||||
|
||||
@@ -50,7 +50,7 @@ export function TodoFrameCustom(el) {
|
||||
if (!e.detail.data.list) return;
|
||||
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('moveList', {
|
||||
new CustomEvent('moveTodoList', {
|
||||
detail: {
|
||||
list: e.detail.data.list,
|
||||
index: e.detail.index,
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { AppDatePicker } from './AppDatePicker.js';
|
||||
import { AppIcon } from './AppIcon.js';
|
||||
import { TodoDay } from './TodoDay.js';
|
||||
import { formatDateId } from './util.js';
|
||||
@@ -11,39 +12,78 @@ export function TodoFrameDays(el) {
|
||||
|
||||
el.innerHTML = `
|
||||
<nav class="leftcontrols">
|
||||
<p><button class="app-button -circle -xl backward"><i class="app-icon" data-id="chevron-left-24"></i></button></p>
|
||||
<p><button class="app-button fastbackward"><i class="app-icon -double" data-id="chevron-left-16"></i></i></button></p>
|
||||
<p><button class="app-button home"><i class="app-icon" data-id="home-16"></i></button></p>
|
||||
<p>
|
||||
<button class="app-button -circle -xl backward">
|
||||
<i class="app-icon" data-id="chevron-left-24"></i>
|
||||
</button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="app-button fastbackward">
|
||||
<i class="app-icon -double" data-id="chevron-left-16"></i>
|
||||
</button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="app-button home">
|
||||
<i class="app-icon" data-id="home-16"></i>
|
||||
</button>
|
||||
</p>
|
||||
</nav>
|
||||
<div class="container"></div>
|
||||
<nav class="rightcontrols">
|
||||
<p><button class="app-button -circle -xl forward"><i class="app-icon" data-id="chevron-right-24"></i></button></p>
|
||||
<p><button class="app-button fastforward"><i class="app-icon -double" data-id="chevron-right-16"></i></button></p>
|
||||
<p>
|
||||
<button class="app-button -circle -xl forward">
|
||||
<i class="app-icon" data-id="chevron-right-24"></i>
|
||||
</button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="app-button fastforward">
|
||||
<i class="app-icon -double" data-id="chevron-right-16"></i>
|
||||
</button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="app-button pickdate">
|
||||
<i class="app-icon" data-id="calendar-16"></i>
|
||||
</button>
|
||||
</p>
|
||||
<div class="app-dropdown app-date-picker datepicker"></div>
|
||||
</nav>
|
||||
`;
|
||||
|
||||
setTimeout(() => el.classList.add('-animated'), 200);
|
||||
|
||||
el.querySelectorAll('.app-icon').forEach(AppIcon);
|
||||
el.querySelectorAll('.app-date-picker').forEach(AppDatePicker);
|
||||
|
||||
el.querySelector('.backward').addEventListener('click', () =>
|
||||
el.dispatchEvent(new CustomEvent('seek', { detail: -1, bubbles: true }))
|
||||
el.dispatchEvent(new CustomEvent('seekDays', { detail: -1, bubbles: true }))
|
||||
);
|
||||
|
||||
el.querySelector('.forward').addEventListener('click', () =>
|
||||
el.dispatchEvent(new CustomEvent('seek', { detail: 1, bubbles: true }))
|
||||
el.dispatchEvent(new CustomEvent('seekDays', { detail: 1, bubbles: true }))
|
||||
);
|
||||
|
||||
el.querySelector('.fastbackward').addEventListener('click', () =>
|
||||
el.dispatchEvent(new CustomEvent('seek', { detail: -5, bubbles: true }))
|
||||
el.dispatchEvent(new CustomEvent('seekDays', { detail: -5, bubbles: true }))
|
||||
);
|
||||
|
||||
el.querySelector('.fastforward').addEventListener('click', () =>
|
||||
el.dispatchEvent(new CustomEvent('seek', { detail: 5, bubbles: true }))
|
||||
el.dispatchEvent(new CustomEvent('seekDays', { detail: 5, bubbles: true }))
|
||||
);
|
||||
|
||||
el.querySelector('.home').addEventListener('click', () =>
|
||||
el.dispatchEvent(new CustomEvent('seekHome', { bubbles: true }))
|
||||
el.dispatchEvent(new CustomEvent('seekToToday', { bubbles: true }))
|
||||
);
|
||||
|
||||
el.querySelector('.pickdate').addEventListener('click', () =>
|
||||
el
|
||||
.querySelector('.datepicker')
|
||||
.dispatchEvent(new CustomEvent('toggleDatePicker'))
|
||||
);
|
||||
|
||||
el.querySelector('.datepicker').addEventListener('pickDate', (e) =>
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('seekToDate', { detail: e.detail, bubbles: true })
|
||||
)
|
||||
);
|
||||
|
||||
el.addEventListener('todoData', (e) => update(e.detail));
|
||||
|
@@ -44,7 +44,7 @@ export function TodoItem(el) {
|
||||
if (state.editing) save();
|
||||
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('checkItem', {
|
||||
new CustomEvent('checkTodoItem', {
|
||||
detail: {
|
||||
item: state.item,
|
||||
done: !state.item.done,
|
||||
@@ -102,7 +102,7 @@ export function TodoItem(el) {
|
||||
// event handler?
|
||||
requestAnimationFrame(() => {
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('deleteItem', {
|
||||
new CustomEvent('deleteTodoItem', {
|
||||
detail: state.item,
|
||||
bubbles: true,
|
||||
})
|
||||
@@ -113,7 +113,7 @@ export function TodoItem(el) {
|
||||
}
|
||||
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('saveItem', {
|
||||
new CustomEvent('saveTodoItem', {
|
||||
detail: {
|
||||
item: state.item,
|
||||
label,
|
||||
|
@@ -48,7 +48,7 @@ export function TodoItemInput(el) {
|
||||
inputEl.value = '';
|
||||
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('addItem', {
|
||||
new CustomEvent('addTodoItem', {
|
||||
detail: { label },
|
||||
bubbles: true,
|
||||
})
|
||||
|
@@ -17,7 +17,7 @@ export function TodoList(el) {
|
||||
|
||||
el.addEventListener('sortableDrop', (e) =>
|
||||
el.dispatchEvent(
|
||||
new CustomEvent('moveItem', {
|
||||
new CustomEvent('moveTodoItem', {
|
||||
detail: {
|
||||
item: e.detail.data.item,
|
||||
index: e.detail.index,
|
||||
|
@@ -10,9 +10,9 @@ export function TodoStore(el) {
|
||||
|
||||
let storeTimeout;
|
||||
|
||||
el.addEventListener('loadStore', load);
|
||||
el.addEventListener('loadTodoStore', load);
|
||||
|
||||
el.addEventListener('addItem', (e) => {
|
||||
el.addEventListener('addTodoItem', (e) => {
|
||||
let index = 0;
|
||||
|
||||
for (const item of state.items) {
|
||||
@@ -32,21 +32,21 @@ export function TodoStore(el) {
|
||||
dispatch({ items: state.items });
|
||||
});
|
||||
|
||||
el.addEventListener('checkItem', (e) => {
|
||||
el.addEventListener('checkTodoItem', (e) => {
|
||||
if (e.detail.item.done === e.detail.done) return;
|
||||
|
||||
e.detail.item.done = e.detail.done;
|
||||
dispatch({ items: state.items });
|
||||
});
|
||||
|
||||
el.addEventListener('saveItem', (e) => {
|
||||
el.addEventListener('saveTodoItem', (e) => {
|
||||
if (e.detail.item.label === e.detail.label) return;
|
||||
|
||||
e.detail.item.label = e.detail.label;
|
||||
dispatch({ items: state.items });
|
||||
});
|
||||
|
||||
el.addEventListener('moveItem', (e) => {
|
||||
el.addEventListener('moveTodoItem', (e) => {
|
||||
const movedItem = state.items.find((item) => item.id === e.detail.item.id);
|
||||
|
||||
const listItems = state.items.filter(
|
||||
@@ -65,11 +65,11 @@ export function TodoStore(el) {
|
||||
dispatch({ items: state.items });
|
||||
});
|
||||
|
||||
el.addEventListener('deleteItem', (e) => {
|
||||
el.addEventListener('deleteTodoItem', (e) => {
|
||||
dispatch({ items: state.items.filter((item) => item.id !== e.detail.id) });
|
||||
});
|
||||
|
||||
el.addEventListener('addList', (e) => {
|
||||
el.addEventListener('addTodoList', (e) => {
|
||||
let index = 0;
|
||||
|
||||
for (const customList of state.customLists) {
|
||||
@@ -85,7 +85,7 @@ export function TodoStore(el) {
|
||||
dispatch({ customLists: state.customLists });
|
||||
});
|
||||
|
||||
el.addEventListener('saveList', (e) => {
|
||||
el.addEventListener('saveTodoList', (e) => {
|
||||
const list = state.customLists.find((l) => l.id === e.detail.list.id);
|
||||
|
||||
if (list.title === e.detail.title) return;
|
||||
@@ -95,7 +95,7 @@ export function TodoStore(el) {
|
||||
dispatch({ customLists: state.customLists });
|
||||
});
|
||||
|
||||
el.addEventListener('moveList', (e) => {
|
||||
el.addEventListener('moveTodoList', (e) => {
|
||||
const movedListIndex = state.customLists.findIndex(
|
||||
(list) => list.id === e.detail.list.id
|
||||
);
|
||||
@@ -112,7 +112,7 @@ export function TodoStore(el) {
|
||||
dispatch({ customLists: state.customLists });
|
||||
});
|
||||
|
||||
el.addEventListener('deleteList', (e) => {
|
||||
el.addEventListener('deleteTodoList', (e) => {
|
||||
dispatch({
|
||||
customLists: state.customLists.filter(
|
||||
(customList) => customList.id !== e.detail.id
|
||||
@@ -120,18 +120,22 @@ export function TodoStore(el) {
|
||||
});
|
||||
});
|
||||
|
||||
el.addEventListener('seek', (e) => {
|
||||
el.addEventListener('seekDays', (e) => {
|
||||
const t = new Date(`${state.at} 00:00:00`);
|
||||
t.setDate(t.getDate() + e.detail);
|
||||
|
||||
dispatch({ at: formatDateId(t) });
|
||||
});
|
||||
|
||||
el.addEventListener('seekHome', () =>
|
||||
el.addEventListener('seekToToday', () =>
|
||||
dispatch({ at: formatDateId(new Date()) })
|
||||
);
|
||||
|
||||
el.addEventListener('customSeek', (e) => {
|
||||
el.addEventListener('seekToDate', (e) =>
|
||||
dispatch({ at: formatDateId(e.detail) })
|
||||
);
|
||||
|
||||
el.addEventListener('seekCustomTodoLists', (e) => {
|
||||
dispatch({
|
||||
customAt: Math.max(
|
||||
0,
|
||||
|
@@ -38,6 +38,15 @@
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.app-button.-highlight {
|
||||
background: #111;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.app-button.-highlight:hover {
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.app-button.-xl {
|
||||
font-size: 2em;
|
||||
|
51
public/styles/app-date-picker.css
Normal file
51
public/styles/app-date-picker.css
Normal file
@@ -0,0 +1,51 @@
|
||||
.app-date-picker {
|
||||
width: 260px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: rgba(0, 0, 0, 10%) 0 4px 12px;
|
||||
padding: 8px;
|
||||
transform: translate(110%, 0);
|
||||
transition: all 0.2s ease-in-out;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app-date-picker.-show {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
.app-date-picker > .header {
|
||||
display: flex;
|
||||
font-size: 1em;
|
||||
margin: 0 0 1em 0;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.app-date-picker > .header > .month {
|
||||
flex-grow: 1;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.app-date-picker > .dates {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.app-date-picker > .dates > thead > tr > th {
|
||||
font-weight: normal;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.app-date-picker > .dates > tbody > tr > td {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.app-date-picker > .dates > tbody > tr > td > button {
|
||||
width: 100%;
|
||||
height: 1.9em;
|
||||
}
|
||||
|
||||
@media (min-width: 320px) {
|
||||
.app-date-picker {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
3
public/styles/todo-app.css
Normal file
3
public/styles/todo-app.css
Normal file
@@ -0,0 +1,3 @@
|
||||
.todo-app {
|
||||
overflow: hidden;
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
.todo-frame {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
@@ -31,6 +30,11 @@
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
.todo-frame > .rightcontrols > .datepicker {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.todo-frame > .container {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
|
Reference in New Issue
Block a user