From c565577b7be36531abfd9e5e7bc0350ad83a72ae Mon Sep 17 00:00:00 2001 From: Christian Toney Date: Thu, 29 Jun 2023 17:15:49 -0400 Subject: [PATCH 1/8] Add a dark theme (#95) * Fix colors * Fix popup background color and shadow * fix label colors * Detect system theme --- public/index.html | 2 +- src/App.tsx | 9 +++++++++ src/components/BacklogTask/BacklogTask.module.css | 8 ++++++++ src/components/Header/Header.module.css | 2 +- src/components/LabelButton/LabelButton.module.css | 6 +++++- src/components/Popup/Popup.module.css | 4 ++++ .../ProjectListButton/ProjectListButton.module.css | 8 ++++++-- src/global.css | 13 ++++++++----- 8 files changed, 42 insertions(+), 10 deletions(-) diff --git a/public/index.html b/public/index.html index 4555c34..160d8a1 100644 --- a/public/index.html +++ b/public/index.html @@ -8,7 +8,7 @@ Planzea - +
diff --git a/src/App.tsx b/src/App.tsx index a49c766..a941f0b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -24,6 +24,15 @@ export default function App() { useEffect(() => { + // Check if the user wants dark theme. + const mediaQueryList = window.matchMedia("(prefers-color-scheme: dark"); + const onSystemThemeChange = (mediaQueryList: MediaQueryList | MediaQueryListEvent) => document.body.classList[mediaQueryList.matches ? "add" : "remove"]("dark"); + onSystemThemeChange(mediaQueryList); + + // Watch for changes to system theme. + mediaQueryList.addEventListener("change", onSystemThemeChange); + + // Set the client. setClient(new CacheClient()); }, []); diff --git a/src/components/BacklogTask/BacklogTask.module.css b/src/components/BacklogTask/BacklogTask.module.css index 2274e1d..86839ca 100644 --- a/src/components/BacklogTask/BacklogTask.module.css +++ b/src/components/BacklogTask/BacklogTask.module.css @@ -39,6 +39,10 @@ cursor: initial; } +:global(.dark) .task:not(.selected):hover { + background-color: rgba(55, 55, 55, 0.14); +} + .task:hover:active { background-color: rgb(220, 220, 220); } @@ -48,6 +52,10 @@ border-color: var(--border); } +:global(.dark) .task.selected { + background-color: rgba(91, 91, 91, 0.14); +} + .task > span { display: flex; align-items: center; diff --git a/src/components/Header/Header.module.css b/src/components/Header/Header.module.css index ec3bf67..648d446 100644 --- a/src/components/Header/Header.module.css +++ b/src/components/Header/Header.module.css @@ -46,7 +46,7 @@ header { #left a { font-size: 17px; font-weight: 400; - color: black; + color: var(--text-important); text-decoration: none; } diff --git a/src/components/LabelButton/LabelButton.module.css b/src/components/LabelButton/LabelButton.module.css index 9f8f420..6f44d7e 100644 --- a/src/components/LabelButton/LabelButton.module.css +++ b/src/components/LabelButton/LabelButton.module.css @@ -2,12 +2,16 @@ display: flex; gap: 5px; align-items: center; - background-color: rgb(253, 253, 253); + background-color: #fdfdfd; border-radius: 5px; padding: 0 5px; box-shadow: var(--box-shadow-default); } +:global(.dark) .label { + background-color: #000000; +} + .colorBubble { background-color: var(--button); border-radius: 100%; diff --git a/src/components/Popup/Popup.module.css b/src/components/Popup/Popup.module.css index e4d183b..badb6be 100644 --- a/src/components/Popup/Popup.module.css +++ b/src/components/Popup/Popup.module.css @@ -55,6 +55,10 @@ pointer-events: all; } +:global(.dark) #popupContainer.open { + background-color: rgba(17, 17, 17, 0.75); +} + #popupContainer.open #popup { transform: scale(1); border-radius: 0; diff --git a/src/components/ProjectListButton/ProjectListButton.module.css b/src/components/ProjectListButton/ProjectListButton.module.css index a03cced..2177cf8 100644 --- a/src/components/ProjectListButton/ProjectListButton.module.css +++ b/src/components/ProjectListButton/ProjectListButton.module.css @@ -18,8 +18,8 @@ cursor: initial; } -.project:hover:active { - background-color: rgb(220, 220, 220); +:global(.dark) .project:not(.selected):hover { + background-color: rgba(55, 55, 55, 0.14); } .project.selected { @@ -27,6 +27,10 @@ border-color: var(--border); } +:global(.dark) .project.selected { + background-color: rgba(91, 91, 91, 0.14); +} + .project > span { display: flex; align-items: center; diff --git a/src/global.css b/src/global.css index 69eca71..ecfd2ea 100644 --- a/src/global.css +++ b/src/global.css @@ -39,22 +39,20 @@ } .dark { - --background: #282828; + --background: #0c0c0c; --background-box: #1c1c1c; --background-header: #1b1c1be8; --background-info: #1f1f1f; --background-input: #171717; --background-input-header: #2e2f2e; --background-popup-box: var(--background-box); - --border: #101010b0; + --border: #282828; --border-default: 1px solid var(--border); --destructive: #a33030; --grid: #242424; --text: #bcbcbc; --text-important: #e3ebe3; - --button: #2d4f24; - --button-disabled: #434343; - --box-shadow-default: rgba(0, 0, 0, 0.35) 0px 5px 15px; + --box-shadow-default: rgba(86, 77, 140, 0.35) 0px 3px 15px; --sidebar-button: #365336; } @@ -67,6 +65,10 @@ a:visited { color: var(--link); } +label { + color: var(--text); +} + html { height: 100vh; } @@ -122,6 +124,7 @@ input { background-color: var(--background-input); font-weight: 100; font-size: 16px; + color: var(--text); } input[type="checkbox"] { From c4ebebe7e41df6184bff9520392302f6b477ea0d Mon Sep 17 00:00:00 2001 From: Christian Toney Date: Sat, 1 Jul 2023 23:17:52 -0400 Subject: [PATCH 2/8] Add the ability to use multiple task lists (#98) * add jsdocs * update * add upgradeParentTask method * delete subtasks * Create task lists * remove toggle * Create tasks * update styles * set up design * update a lot * update typescript * Restore task list adding * Remove tasks from list * remove debug * Delete task lists * Rename task lists * drag task lists * fix padding * Allow list reordering * better reorder * update db version * sort accurately * remove console.log * only grab on primary * Fix memory leak * remove task ID * don't show task lists until ready * update task list positions by button * simplify updateTaskPosition * simplify stopPropagation --- .vscode/settings.json | 3 + package-lock.json | 184 +++++----- package.json | 12 +- src/client/CacheClient.ts | 18 +- src/client/Client.ts | 209 ++++++----- src/client/ClientDatabase.ts | 6 +- src/client/Project.ts | 4 +- src/client/Task.ts | 126 ++++++- src/client/TaskList.ts | 44 +++ src/client/errors/ContentNotFoundError.ts | 12 + src/components/Icon/Icon.tsx | 2 +- src/components/Popup/Popup.tsx | 7 +- .../TaskDeletionPopup/TaskDeletionPopup.tsx | 10 +- .../TaskListSection.module.css | 107 ++++++ .../TaskListSection/TaskListSection.tsx | 164 +++++++++ src/components/TaskPopup/TaskPopup.module.css | 22 +- src/components/TaskPopup/TaskPopup.tsx | 6 +- .../TaskPopupParentTaskSection.tsx | 2 +- .../TaskPopupSubTaskSection.module.css | 45 +-- .../TaskPopupSubTaskSection.tsx | 345 +++++++++++++++--- 20 files changed, 1001 insertions(+), 327 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/client/TaskList.ts create mode 100644 src/client/errors/ContentNotFoundError.ts create mode 100644 src/components/TaskListSection/TaskListSection.module.css create mode 100644 src/components/TaskListSection/TaskListSection.tsx diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d7207a4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules\\typescript\\lib" +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6bbfa6d..b9f2fb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,13 +15,13 @@ "html-react-parser": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.14.0" + "react-router-dom": "^6.14.1" }, "devDependencies": { "@babel/preset-env": "^7.22.5", "@babel/preset-react": "^7.22.5", "@types/jest": "^29.5.2", - "@types/node": "^20.3.2", + "@types/node": "^20.3.3", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", "@types/sanitize-html": "^2.9.0", @@ -34,7 +34,7 @@ "core-js": "^3.31.0", "crypto-browserify": "^3.12.0", "css-loader": "^6.8.1", - "eslint": "^8.43.0", + "eslint": "^8.44.0", "eslint-plugin-react": "^7.32.2", "file-loader": "^6.2.0", "html-loader": "^4.2.0", @@ -43,16 +43,25 @@ "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "style-loader": "^3.3.3", - "ts-loader": "^9.4.3", + "ts-loader": "^9.4.4", "ts-node": "^10.9.1", - "typescript": "^5.1.5", + "typescript": "^5.1.6", "url": "^0.11.1", "util": "^0.12.5", - "webpack": "^5.88.0", + "webpack": "^5.88.1", "webpack-cli": "^5.1.4", "webpack-dev-server": "^4.15.1" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -1886,14 +1895,14 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -1924,9 +1933,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", - "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2109,14 +2118,10 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", - "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.4.tgz", + "integrity": "sha512-KE/SxsDqNs3rrWwFHcRh15ZLVFrI0YoZtgAdIyIq9k5hUNmiWRXXThPomIxHuL20sLdgzbDFyvkUMna14bvtrw==", + "dev": true }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", @@ -2182,9 +2187,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.0.tgz", - "integrity": "sha512-Eu1V3kz3mV0wUpVTiFHuaT8UD1gj/0VnoFHQYX35xlslQUpe8CuYoKFn9d4WZFHm3yDywz6ALZuGdnUPKrNeAw==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.1.tgz", + "integrity": "sha512-bgVQM4ZJ2u2CM8k1ey70o1ePFXsEzYVZoWghh6WjM8p59jQ7HxzbHW4SbnWFG7V9ig9chLawQxDTZ3xzOF8MkQ==", "engines": { "node": ">=14" } @@ -2375,9 +2380,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.3.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.2.tgz", - "integrity": "sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==", + "version": "20.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.3.tgz", + "integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==", "dev": true }, "node_modules/@types/prop-types": { @@ -3224,6 +3229,24 @@ "node": ">=8" } }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.flatmap": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", @@ -3712,9 +3735,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001508", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001508.tgz", - "integrity": "sha512-sdQZOJdmt3GJs1UMNpCCCyeuS2IEGLXnHyAo9yIO5JJDjbjoVRij4M1qep6P6gFpptD1PqIYgzM+gwJbOi92mw==", + "version": "1.0.30001509", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz", + "integrity": "sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA==", "dev": true, "funding": [ { @@ -4526,9 +4549,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.442", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.442.tgz", - "integrity": "sha512-RkrZF//Ya+0aJq2NM3OdisNh5ZodZq1rdXOS96G8DdDgpDKqKE81yTbbQ3F/4CKm1JBPsGu1Lp/akkna2xO06Q==", + "version": "1.4.447", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.447.tgz", + "integrity": "sha512-sxX0LXh+uL41hSJsujAN86PjhrV/6c79XmpY0TvjZStV6VxIgarf8SRkUoUTuYmFcZQTemsoqo8qXOGw5npWfw==", "dev": true }, "node_modules/elliptic": { @@ -4731,15 +4754,15 @@ } }, "node_modules/eslint": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", - "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", + "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.43.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -4751,7 +4774,7 @@ "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "espree": "^9.6.0", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -4771,7 +4794,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -4992,12 +5015,12 @@ } }, "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", + "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" }, @@ -5208,9 +5231,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -7102,13 +7125,15 @@ } }, "node_modules/jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.4.tgz", + "integrity": "sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw==", "dev": true, "dependencies": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" }, "engines": { "node": ">=4.0" @@ -7725,17 +7750,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -8358,11 +8383,11 @@ "integrity": "sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw==" }, "node_modules/react-router": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.0.tgz", - "integrity": "sha512-OD+vkrcGbvlwkspUFDgMzsu1RXwdjNh83YgG/28lBnDzgslhCgxIqoExLlxsfTpIygp7fc+Hd3esloNwzkm2xA==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.1.tgz", + "integrity": "sha512-U4PfgvG55LdvbQjg5Y9QRWyVxIdO1LlpYT7x+tMAxd9/vmiPuJhIwdxZuIQLN/9e3O4KFDHYfR9gzGeYMasW8g==", "dependencies": { - "@remix-run/router": "1.7.0" + "@remix-run/router": "1.7.1" }, "engines": { "node": ">=14" @@ -8372,12 +8397,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.0.tgz", - "integrity": "sha512-YEwlApKwzMMMbGbhh+Q7MsloTldcwMgHxUY/1g0uA62+B1hZo2jsybCWIDCL8zvIDB1FA0pBKY9chHbZHt+2dQ==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.1.tgz", + "integrity": "sha512-ssF6M5UkQjHK70fgukCJyjlda0Dgono2QGwqGvuk7D+EDGHdacEN3Yke2LTMjkrpHuFwBfDFsEjGVXBDmL+bWw==", "dependencies": { - "@remix-run/router": "1.7.0", - "react-router": "6.14.0" + "@remix-run/router": "1.7.1", + "react-router": "6.14.1" }, "engines": { "node": ">=14" @@ -9511,9 +9536,9 @@ } }, "node_modules/ts-loader": { - "version": "9.4.3", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.3.tgz", - "integrity": "sha512-n3hBnm6ozJYzwiwt5YRiJZkzktftRpMiBApHaJPoWLA+qetQBAXkHqCLM6nwSdRDimqVtA5ocIkcTRLMTt7yzA==", + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.4.tgz", + "integrity": "sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w==", "dev": true, "dependencies": { "chalk": "^4.1.0", @@ -9754,9 +9779,9 @@ } }, "node_modules/typescript": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.5.tgz", - "integrity": "sha512-FOH+WN/DQjUvN6WgW+c4Ml3yi0PH+a/8q+kNIfRehv1wLhWONedw85iu+vQ39Wp49IzTJEsZ2lyLXpBF7mkF1g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -9966,9 +9991,9 @@ } }, "node_modules/webpack": { - "version": "5.88.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.0.tgz", - "integrity": "sha512-O3jDhG5e44qIBSi/P6KpcCcH7HD+nYIHVBhdWFxcLOcIGN8zGo5nqF3BjyNCxIh4p1vFdNnreZv2h2KkoAw3lw==", + "version": "5.88.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.1.tgz", + "integrity": "sha512-FROX3TxQnC/ox4N+3xQoWZzvGXSuscxR32rbzjpXgEzWudJFEJBpdlkkob2ylrv5yzzufD1zph1OoFsLtm6stQ==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -10259,15 +10284,6 @@ "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 7238c9a..de5afb3 100644 --- a/package.json +++ b/package.json @@ -27,13 +27,13 @@ "html-react-parser": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.14.0" + "react-router-dom": "^6.14.1" }, "devDependencies": { "@babel/preset-env": "^7.22.5", "@babel/preset-react": "^7.22.5", "@types/jest": "^29.5.2", - "@types/node": "^20.3.2", + "@types/node": "^20.3.3", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", "@types/sanitize-html": "^2.9.0", @@ -46,7 +46,7 @@ "core-js": "^3.31.0", "crypto-browserify": "^3.12.0", "css-loader": "^6.8.1", - "eslint": "^8.43.0", + "eslint": "^8.44.0", "eslint-plugin-react": "^7.32.2", "file-loader": "^6.2.0", "html-loader": "^4.2.0", @@ -55,12 +55,12 @@ "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "style-loader": "^3.3.3", - "ts-loader": "^9.4.3", + "ts-loader": "^9.4.4", "ts-node": "^10.9.1", - "typescript": "^5.1.5", + "typescript": "^5.1.6", "url": "^0.11.1", "util": "^0.12.5", - "webpack": "^5.88.0", + "webpack": "^5.88.1", "webpack-cli": "^5.1.4", "webpack-dev-server": "^4.15.1" } diff --git a/src/client/CacheClient.ts b/src/client/CacheClient.ts index f2ff419..5c1ea36 100644 --- a/src/client/CacheClient.ts +++ b/src/client/CacheClient.ts @@ -13,8 +13,8 @@ type EventCallbacksArray = { [EventName in keyof CacheEventCallbacks]: CacheEventCallbacks[EventName][]; }; -type MutableCacheClient = { - -readonly [K in keyof CacheClient]: CacheClient[K]; +export type Mutable = { + -readonly [K in keyof T]: T[K]; }; export default class CacheClient extends Client { @@ -38,7 +38,7 @@ export default class CacheClient extends Client { // Add project to cache. if (this.projects) { - (this as MutableCacheClient).projects = [...this.projects, project]; + (this as Mutable).projects = [...this.projects, project]; } @@ -50,7 +50,7 @@ export default class CacheClient extends Client { if (!this.projects) { - (this as MutableCacheClient).projects = await super.getProjects(...parameters); + (this as Mutable).projects = await super.getProjects(...parameters); this.#fireEvent("projectsArrayChange", this.projects ?? []); } @@ -61,7 +61,7 @@ export default class CacheClient extends Client { addEventListener(eventName: EventName, callback: CacheEventCallbacks[EventName]): void { - this.eventCallbacks[eventName].push(callback as () => void); + this.eventCallbacks[eventName].push(callback); } @@ -77,13 +77,13 @@ export default class CacheClient extends Client { removeEventListener(eventName: EventName, callback: CacheEventCallbacks[EventName]): void { - this.eventCallbacks[eventName] = (this.eventCallbacks[eventName] as (() => void)[]).filter((possibleCallback) => possibleCallback !== callback); + this.eventCallbacks[eventName] = this.eventCallbacks[eventName].filter((possibleCallback) => possibleCallback !== callback) as EventCallbacksArray[EventName]; } setCurrentProject(project: Project | null): void { - (this as MutableCacheClient).currentProject = project; + (this as Mutable).currentProject = project; this.#fireEvent("currentProjectChange", project); @@ -91,7 +91,7 @@ export default class CacheClient extends Client { setSelectedProjects(projects: Project[]): void { - (this as MutableCacheClient).selectedProjects = projects; + (this as Mutable).selectedProjects = projects; this.#fireEvent("projectSelectionChange", projects); @@ -99,7 +99,7 @@ export default class CacheClient extends Client { setSelectedTasks(tasks: Task[]): void { - (this as MutableCacheClient).selectedTasks = tasks; + (this as Mutable).selectedTasks = tasks; this.#fireEvent("taskBacklogSelectionChange", tasks); diff --git a/src/client/Client.ts b/src/client/Client.ts index 830dcd1..8d03053 100644 --- a/src/client/Client.ts +++ b/src/client/Client.ts @@ -5,11 +5,13 @@ import Task, { InitialTaskProperties, TaskProperties } from "./Task"; import Label, { InitialLabelProperties, LabelProperties } from "./Label"; import Project, { defaultStatuses, InitialProjectProperties, ProjectProperties } from "./Project"; import "dexie-export-import"; +import TaskList, { InitialTaskListProperties, TaskListProperties } from "./TaskList"; +import { ContentNotFoundError } from "./errors/ContentNotFoundError"; export type Optional = Pick, K> & Omit; export type PropertiesUpdate = Partial>; -export type PlanzeaObject = Attachment | Task | Label | Project; -export type PlanzeaObjectConstructor = typeof Attachment | typeof Task | typeof Label | typeof Project; +export type PlanzeaObject = Attachment | Task | TaskList | Label | Project; +export type PlanzeaObjectConstructor = typeof Attachment | typeof TaskList | typeof Task | typeof Label | typeof Project; export type PlanzeaObjectProperties = AttachmentProperties & TaskProperties & LabelProperties & ProjectProperties; export interface EventCallbacks { @@ -22,6 +24,9 @@ export interface EventCallbacks { taskCreate: ((task: Task) => void) | (() => void); taskDelete: ((taskId: string) => void) | (() => void); taskUpdate: ((newTask: Task, oldTaskProperties?: TaskProperties) => void) | ((newTask: Task) => void) | (() => void); + taskListCreate: ((taskList: TaskList) => void) | (() => void); + taskListDelete: ((taskListId: string) => void) | (() => void); + taskListUpdate: ((newTaskList: TaskList, oldTaskListProperties?: TaskListProperties) => void) | ((newTaskList: TaskList) => void) | (() => void); } type EventCallbacksArray = { @@ -65,15 +70,19 @@ export default class Client { projectUpdate: [], taskCreate: [], taskDelete: [], - taskUpdate: [] + taskUpdate: [], + taskListCreate: [], + taskListDelete: [], + taskListUpdate: [] }; personalProjectId?: string; async #createObject(constructor: typeof Attachment, props: InitialAttachmentProperties): Promise; async #createObject(constructor: typeof Task, props: InitialTaskProperties): Promise; + async #createObject(constructor: typeof TaskList, props: InitialTaskListProperties): Promise; async #createObject(constructor: typeof Label, props: InitialLabelProperties): Promise