mirror of
https://github.com/morris/vanilla-todo.git
synced 2025-08-18 11:51:20 +02:00
update deps
This commit is contained in:
16
README.md
16
README.md
@@ -247,7 +247,7 @@ export function HelloWorld(el) {
|
|||||||
|
|
||||||
// attach event listeners
|
// attach event listeners
|
||||||
el.addEventListener('modifyCounter', (e) =>
|
el.addEventListener('modifyCounter', (e) =>
|
||||||
update({ counter: state.counter + e.detail })
|
update({ counter: state.counter + e.detail }),
|
||||||
);
|
);
|
||||||
|
|
||||||
// initial update
|
// initial update
|
||||||
@@ -267,7 +267,7 @@ export function HelloWorld(el) {
|
|||||||
el.querySelector('.my-counter').dispatchEvent(
|
el.querySelector('.my-counter').dispatchEvent(
|
||||||
new CustomEvent('updateMyCounter', {
|
new CustomEvent('updateMyCounter', {
|
||||||
detail: { value: state.counter },
|
detail: { value: state.counter },
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,7 +297,7 @@ export function MyCounter(el) {
|
|||||||
new CustomEvent('modifyCounter', {
|
new CustomEvent('modifyCounter', {
|
||||||
detail: 1,
|
detail: 1,
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -308,7 +308,7 @@ export function MyCounter(el) {
|
|||||||
new CustomEvent('modifyCounter', {
|
new CustomEvent('modifyCounter', {
|
||||||
detail: -1,
|
detail: -1,
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -434,7 +434,7 @@ export function TodoList(el) {
|
|||||||
const childrenByKey = new Map();
|
const childrenByKey = new Map();
|
||||||
|
|
||||||
obsolete.forEach((child) =>
|
obsolete.forEach((child) =>
|
||||||
childrenByKey.set(child.getAttribute('data-key'), child)
|
childrenByKey.set(child.getAttribute('data-key'), child),
|
||||||
);
|
);
|
||||||
|
|
||||||
// build new list of child elements from data
|
// build new list of child elements from data
|
||||||
@@ -459,7 +459,7 @@ export function TodoList(el) {
|
|||||||
|
|
||||||
// update child
|
// update child
|
||||||
child.dispatchEvent(
|
child.dispatchEvent(
|
||||||
new CustomEvent('updateTodoItem', { detail: { item: item } })
|
new CustomEvent('updateTodoItem', { detail: { item: item } }),
|
||||||
);
|
);
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
@@ -823,6 +823,10 @@ Thanks!
|
|||||||
|
|
||||||
## 9. Changelog
|
## 9. Changelog
|
||||||
|
|
||||||
|
### 11/2023
|
||||||
|
|
||||||
|
- Update dependencies
|
||||||
|
|
||||||
### 05/2023
|
### 05/2023
|
||||||
|
|
||||||
- Add basic testing
|
- Add basic testing
|
||||||
|
4
es5/.prettierrc.json
Normal file
4
es5/.prettierrc.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "es5"
|
||||||
|
}
|
10
es5/.stylelintrc.json
Normal file
10
es5/.stylelintrc.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"extends": ["stylelint-config-standard", "stylelint-rscss/config"],
|
||||||
|
"rules": {
|
||||||
|
"property-no-vendor-prefix": null,
|
||||||
|
"selector-class-pattern": "[a-z\\-][a-z0-9\\-]+",
|
||||||
|
"media-feature-range-notation": "prefix",
|
||||||
|
"color-function-notation": "legacy",
|
||||||
|
"declaration-block-no-redundant-longhand-properties": null
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
@@ -12,7 +12,7 @@ VT.TodoApp = function (el) {
|
|||||||
el.innerHTML = [
|
el.innerHTML = [
|
||||||
'<header class="app-header">',
|
'<header class="app-header">',
|
||||||
' <h1 class="title">VANILLA TODO</h1>',
|
' <h1 class="title">VANILLA TODO</h1>',
|
||||||
' <p class="app-fps"></p>',
|
' <p class="app-fps fps"></p>',
|
||||||
'</header>',
|
'</header>',
|
||||||
'<div class="todo-frame -days"></div>',
|
'<div class="todo-frame -days"></div>',
|
||||||
'<div class="app-collapsible">',
|
'<div class="app-collapsible">',
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
background: #eee;
|
background: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-collapsible > .bar > .app-button:active {
|
.app-collapsible > .bar > .toggle:active {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* stylelint-disable-next-line rscss/no-descendant-combinator */
|
||||||
.app-footer a {
|
.app-footer a {
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header > .app-fps {
|
.app-header > .fps {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
width: 1em;
|
width: 1em;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
fill: currentColor;
|
fill: currentcolor;
|
||||||
transition: transform 0.1s ease-out;
|
transition: transform 0.1s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
.todo-custom-list {
|
.todo-custom-list {
|
||||||
padding: 0 0.5em;
|
padding: 0 0.5em;
|
||||||
transition: transform 0.2s ease-out, opacity 0.2s ease-out,
|
transition:
|
||||||
|
transform 0.2s ease-out,
|
||||||
|
opacity 0.2s ease-out,
|
||||||
box-shadow 0.2s ease-out;
|
box-shadow 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10,7 +12,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.todo-custom-list > .header > .title {
|
.todo-custom-list > .header > .title {
|
||||||
margin: 0 0 10px 0;
|
margin: 0 0 10px;
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -18,7 +20,7 @@
|
|||||||
|
|
||||||
.todo-custom-list > .header > .form {
|
.todo-custom-list > .header > .form {
|
||||||
display: none;
|
display: none;
|
||||||
margin: 0 0 10px 0;
|
margin: 0 0 10px;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
}
|
}
|
||||||
@@ -52,8 +54,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.todo-custom-list.-dragging {
|
.todo-custom-list.-dragging {
|
||||||
box-shadow: 10px 0 12px -14px rgba(0, 0, 0, 0.3),
|
box-shadow:
|
||||||
-10px 0 12px -14px rgba(0, 0, 0, 0.3);
|
10px 0 12px -14px rgba(0, 0, 0, 30%),
|
||||||
|
-10px 0 12px -14px rgba(0, 0, 0, 30%);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
@@ -9,14 +9,14 @@
|
|||||||
|
|
||||||
.todo-day > .header > .dayofweek {
|
.todo-day > .header > .dayofweek {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin: 0 0 0.25em 0;
|
margin: 0 0 0.25em;
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo-day > .header > .date {
|
.todo-day > .header > .date {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin: 0.25em 0 0 0;
|
margin: 0.25em 0 0;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
.todo-frame > .leftcontrols > p,
|
.todo-frame > .leftcontrols > p,
|
||||||
.todo-frame > .rightcontrols > p {
|
.todo-frame > .rightcontrols > p {
|
||||||
margin: 0 0 0.5em 0;
|
margin: 0 0 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo-frame > .container {
|
.todo-frame > .container {
|
||||||
@@ -45,7 +45,9 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
transition: transform 0.2s ease-out, opacity 0.2s ease-out;
|
transition:
|
||||||
|
transform 0.2s ease-out,
|
||||||
|
opacity 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo-frame.-animated {
|
.todo-frame.-animated {
|
||||||
|
@@ -5,7 +5,9 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0.25em 0;
|
padding: 0.25em 0;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
transition: transform 0.2s ease-out, opacity 0.2s ease-out;
|
transition:
|
||||||
|
transform 0.2s ease-out,
|
||||||
|
opacity 0.2s ease-out;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
-webkit-touch-callout: none;
|
-webkit-touch-callout: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
@@ -48,7 +50,7 @@
|
|||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
padding: 0 0 0.25em 0;
|
padding: 0 0 0.25em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
|
3454
package-lock.json
generated
3454
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
41
package.json
41
package.json
@@ -1,7 +1,26 @@
|
|||||||
{
|
{
|
||||||
"name": "vanilla-todo",
|
"name": "vanilla-todo",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "A TeuxDeux clone built with vanilla web technology only",
|
"description": "A TeuxDeux clone in plain HTML, CSS and JavaScript (no build steps)",
|
||||||
|
"keywords": [
|
||||||
|
"vanilla",
|
||||||
|
"html",
|
||||||
|
"css",
|
||||||
|
"javascript"
|
||||||
|
],
|
||||||
|
"author": "Morris Brodersen <mb@morrisbrodersen.de>",
|
||||||
|
"license": "ISC",
|
||||||
|
"homepage": "https://github.com/morris/vanilla-todo#readme",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/morris/vanilla-todo.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/morris/vanilla-todo/issues"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"format-check": "prettier --check .",
|
"format-check": "prettier --check .",
|
||||||
@@ -10,30 +29,14 @@
|
|||||||
"serve": "http-server -c-1 public",
|
"serve": "http-server -c-1 public",
|
||||||
"test": "playwright test"
|
"test": "playwright test"
|
||||||
},
|
},
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/morris/vanilla-todo.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"vanilla",
|
|
||||||
"html",
|
|
||||||
"javascript",
|
|
||||||
"css"
|
|
||||||
],
|
|
||||||
"author": "Morris Brodersen <mb@morrisbrodersen.de>",
|
|
||||||
"license": "ISC",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/morris/vanilla-todo/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/morris/vanilla-todo#readme",
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.33.0",
|
"@playwright/test": "^1.33.0",
|
||||||
"eslint": "^8.20.0",
|
"eslint": "^8.20.0",
|
||||||
"eslint-plugin-compat": "^4.0.2",
|
"eslint-plugin-compat": "^4.0.2",
|
||||||
"http-server": "^14.1.1",
|
"http-server": "^14.1.1",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^3.1.0",
|
||||||
"stylelint": "^15.6.1",
|
"stylelint": "^15.6.1",
|
||||||
"stylelint-config-standard": "^33.0.0",
|
"stylelint-config-standard": "^34.0.0",
|
||||||
"stylelint-rscss": "^0.4.0"
|
"stylelint-rscss": "^0.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
@@ -6,7 +6,7 @@ export function AppCollapsible(el) {
|
|||||||
el.addEventListener('collapse', (e) => update({ show: !e.detail }));
|
el.addEventListener('collapse', (e) => update({ show: !e.detail }));
|
||||||
|
|
||||||
el.querySelector('.bar > .toggle').addEventListener('click', () =>
|
el.querySelector('.bar > .toggle').addEventListener('click', () =>
|
||||||
update({ show: !state.show })
|
update({ show: !state.show }),
|
||||||
);
|
);
|
||||||
|
|
||||||
update();
|
update();
|
||||||
@@ -16,7 +16,7 @@ export function AppCollapsible(el) {
|
|||||||
|
|
||||||
el.querySelector('.bar > .toggle > .app-icon').classList.toggle(
|
el.querySelector('.bar > .toggle > .app-icon').classList.toggle(
|
||||||
'-r180',
|
'-r180',
|
||||||
state.show
|
state.show,
|
||||||
);
|
);
|
||||||
|
|
||||||
el.querySelectorAll('.body').forEach((el) => {
|
el.querySelectorAll('.body').forEach((el) => {
|
||||||
|
@@ -60,7 +60,7 @@ export function AppDatePicker(el) {
|
|||||||
el.querySelectorAll('.app-icon').forEach(AppIcon);
|
el.querySelectorAll('.app-icon').forEach(AppIcon);
|
||||||
|
|
||||||
el.addEventListener('toggleDatePicker', (e) =>
|
el.addEventListener('toggleDatePicker', (e) =>
|
||||||
update({ show: e.detail ?? !state.show })
|
update({ show: e.detail ?? !state.show }),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.addEventListener('setMonth', (e) => update(e.detail));
|
el.addEventListener('setMonth', (e) => update(e.detail));
|
||||||
@@ -78,10 +78,10 @@ export function AppDatePicker(el) {
|
|||||||
detail: new Date(
|
detail: new Date(
|
||||||
e.target.dataset.year,
|
e.target.dataset.year,
|
||||||
e.target.dataset.month - 1,
|
e.target.dataset.month - 1,
|
||||||
e.target.dataset.day
|
e.target.dataset.day,
|
||||||
),
|
),
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ export function AppDatePicker(el) {
|
|||||||
: {
|
: {
|
||||||
year: state.year - 1,
|
year: state.year - 1,
|
||||||
month: 12,
|
month: 12,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ export function AppDatePicker(el) {
|
|||||||
: {
|
: {
|
||||||
year: state.year + 1,
|
year: state.year + 1,
|
||||||
month: 1,
|
month: 1,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ export function AppDatePicker(el) {
|
|||||||
const first = new Date(state.year, state.month - 1, 1);
|
const first = new Date(state.year, state.month - 1, 1);
|
||||||
|
|
||||||
el.querySelector('.month').innerHTML = `${formatMonth(
|
el.querySelector('.month').innerHTML = `${formatMonth(
|
||||||
first
|
first,
|
||||||
)} ${first.getFullYear()}`;
|
)} ${first.getFullYear()}`;
|
||||||
|
|
||||||
let current = new Date(first);
|
let current = new Date(first);
|
||||||
@@ -147,7 +147,7 @@ export function AppDatePicker(el) {
|
|||||||
'-highlight',
|
'-highlight',
|
||||||
current.getFullYear() === now.getFullYear() &&
|
current.getFullYear() === now.getFullYear() &&
|
||||||
current.getMonth() === now.getMonth() &&
|
current.getMonth() === now.getMonth() &&
|
||||||
current.getDate() === now.getDate()
|
current.getDate() === now.getDate(),
|
||||||
);
|
);
|
||||||
|
|
||||||
current.setDate(current.getDate() + 1);
|
current.setDate(current.getDate() + 1);
|
||||||
|
@@ -26,7 +26,7 @@ export function AppDraggable(el, options) {
|
|||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
true
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
function start(e) {
|
function start(e) {
|
||||||
@@ -122,7 +122,7 @@ export function AppDraggable(el, options) {
|
|||||||
new CustomEvent('draggableStart', {
|
new CustomEvent('draggableStart', {
|
||||||
detail: buildDetail(),
|
detail: buildDetail(),
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ export function AppDraggable(el, options) {
|
|||||||
new CustomEvent('draggableDrag', {
|
new CustomEvent('draggableDrag', {
|
||||||
detail: buildDetail(),
|
detail: buildDetail(),
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ export function AppDraggable(el, options) {
|
|||||||
new CustomEvent('draggableLeave', {
|
new CustomEvent('draggableLeave', {
|
||||||
detail: buildDetail(),
|
detail: buildDetail(),
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ export function AppDraggable(el, options) {
|
|||||||
new CustomEvent('draggableEnter', {
|
new CustomEvent('draggableEnter', {
|
||||||
detail: buildDetail(),
|
detail: buildDetail(),
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ export function AppDraggable(el, options) {
|
|||||||
new CustomEvent('draggableOver', {
|
new CustomEvent('draggableOver', {
|
||||||
detail: buildDetail(),
|
detail: buildDetail(),
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,14 +192,14 @@ export function AppDraggable(el, options) {
|
|||||||
new CustomEvent('draggableDrop', {
|
new CustomEvent('draggableDrop', {
|
||||||
detail: buildDetail(),
|
detail: buildDetail(),
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
image.dispatchEvent(
|
image.dispatchEvent(
|
||||||
new CustomEvent('draggableCancel', {
|
new CustomEvent('draggableCancel', {
|
||||||
detail: buildDetail(),
|
detail: buildDetail(),
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,7 +297,7 @@ export function AppDraggable(el, options) {
|
|||||||
const distanceSquared = pointDistanceToRectSquared(
|
const distanceSquared = pointDistanceToRectSquared(
|
||||||
clientX,
|
clientX,
|
||||||
clientY,
|
clientY,
|
||||||
rect
|
rect,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (distanceSquared > dropRangeSquared) return;
|
if (distanceSquared > dropRangeSquared) return;
|
||||||
|
@@ -25,7 +25,7 @@ export function AppFps(el) {
|
|||||||
const fps = (sampleSize / sum) * 1000;
|
const fps = (sampleSize / sum) * 1000;
|
||||||
|
|
||||||
el.innerText = `${fps.toFixed(0)} fps (${min.toFixed(0)} ms - ${max.toFixed(
|
el.innerText = `${fps.toFixed(0)} fps (${min.toFixed(0)} ms - ${max.toFixed(
|
||||||
0
|
0,
|
||||||
)} ms)`;
|
)} ms)`;
|
||||||
|
|
||||||
times = [];
|
times = [];
|
||||||
|
@@ -5,11 +5,11 @@ export function AppSortable(el, options) {
|
|||||||
let currentIndex = -1;
|
let currentIndex = -1;
|
||||||
|
|
||||||
el.addEventListener('draggableStart', (e) =>
|
el.addEventListener('draggableStart', (e) =>
|
||||||
e.detail.image.addEventListener('draggableCancel', cleanUp)
|
e.detail.image.addEventListener('draggableCancel', cleanUp),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.addEventListener('draggableOver', (e) =>
|
el.addEventListener('draggableOver', (e) =>
|
||||||
maybeDispatchUpdate(calculateIndex(e.detail.image), e)
|
maybeDispatchUpdate(calculateIndex(e.detail.image), e),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.addEventListener('draggableLeave', (e) => maybeDispatchUpdate(-1, e));
|
el.addEventListener('draggableLeave', (e) => maybeDispatchUpdate(-1, e));
|
||||||
@@ -19,8 +19,8 @@ export function AppSortable(el, options) {
|
|||||||
new CustomEvent('sortableDrop', {
|
new CustomEvent('sortableDrop', {
|
||||||
detail: buildDetail(e),
|
detail: buildDetail(e),
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.addEventListener('sortableUpdate', (e) => {
|
el.addEventListener('sortableUpdate', (e) => {
|
||||||
@@ -47,7 +47,7 @@ export function AppSortable(el, options) {
|
|||||||
new CustomEvent('sortableUpdate', {
|
new CustomEvent('sortableUpdate', {
|
||||||
detail: buildDetail(originalEvent),
|
detail: buildDetail(originalEvent),
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -109,11 +109,11 @@ export function TodoApp(el) {
|
|||||||
Object.assign(state, next);
|
Object.assign(state, next);
|
||||||
|
|
||||||
el.querySelectorAll('.todo-frame').forEach((el) =>
|
el.querySelectorAll('.todo-frame').forEach((el) =>
|
||||||
el.dispatchEvent(new CustomEvent('todoData', { detail: state }))
|
el.dispatchEvent(new CustomEvent('todoData', { detail: state })),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.querySelectorAll('.app-collapsible').forEach((el) =>
|
el.querySelectorAll('.app-collapsible').forEach((el) =>
|
||||||
el.dispatchEvent(new CustomEvent('collapse'))
|
el.dispatchEvent(new CustomEvent('collapse')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -68,7 +68,7 @@ export function TodoCustomList(el) {
|
|||||||
if (state.list.items.length > 0) {
|
if (state.list.items.length > 0) {
|
||||||
if (
|
if (
|
||||||
!confirm(
|
!confirm(
|
||||||
'Deleting this list will delete its items as well. Are you sure?'
|
'Deleting this list will delete its items as well. Are you sure?',
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
@@ -79,7 +79,7 @@ export function TodoCustomList(el) {
|
|||||||
new CustomEvent('deleteTodoList', {
|
new CustomEvent('deleteTodoList', {
|
||||||
detail: state.list,
|
detail: state.list,
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ export function TodoCustomList(el) {
|
|||||||
new CustomEvent('saveTodoList', {
|
new CustomEvent('saveTodoList', {
|
||||||
detail: { list: state.list, title: inputEl.value.trim() },
|
detail: { list: state.list, title: inputEl.value.trim() },
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
update({ editing: false });
|
update({ editing: false });
|
||||||
}
|
}
|
||||||
@@ -132,12 +132,11 @@ export function TodoCustomList(el) {
|
|||||||
titleEl.innerText = state.list.title || '...';
|
titleEl.innerText = state.list.title || '...';
|
||||||
|
|
||||||
el.querySelector('.todo-list').dispatchEvent(
|
el.querySelector('.todo-list').dispatchEvent(
|
||||||
new CustomEvent('todoItems', { detail: state.list.items })
|
new CustomEvent('todoItems', { detail: state.list.items }),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.querySelector(
|
el.querySelector('.todo-list > .todo-item-input').dataset.key =
|
||||||
'.todo-list > .todo-item-input'
|
`todo-item-input${state.list.id}`;
|
||||||
).dataset.key = `todo-item-input${state.list.id}`;
|
|
||||||
|
|
||||||
el.classList.toggle('-editing', state.editing);
|
el.classList.toggle('-editing', state.editing);
|
||||||
|
|
||||||
|
@@ -43,7 +43,7 @@ export function TodoDay(el) {
|
|||||||
el.querySelector('.header > .dayofweek').innerText = formatDayOfWeek(date);
|
el.querySelector('.header > .dayofweek').innerText = formatDayOfWeek(date);
|
||||||
el.querySelector('.header > .date').innerText = formatDate(date);
|
el.querySelector('.header > .date').innerText = formatDate(date);
|
||||||
el.querySelector('.todo-list').dispatchEvent(
|
el.querySelector('.todo-list').dispatchEvent(
|
||||||
new CustomEvent('todoItems', { detail: state.items })
|
new CustomEvent('todoItems', { detail: state.items }),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,19 +29,19 @@ export function TodoFrameCustom(el) {
|
|||||||
|
|
||||||
el.querySelector('.back').addEventListener('click', () =>
|
el.querySelector('.back').addEventListener('click', () =>
|
||||||
el.dispatchEvent(
|
el.dispatchEvent(
|
||||||
new CustomEvent('seekCustomTodoLists', { detail: -1, bubbles: true })
|
new CustomEvent('seekCustomTodoLists', { detail: -1, bubbles: true }),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.querySelector('.forward').addEventListener('click', () =>
|
el.querySelector('.forward').addEventListener('click', () =>
|
||||||
el.dispatchEvent(
|
el.dispatchEvent(
|
||||||
new CustomEvent('seekCustomTodoLists', { detail: 1, bubbles: true })
|
new CustomEvent('seekCustomTodoLists', { detail: 1, bubbles: true }),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.querySelector('.add').addEventListener('click', () => {
|
el.querySelector('.add').addEventListener('click', () => {
|
||||||
el.dispatchEvent(
|
el.dispatchEvent(
|
||||||
new CustomEvent('addTodoList', { detail: {}, bubbles: true })
|
new CustomEvent('addTodoList', { detail: {}, bubbles: true }),
|
||||||
);
|
);
|
||||||
// TODO seek if not at end
|
// TODO seek if not at end
|
||||||
});
|
});
|
||||||
@@ -56,7 +56,7 @@ export function TodoFrameCustom(el) {
|
|||||||
index: e.detail.index,
|
index: e.detail.index,
|
||||||
},
|
},
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -55,35 +55,39 @@ export function TodoFrameDays(el) {
|
|||||||
el.querySelectorAll('.app-date-picker').forEach(AppDatePicker);
|
el.querySelectorAll('.app-date-picker').forEach(AppDatePicker);
|
||||||
|
|
||||||
el.querySelector('.backward').addEventListener('click', () =>
|
el.querySelector('.backward').addEventListener('click', () =>
|
||||||
el.dispatchEvent(new CustomEvent('seekDays', { detail: -1, bubbles: true }))
|
el.dispatchEvent(
|
||||||
|
new CustomEvent('seekDays', { detail: -1, bubbles: true }),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.querySelector('.forward').addEventListener('click', () =>
|
el.querySelector('.forward').addEventListener('click', () =>
|
||||||
el.dispatchEvent(new CustomEvent('seekDays', { detail: 1, bubbles: true }))
|
el.dispatchEvent(new CustomEvent('seekDays', { detail: 1, bubbles: true })),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.querySelector('.fastbackward').addEventListener('click', () =>
|
el.querySelector('.fastbackward').addEventListener('click', () =>
|
||||||
el.dispatchEvent(new CustomEvent('seekDays', { detail: -5, bubbles: true }))
|
el.dispatchEvent(
|
||||||
|
new CustomEvent('seekDays', { detail: -5, bubbles: true }),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.querySelector('.fastforward').addEventListener('click', () =>
|
el.querySelector('.fastforward').addEventListener('click', () =>
|
||||||
el.dispatchEvent(new CustomEvent('seekDays', { detail: 5, bubbles: true }))
|
el.dispatchEvent(new CustomEvent('seekDays', { detail: 5, bubbles: true })),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.querySelector('.home').addEventListener('click', () =>
|
el.querySelector('.home').addEventListener('click', () =>
|
||||||
el.dispatchEvent(new CustomEvent('seekToToday', { bubbles: true }))
|
el.dispatchEvent(new CustomEvent('seekToToday', { bubbles: true })),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.querySelector('.pickdate').addEventListener('click', () =>
|
el.querySelector('.pickdate').addEventListener('click', () =>
|
||||||
el
|
el
|
||||||
.querySelector('.datepicker')
|
.querySelector('.datepicker')
|
||||||
.dispatchEvent(new CustomEvent('toggleDatePicker'))
|
.dispatchEvent(new CustomEvent('toggleDatePicker')),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.querySelector('.datepicker').addEventListener('pickDate', (e) =>
|
el.querySelector('.datepicker').addEventListener('pickDate', (e) =>
|
||||||
el.dispatchEvent(
|
el.dispatchEvent(
|
||||||
new CustomEvent('seekToDate', { detail: e.detail, bubbles: true })
|
new CustomEvent('seekToDate', { detail: e.detail, bubbles: true }),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.addEventListener('todoData', (e) => update(e.detail));
|
el.addEventListener('todoData', (e) => update(e.detail));
|
||||||
|
@@ -50,7 +50,7 @@ export function TodoItem(el) {
|
|||||||
done: !state.item.done,
|
done: !state.item.done,
|
||||||
},
|
},
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ export function TodoItem(el) {
|
|||||||
new CustomEvent('deleteTodoItem', {
|
new CustomEvent('deleteTodoItem', {
|
||||||
detail: state.item,
|
detail: state.item,
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ export function TodoItem(el) {
|
|||||||
label,
|
label,
|
||||||
},
|
},
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
update({ editing: false });
|
update({ editing: false });
|
||||||
|
@@ -51,7 +51,7 @@ export function TodoItemInput(el) {
|
|||||||
new CustomEvent('addTodoItem', {
|
new CustomEvent('addTodoItem', {
|
||||||
detail: { label },
|
detail: { label },
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,8 +23,8 @@ export function TodoList(el) {
|
|||||||
index: e.detail.index,
|
index: e.detail.index,
|
||||||
},
|
},
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
})
|
}),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.addEventListener('todoItems', (e) => update({ items: e.detail }));
|
el.addEventListener('todoItems', (e) => update({ items: e.detail }));
|
||||||
|
@@ -50,7 +50,7 @@ export function TodoStore(el) {
|
|||||||
const movedItem = state.items.find((item) => item.id === e.detail.item.id);
|
const movedItem = state.items.find((item) => item.id === e.detail.item.id);
|
||||||
|
|
||||||
const listItems = state.items.filter(
|
const listItems = state.items.filter(
|
||||||
(item) => item.listId === e.detail.listId && item !== movedItem
|
(item) => item.listId === e.detail.listId && item !== movedItem,
|
||||||
);
|
);
|
||||||
|
|
||||||
listItems.sort((a, b) => a.index - b.index);
|
listItems.sort((a, b) => a.index - b.index);
|
||||||
@@ -66,7 +66,7 @@ export function TodoStore(el) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
el.addEventListener('deleteTodoItem', (e) =>
|
el.addEventListener('deleteTodoItem', (e) =>
|
||||||
dispatch({ items: state.items.filter((item) => item.id !== e.detail.id) })
|
dispatch({ items: state.items.filter((item) => item.id !== e.detail.id) }),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.addEventListener('addTodoList', (e) => {
|
el.addEventListener('addTodoList', (e) => {
|
||||||
@@ -97,7 +97,7 @@ export function TodoStore(el) {
|
|||||||
|
|
||||||
el.addEventListener('moveTodoList', (e) => {
|
el.addEventListener('moveTodoList', (e) => {
|
||||||
const movedListIndex = state.customLists.findIndex(
|
const movedListIndex = state.customLists.findIndex(
|
||||||
(list) => list.id === e.detail.list.id
|
(list) => list.id === e.detail.list.id,
|
||||||
);
|
);
|
||||||
const movedList = state.customLists[movedListIndex];
|
const movedList = state.customLists[movedListIndex];
|
||||||
|
|
||||||
@@ -115,9 +115,9 @@ export function TodoStore(el) {
|
|||||||
el.addEventListener('deleteTodoList', (e) =>
|
el.addEventListener('deleteTodoList', (e) =>
|
||||||
dispatch({
|
dispatch({
|
||||||
customLists: state.customLists.filter(
|
customLists: state.customLists.filter(
|
||||||
(customList) => customList.id !== e.detail.id
|
(customList) => customList.id !== e.detail.id,
|
||||||
),
|
),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.addEventListener('seekDays', (e) => {
|
el.addEventListener('seekDays', (e) => {
|
||||||
@@ -128,20 +128,20 @@ export function TodoStore(el) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
el.addEventListener('seekToToday', () =>
|
el.addEventListener('seekToToday', () =>
|
||||||
dispatch({ at: formatDateId(new Date()) })
|
dispatch({ at: formatDateId(new Date()) }),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.addEventListener('seekToDate', (e) =>
|
el.addEventListener('seekToDate', (e) =>
|
||||||
dispatch({ at: formatDateId(e.detail) })
|
dispatch({ at: formatDateId(e.detail) }),
|
||||||
);
|
);
|
||||||
|
|
||||||
el.addEventListener('seekCustomTodoLists', (e) =>
|
el.addEventListener('seekCustomTodoLists', (e) =>
|
||||||
dispatch({
|
dispatch({
|
||||||
customAt: Math.max(
|
customAt: Math.max(
|
||||||
0,
|
0,
|
||||||
Math.min(state.customLists.length - 1, state.customAt + e.detail)
|
Math.min(state.customLists.length - 1, state.customAt + e.detail),
|
||||||
),
|
),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
function dispatch(next) {
|
function dispatch(next) {
|
||||||
@@ -152,7 +152,7 @@ export function TodoStore(el) {
|
|||||||
new CustomEvent('todoData', {
|
new CustomEvent('todoData', {
|
||||||
detail: state,
|
detail: state,
|
||||||
bubbles: false,
|
bubbles: false,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
.todo-custom-list {
|
.todo-custom-list {
|
||||||
padding: 0 0.5em;
|
padding: 0 0.5em;
|
||||||
transition: transform 0.2s ease-out, opacity 0.2s ease-out,
|
transition:
|
||||||
|
transform 0.2s ease-out,
|
||||||
|
opacity 0.2s ease-out,
|
||||||
box-shadow 0.2s ease-out;
|
box-shadow 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +54,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.todo-custom-list.-dragging {
|
.todo-custom-list.-dragging {
|
||||||
box-shadow: 10px 0 12px -14px rgb(0 0 0 / 30%),
|
box-shadow:
|
||||||
|
10px 0 12px -14px rgb(0 0 0 / 30%),
|
||||||
-10px 0 12px -14px rgb(0 0 0 / 30%);
|
-10px 0 12px -14px rgb(0 0 0 / 30%);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
|
@@ -46,7 +46,9 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
transition: transform 0.2s ease-out, opacity 0.2s ease-out;
|
transition:
|
||||||
|
transform 0.2s ease-out,
|
||||||
|
opacity 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo-frame.-animated {
|
.todo-frame.-animated {
|
||||||
|
@@ -5,7 +5,9 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0.25em 0;
|
padding: 0.25em 0;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
transition: transform 0.2s ease-out, opacity 0.2s ease-out;
|
transition:
|
||||||
|
transform 0.2s ease-out,
|
||||||
|
opacity 0.2s ease-out;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
-webkit-touch-callout: none;
|
-webkit-touch-callout: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
|
@@ -9,7 +9,7 @@ test("Add item to today's todo list (Enter)", async ({ page }) => {
|
|||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
|
|
||||||
await expect(page.locator('.-today .todo-item > .label')).toHaveText(
|
await expect(page.locator('.-today .todo-item > .label')).toHaveText(
|
||||||
'Hello, world!'
|
'Hello, world!',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -22,6 +22,6 @@ test("Add item to today's todo list (click)", async ({ page }) => {
|
|||||||
await page.locator('.-today .todo-item-input > .save').click();
|
await page.locator('.-today .todo-item-input > .save').click();
|
||||||
|
|
||||||
await expect(page.locator('.-today .todo-item > .label')).toHaveText(
|
await expect(page.locator('.-today .todo-item > .label')).toHaveText(
|
||||||
'Hello, world!'
|
'Hello, world!',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@@ -4,6 +4,6 @@ import util from '../../public/scripts/util.js';
|
|||||||
test('formatDate', () => {
|
test('formatDate', () => {
|
||||||
expect(util.formatDate(new Date(0))).toEqual('January 1st 1970');
|
expect(util.formatDate(new Date(0))).toEqual('January 1st 1970');
|
||||||
expect(util.formatDate(new Date('2023-05-13 12:00:00'))).toEqual(
|
expect(util.formatDate(new Date('2023-05-13 12:00:00'))).toEqual(
|
||||||
'May 13th 2023'
|
'May 13th 2023',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user