mirror of
https://github.com/sechan100/daily-routine-2.git
synced 2026-07-22 05:37:51 +00:00
새로운 property인 daysOfMonth를 추가
새로운 프로퍼티를 추가하고, 이에 따른 features ui까지 개발
This commit is contained in:
parent
17ded3743f
commit
a967873152
24 changed files with 1377 additions and 323 deletions
|
|
@ -5,7 +5,8 @@
|
|||
"plugins": [
|
||||
"@typescript-eslint",
|
||||
"react",
|
||||
"react-hooks"
|
||||
"react-hooks",
|
||||
"fsd-import"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
|
|
@ -23,6 +24,9 @@
|
|||
"@typescript-eslint/no-empty-interface": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"react-hooks/rules-of-hooks": "error", // Hooks의 규칙을 강제
|
||||
"react-hooks/exhaustive-deps": "warn" // 의존성 배열 검사
|
||||
"react-hooks/exhaustive-deps": "warn", // 의존성 배열 검사
|
||||
"fsd-import/fsd-relative-path": "error",
|
||||
"fsd-import/public-api-imports": "error",
|
||||
"fsd-import/layer-imports": "error"
|
||||
}
|
||||
}
|
||||
564
package-lock.json
generated
564
package-lock.json
generated
|
|
@ -9,6 +9,8 @@
|
|||
"version": "1.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/styled": "^11.13.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"clsx": "^2.1.1",
|
||||
"esbuild-sass-plugin": "^3.3.1",
|
||||
|
|
@ -17,6 +19,7 @@
|
|||
"lodash": "^4.17.21",
|
||||
"npm": "^10.8.3",
|
||||
"react": "^18.3.1",
|
||||
"react-bem-helper": "^1.4.1",
|
||||
"react-calendar": "^5.0.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
|
|
@ -36,11 +39,158 @@
|
|||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"esbuild": "^0.24.0",
|
||||
"eslint-plugin-fsd-import": "^0.0.13",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz",
|
||||
"integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==",
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.25.7",
|
||||
"picocolors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz",
|
||||
"integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.25.7",
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"jsesc": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-imports": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz",
|
||||
"integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==",
|
||||
"dependencies": {
|
||||
"@babel/traverse": "^7.25.7",
|
||||
"@babel/types": "^7.25.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz",
|
||||
"integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz",
|
||||
"integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz",
|
||||
"integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.25.7",
|
||||
"chalk": "^2.4.2",
|
||||
"js-tokens": "^4.0.0",
|
||||
"picocolors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz",
|
||||
"integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.25.8"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz",
|
||||
|
|
@ -52,6 +202,57 @@
|
|||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz",
|
||||
"integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.25.7",
|
||||
"@babel/parser": "^7.25.7",
|
||||
"@babel/types": "^7.25.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz",
|
||||
"integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.25.7",
|
||||
"@babel/generator": "^7.25.7",
|
||||
"@babel/parser": "^7.25.7",
|
||||
"@babel/template": "^7.25.7",
|
||||
"@babel/types": "^7.25.7",
|
||||
"debug": "^4.3.1",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse/node_modules/globals": {
|
||||
"version": "11.12.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
||||
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.25.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz",
|
||||
"integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.25.7",
|
||||
"@babel/helper-validator-identifier": "^7.25.7",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bufbuild/protobuf": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.1.0.tgz",
|
||||
|
|
@ -77,6 +278,139 @@
|
|||
"w3c-keyname": "^2.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/babel-plugin": {
|
||||
"version": "11.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz",
|
||||
"integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": "^7.16.7",
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/hash": "^0.9.2",
|
||||
"@emotion/memoize": "^0.9.0",
|
||||
"@emotion/serialize": "^1.2.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"convert-source-map": "^1.5.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"find-root": "^1.1.0",
|
||||
"source-map": "^0.5.7",
|
||||
"stylis": "4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/cache": {
|
||||
"version": "11.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz",
|
||||
"integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==",
|
||||
"dependencies": {
|
||||
"@emotion/memoize": "^0.9.0",
|
||||
"@emotion/sheet": "^1.4.0",
|
||||
"@emotion/utils": "^1.4.0",
|
||||
"@emotion/weak-memoize": "^0.4.0",
|
||||
"stylis": "4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/hash": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
|
||||
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g=="
|
||||
},
|
||||
"node_modules/@emotion/is-prop-valid": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz",
|
||||
"integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==",
|
||||
"dependencies": {
|
||||
"@emotion/memoize": "^0.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/memoize": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
|
||||
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ=="
|
||||
},
|
||||
"node_modules/@emotion/react": {
|
||||
"version": "11.13.3",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz",
|
||||
"integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.12.0",
|
||||
"@emotion/cache": "^11.13.0",
|
||||
"@emotion/serialize": "^1.3.1",
|
||||
"@emotion/use-insertion-effect-with-fallbacks": "^1.1.0",
|
||||
"@emotion/utils": "^1.4.0",
|
||||
"@emotion/weak-memoize": "^0.4.0",
|
||||
"hoist-non-react-statics": "^3.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/serialize": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz",
|
||||
"integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==",
|
||||
"dependencies": {
|
||||
"@emotion/hash": "^0.9.2",
|
||||
"@emotion/memoize": "^0.9.0",
|
||||
"@emotion/unitless": "^0.10.0",
|
||||
"@emotion/utils": "^1.4.1",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/sheet": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
|
||||
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg=="
|
||||
},
|
||||
"node_modules/@emotion/styled": {
|
||||
"version": "11.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz",
|
||||
"integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.12.0",
|
||||
"@emotion/is-prop-valid": "^1.3.0",
|
||||
"@emotion/serialize": "^1.3.0",
|
||||
"@emotion/use-insertion-effect-with-fallbacks": "^1.1.0",
|
||||
"@emotion/utils": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.0.0-rc.0",
|
||||
"react": ">=16.8.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/unitless": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
|
||||
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg=="
|
||||
},
|
||||
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz",
|
||||
"integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/utils": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz",
|
||||
"integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA=="
|
||||
},
|
||||
"node_modules/@emotion/weak-memoize": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
|
||||
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg=="
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz",
|
||||
|
|
@ -528,6 +862,49 @@
|
|||
"deprecated": "Use @eslint/object-schema instead",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
||||
"dependencies": {
|
||||
"@jridgewell/set-array": "^1.2.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/set-array": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.25",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
|
@ -617,6 +994,11 @@
|
|||
"integrity": "sha512-OF3keVCbfPlkzxnnDBUZJn1RiCJzKeadjiW0xTEb0G1SUJ5gDVb3qnzZr2T4uIFvsbKJbXy1v2DN7e2zaEY7jQ==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
|
||||
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
|
||||
|
|
@ -1062,6 +1444,36 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-macros": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
|
||||
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"cosmiconfig": "^7.0.0",
|
||||
"resolve": "^1.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10",
|
||||
"npm": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-macros/node_modules/resolve": {
|
||||
"version": "1.22.8",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.13.0",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"resolve": "bin/resolve"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
|
|
@ -1128,7 +1540,6 @@
|
|||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
|
@ -1200,6 +1611,26 @@
|
|||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
||||
"integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
|
||||
"dependencies": {
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"parse-json": "^5.0.0",
|
||||
"path-type": "^4.0.0",
|
||||
"yaml": "^1.10.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
|
|
@ -1217,8 +1648,7 @@
|
|||
"node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||
},
|
||||
"node_modules/data-view-buffer": {
|
||||
"version": "1.0.1",
|
||||
|
|
@ -1368,6 +1798,14 @@
|
|||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/es-abstract": {
|
||||
"version": "1.23.3",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
|
||||
|
|
@ -1590,7 +2028,6 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
|
|
@ -1653,6 +2090,22 @@
|
|||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-fsd-import": {
|
||||
"version": "0.0.13",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-fsd-import/-/eslint-plugin-fsd-import-0.0.13.tgz",
|
||||
"integrity": "sha512-BrICj/81D624rN2kQiMKFDcQUFshZe0Aa8vZzZFWuByEDkfyk0zG9eeiZ9Kgb5G7JzcLnvUykLVGoWugEVFRtw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"micromatch": "^4.0.5",
|
||||
"requireindex": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.0.0 || ^17.0.0 || >= 18.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=7"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react": {
|
||||
"version": "7.37.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.1.tgz",
|
||||
|
|
@ -1949,6 +2402,11 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/find-root": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
||||
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
|
||||
},
|
||||
"node_modules/find-up": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||
|
|
@ -2283,7 +2741,6 @@
|
|||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"parent-module": "^1.0.0",
|
||||
"resolve-from": "^4.0.0"
|
||||
|
|
@ -2349,6 +2806,11 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
|
||||
},
|
||||
"node_modules/is-async-function": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
|
||||
|
|
@ -2699,12 +3161,28 @@
|
|||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jsesc": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
|
||||
"integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
|
||||
"bin": {
|
||||
"jsesc": "bin/jsesc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/json-parse-even-better-errors": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
|
|
@ -2753,6 +3231,11 @@
|
|||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
|
|
@ -5382,7 +5865,6 @@
|
|||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"callsites": "^3.0.0"
|
||||
},
|
||||
|
|
@ -5390,6 +5872,23 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-json": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
|
||||
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"error-ex": "^1.3.1",
|
||||
"json-parse-even-better-errors": "^2.3.0",
|
||||
"lines-and-columns": "^1.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
|
|
@ -5426,11 +5925,15 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
|
||||
"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw=="
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
|
|
@ -5509,6 +6012,14 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-bem-helper": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/react-bem-helper/-/react-bem-helper-1.4.1.tgz",
|
||||
"integrity": "sha512-TQD6WfT5fPgr48v8GLmP8ldc7D5iT75VZ6B4nC05uTvPuaDf64m5FrCEHNY3R1u90wdCxtC2J5OvY8Z1hfwyJw==",
|
||||
"dependencies": {
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-calendar": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-5.0.0.tgz",
|
||||
|
|
@ -5702,6 +6213,15 @@
|
|||
"url": "https://github.com/sponsors/mysticatea"
|
||||
}
|
||||
},
|
||||
"node_modules/requireindex": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz",
|
||||
"integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.5"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "2.0.0-next.5",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
|
||||
|
|
@ -5722,7 +6242,6 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
|
|
@ -6312,6 +6831,14 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
|
|
@ -6431,6 +6958,11 @@
|
|||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/stylis": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
|
||||
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
|
|
@ -6478,6 +7010,14 @@
|
|||
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
|
|
@ -6771,6 +7311,14 @@
|
|||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
|
|
|
|||
|
|
@ -21,11 +21,14 @@
|
|||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"esbuild": "^0.24.0",
|
||||
"eslint-plugin-fsd-import": "^0.0.13",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/styled": "^11.13.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"clsx": "^2.1.1",
|
||||
"esbuild-sass-plugin": "^3.3.1",
|
||||
|
|
@ -34,6 +37,7 @@
|
|||
"lodash": "^4.17.21",
|
||||
"npm": "^10.8.3",
|
||||
"react": "^18.3.1",
|
||||
"react-bem-helper": "^1.4.1",
|
||||
"react-calendar": "^5.0.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { routineManager, Routine } from "entities/routine/routine";
|
||||
import { routineManager } from "entities/routine/routine";
|
||||
import { Routine } from "./routine/types";
|
||||
import { RoutineNote, routineNoteService, Task } from "entities/routine-note";
|
||||
////////////////////////////////////
|
||||
import { fileAccessor } from "shared/file/file-accessor";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Day } from "shared/day";
|
||||
import { Routine, routineManager } from "./routine/routine";
|
||||
import { routineManager } from "./routine/routine";
|
||||
import { Routine } from "./routine/types";
|
||||
import moment from "obsidian";
|
||||
|
||||
|
||||
|
|
@ -161,13 +162,37 @@ ${routineNote.tasks.map(task => {
|
|||
|
||||
|
||||
/**
|
||||
* routine으로부터 Task를 파생시킨다.
|
||||
* routine으로부터 Task를 유도한다.
|
||||
* @param routine
|
||||
* @param day
|
||||
* @returns RoutineTask | null 만약 routine이 day에 수행어야하는 루틴이 아니라면 null을 반환한다.
|
||||
*/
|
||||
const deriveRoutineTask = (routine: Routine, day: Day): RoutineTask | null => {
|
||||
if (!routine.properties.daysOfWeek.contains(day.getDayOfWeek())) return null;
|
||||
/**
|
||||
* NOTE: 이 부분은 daysOfWeek와 daysOfMonth를 기준으로 루틴을 수행할지 말지를 결정한다.
|
||||
* 특히 daysOfMonth의 경우에는, 0인 경우를 주의해서 처리해야하는데, 이는 매월 마지막 날을 의미한다.
|
||||
*/
|
||||
|
||||
// MONTH 기준
|
||||
if(routine.properties.activeCriteria === "month"){
|
||||
const days = Array.from(routine.properties.daysOfMonth);
|
||||
|
||||
// 0이 존재하는 경우, 0을 매개받은 day의 달의 마지막 날짜로 치환한다.
|
||||
if(days.contains(0)){
|
||||
const lastDayOfMonth = day.moment.daysInMonth();
|
||||
days.remove(0);
|
||||
days.push(lastDayOfMonth);
|
||||
}
|
||||
|
||||
// 오늘이 수행 날짜인지 확인 후 반환
|
||||
if(!days.contains(day.getDate())) return null;
|
||||
}
|
||||
|
||||
// WEEK 기준
|
||||
if(routine.properties.activeCriteria === "week"){
|
||||
if(!routine.properties.daysOfWeek.contains(day.getDayOfWeek())) return null;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
type: "routine",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { getFrontMatterInfo, parseYaml, stringifyYaml, TFile } from "obsidian";
|
||||
import { getFrontMatterInfo, Notice, parseYaml, stringifyYaml } from "obsidian";
|
||||
import { DayOfWeek } from "shared/day";
|
||||
import { Routine, RoutineProperties } from "./routine";
|
||||
import { keys } from "lodash";
|
||||
import { validateRoutineProperties, RoutineProperties } from "./types";
|
||||
|
||||
|
||||
|
||||
|
|
@ -24,9 +22,15 @@ export class RoutineFrontMatter {
|
|||
const yaml = fmInfo.frontmatter.replace('---', '').trim()
|
||||
const fm = parseYaml(yaml);
|
||||
|
||||
const properties = {
|
||||
const properties: RoutineProperties = {
|
||||
order: fm.order,
|
||||
daysOfWeek: fm.daysOfWeek
|
||||
activeCriteria: fm.activeCriteria,
|
||||
daysOfWeek: fm.daysOfWeek,
|
||||
daysOfMonth: fm.daysOfMonth
|
||||
}
|
||||
if(!validateRoutineProperties(properties)){
|
||||
new Notice('Invalid Routine frontmatter.');
|
||||
throw new Error('Invalid Routine frontmatter.');
|
||||
}
|
||||
|
||||
return new RoutineFrontMatter(properties);
|
||||
|
|
@ -36,7 +40,7 @@ export class RoutineFrontMatter {
|
|||
* properties로부터 RoutineFrontMatter 객체를 생성한다.
|
||||
*/
|
||||
static fromObsidianFrontMatter(frontmatter: unknown){
|
||||
if(!isRoutineProperty(frontmatter)){
|
||||
if(!validateRoutineProperties(frontmatter)){
|
||||
throw new Error('Invalid Routine frontmatter.');
|
||||
}
|
||||
return new RoutineFrontMatter(frontmatter);
|
||||
|
|
@ -46,13 +50,9 @@ export class RoutineFrontMatter {
|
|||
* frontmatter block(---)과 개행문자들로 묶인 frontmatter 문자열을 반환한다.
|
||||
*/
|
||||
stringify(){
|
||||
const props = {
|
||||
order: this.#properties.order,
|
||||
daysOfWeek: this.#properties.daysOfWeek.map(d => DayOfWeek[d])
|
||||
}
|
||||
const frontmatter = [
|
||||
"---",
|
||||
stringifyYaml(props),
|
||||
stringifyYaml(this.#properties),
|
||||
"---"
|
||||
].join('\n');
|
||||
return frontmatter;
|
||||
|
|
@ -64,22 +64,4 @@ export class RoutineFrontMatter {
|
|||
get properties(): RoutineProperties {
|
||||
return this.#properties;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* obsidian api에서 반환된 js object 형식의 frontmatter가 RoutineProperties 타입인지 확인하는 타입가드
|
||||
* @param fm js object로 변환된 frontmatter
|
||||
*/
|
||||
export function isRoutineProperty(fm: any): fm is RoutineProperties {
|
||||
// order
|
||||
const hasOrder = 'order' in fm && typeof fm.order === 'number';
|
||||
|
||||
// daysOfWeek
|
||||
const hasDaysOfWeek =
|
||||
'daysOfWeek' in fm &&
|
||||
Array.isArray(fm.daysOfWeek) &&
|
||||
fm.daysOfWeek.every((d: any) => typeof d === 'string' && keys(DayOfWeek).includes(d));
|
||||
|
||||
return hasOrder && hasDaysOfWeek;
|
||||
}
|
||||
|
|
@ -1 +1,2 @@
|
|||
export { routineManager } from "./routine";
|
||||
export { routineManager } from "./routine";
|
||||
export * from "./types";
|
||||
|
|
@ -1,22 +1,9 @@
|
|||
import { getFrontMatterInfo, parseFrontMatterEntry, parseYaml, stringifyYaml, TFile } from "obsidian";
|
||||
import { TFile } from "obsidian";
|
||||
import { fileAccessor } from "shared/file/file-accessor";
|
||||
import { plugin } from "shared/plugin-service-locator";
|
||||
import { DAYS_OF_WEEK, DayOfWeek } from "shared/day";
|
||||
import { isRoutineProperty, RoutineFrontMatter } from "./front-matter";
|
||||
|
||||
|
||||
/**
|
||||
* 루틴 파일에 대한 정보 객체
|
||||
*/
|
||||
export interface Routine {
|
||||
name: string; // 루틴 파일 제목 겸 루틴 내용
|
||||
properties: RoutineProperties; // 루틴 파일의 프로퍼티
|
||||
}
|
||||
|
||||
export interface RoutineProperties {
|
||||
order: number; // routine들 순서(음이 아닌 정수 0, 1, 2, ...)
|
||||
daysOfWeek: DayOfWeek[];
|
||||
}
|
||||
import { RoutineFrontMatter } from "./front-matter";
|
||||
import { validateRoutineProperties } from "./types";
|
||||
import { Routine, RoutineProperties } from "./types";
|
||||
|
||||
|
||||
interface RoutineManager {
|
||||
|
|
@ -66,7 +53,7 @@ export const routineManager: RoutineManager = {
|
|||
const file = fileAccessor.getFile(path);
|
||||
|
||||
await fileAccessor.writeFrontMatter(file, (fm => {
|
||||
if(!isRoutineProperty(fm)) throw new Error('Invalid Routine frontmatter.');
|
||||
if(!validateRoutineProperties(fm)) throw new Error('Invalid Routine frontmatter.');
|
||||
return {
|
||||
...fm,
|
||||
...newPropertiesPatial
|
||||
|
|
|
|||
59
src/entities/routine/types.ts
Normal file
59
src/entities/routine/types.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { keys } from "lodash";
|
||||
import { DayOfWeek } from "shared/day";
|
||||
|
||||
|
||||
/**
|
||||
* 루틴 파일에 대한 정보 객체
|
||||
*/
|
||||
|
||||
|
||||
export interface Routine {
|
||||
name: string; // 루틴 파일 제목 겸 루틴 내용
|
||||
properties: RoutineProperties; // 루틴 파일의 프로퍼티
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export interface RoutineProperties {
|
||||
order: number; // routine들 순서(음이 아닌 정수 0, 1, 2, ...)
|
||||
activeCriteria: "week" | "month"; // 루틴이 활성화되는 기준
|
||||
daysOfMonth: number[]; // 0 ~ 31 (0은 매월 마지막 날)
|
||||
daysOfWeek: DayOfWeek[]; // 요일
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* obsidian api에서 반환된 js object 형식의 frontmatter가 RoutineProperties 타입인지 확인하는 타입가드
|
||||
* @param fm js object로 변환된 frontmatter
|
||||
*/
|
||||
|
||||
export function validateRoutineProperties(fm: any): fm is RoutineProperties {
|
||||
console.log(fm);
|
||||
// order
|
||||
const hasOrder = 'order' in fm && typeof fm.order === 'number';
|
||||
if(!hasOrder) return false;
|
||||
|
||||
// activeCriteria
|
||||
const hasActiveCriteria = 'activeCriteria' in fm &&
|
||||
(fm.activeCriteria === 'week' || fm.activeCriteria === 'month');
|
||||
if(!hasActiveCriteria) return false;
|
||||
|
||||
// daysOfWeek
|
||||
const validDaysOfWeekIfHas = 'daysOfWeek' in fm &&
|
||||
Array.isArray(fm.daysOfWeek) &&
|
||||
fm.daysOfWeek.every((d: any) => typeof d === 'string' && keys(DayOfWeek).includes(d));
|
||||
|
||||
// daysOfMonth
|
||||
const validDaysOfMonthIfHas = 'daysOfMonth' in fm &&
|
||||
Array.isArray(fm.daysOfMonth) &&
|
||||
fm.daysOfMonth.every((d: any) => typeof d === 'number' && d >= 0 && d <= 31);
|
||||
|
||||
// daysOfWeek OR daysOfMonth
|
||||
if(!(validDaysOfMonthIfHas && validDaysOfWeekIfHas)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2,7 +2,7 @@ import { routineNoteArchiver } from "entities/archive";
|
|||
import { RoutineNote, routineNoteService } from "entities/routine-note";
|
||||
//////////////////////////////
|
||||
import { Day } from "shared/day";
|
||||
import { PerCentageCircle } from "shared/components/PercentageCircle";
|
||||
import { PercentageCircle } from "shared/components/PercentageCircle";
|
||||
import Calendar from "react-calendar"
|
||||
import { moment } from "obsidian";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
|
@ -72,7 +72,7 @@ export const RoutineCalendar = ({ defaultDay, onDayTileClick }: RoutineCalendarP
|
|||
// 렌더링
|
||||
if(!routineNotes) return <div>Loading...</div>;
|
||||
return (
|
||||
<div>
|
||||
<div className="dr-routine-note-calendar">
|
||||
<Calendar
|
||||
tileContent={tileContent}
|
||||
defaultValue={activeDay.getJsDate()}
|
||||
|
|
@ -99,6 +99,6 @@ const DayTile = ({percentage, day }: DayTileProps) => {
|
|||
return () => clearTimeout(cancel);
|
||||
}, [percentage]);
|
||||
return (
|
||||
<PerCentageCircle percentage={percent} text={day.getDate().toString()} />
|
||||
<PercentageCircle percentage={percent} text={day.getDate().toString()} />
|
||||
)
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ $color-hover-bg: #e6e6e6;
|
|||
}
|
||||
|
||||
// react-calendar 기본 스타일
|
||||
.react-calendar {
|
||||
.dr-routine-note-calendar .react-calendar {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
background: white;
|
||||
|
|
@ -51,7 +51,7 @@ $color-hover-bg: #e6e6e6;
|
|||
}
|
||||
|
||||
// 네비게이션
|
||||
.react-calendar__navigation {
|
||||
.dr-routine-note-calendar .react-calendar__navigation {
|
||||
display: flex;
|
||||
height: 44px;
|
||||
margin-bottom: 1em;
|
||||
|
|
@ -74,7 +74,7 @@ $color-hover-bg: #e6e6e6;
|
|||
}
|
||||
|
||||
// 월, 요일 및 날짜
|
||||
.react-calendar__month-view__weekdays {
|
||||
.dr-routine-note-calendar .react-calendar__month-view__weekdays {
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font: inherit;
|
||||
|
|
@ -86,7 +86,7 @@ $color-hover-bg: #e6e6e6;
|
|||
}
|
||||
}
|
||||
|
||||
.react-calendar__month-view__weekNumbers .react-calendar__tile {
|
||||
.dr-routine-note-calendar .react-calendar__month-view__weekNumbers .react-calendar__tile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -96,7 +96,7 @@ $color-hover-bg: #e6e6e6;
|
|||
}
|
||||
|
||||
// 날짜 타일 스타일
|
||||
.react-calendar__month-view__days {
|
||||
.dr-routine-note-calendar .react-calendar__month-view__days {
|
||||
gap: 0.5em 0;
|
||||
|
||||
&__day {
|
||||
|
|
@ -120,7 +120,7 @@ $color-hover-bg: #e6e6e6;
|
|||
}
|
||||
}
|
||||
// 이웃한 달의 날짜
|
||||
.react-calendar__month-view__days__day--neighboringMonth {
|
||||
.dr-routine-note-calendar .react-calendar__month-view__days__day--neighboringMonth {
|
||||
.dr-percentage-circle {
|
||||
circle {
|
||||
stroke: $color-disabled-neighbor !important;
|
||||
|
|
@ -134,7 +134,7 @@ $color-hover-bg: #e6e6e6;
|
|||
|
||||
|
||||
// react-calendar 타일
|
||||
.react-calendar__tile {
|
||||
.dr-routine-note-calendar .react-calendar__tile {
|
||||
max-width: 100%;
|
||||
height: 6em;
|
||||
padding: 1em;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Day } from "shared/day";
|
|||
import clsx from "clsx";
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import "./days-nav.scss";
|
||||
import { PerCentageCircle } from "shared/components/PercentageCircle";
|
||||
import { PercentageCircle } from "shared/components/PercentageCircle";
|
||||
import { Navigation } from 'swiper/modules';
|
||||
import { Swiper, SwiperClass, SwiperRef, SwiperSlide } from 'swiper/react';
|
||||
import 'swiper/swiper-bundle.css';
|
||||
|
|
@ -217,7 +217,7 @@ export const DaysNav = ({ currentDay, onDayClick }: DaysNavProps) => {
|
|||
onClick={(e) => onDayClick(day, e)}
|
||||
>
|
||||
<div className="dr-days__day-of-week">{day.format("ddd")}</div>
|
||||
<PerCentageCircle
|
||||
<PercentageCircle
|
||||
percentage={percentage}
|
||||
transition={circleTransitionRef.current}
|
||||
text={day.format("M/D")}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
/** @jsxImportSource @emotion/react */
|
||||
import { RoutineProperties } from "entities/routine";
|
||||
import { useCallback, useEffect, useRef } from "react";
|
||||
import clsx from "clsx";
|
||||
import { useCallback } from "react";
|
||||
import Calendar from "react-calendar";
|
||||
import { DAYS_OF_WEEK, DayOfWeek } from "shared/day";
|
||||
import { ButtonComponent } from "obsidian";
|
||||
import "./days-of-month-calendar-style.scss";
|
||||
import { Button } from "shared/components/Button";
|
||||
import { dr } from "shared/daily-routine-bem";
|
||||
|
||||
|
||||
|
||||
|
|
@ -8,28 +15,80 @@ import { DAYS_OF_WEEK, DayOfWeek } from "shared/day";
|
|||
|
||||
interface DaysOptionProps {
|
||||
className?: string;
|
||||
getDays: () => DayOfWeek[];
|
||||
onDaysChange: (action: "add" | "remove", day: DayOfWeek) => void;
|
||||
properties: RoutineProperties;
|
||||
setProperties: (props: RoutineProperties) => void;
|
||||
}
|
||||
export const DaysOption = ({ className, getDays, onDaysChange }: DaysOptionProps) => {
|
||||
// 날짜 하나하나 클릭시
|
||||
/**
|
||||
* daysOfWeek, 또는 daysOfMonth를 설정하는 옵션 컴포넌트
|
||||
*/
|
||||
export const DaysOption = ({ className, properties, setProperties }: DaysOptionProps) => {
|
||||
|
||||
|
||||
// activeCriteria 변경 콜백
|
||||
const changeActiveCriteria = useCallback((criteria: "week" | "month") => {
|
||||
setProperties({
|
||||
...properties,
|
||||
activeCriteria: criteria
|
||||
});
|
||||
}, [properties, setProperties]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<Button onClick={() => changeActiveCriteria("week")}>Week</Button>
|
||||
<Button onClick={() => changeActiveCriteria("month")}>Month</Button>
|
||||
</div>
|
||||
<>
|
||||
{properties.activeCriteria === "week" &&
|
||||
<DaysOfWeekOption
|
||||
daysOfWeek={properties.daysOfWeek}
|
||||
setDaysOfweek={(daysOfWeek) => setProperties({...properties, daysOfWeek})}
|
||||
/>
|
||||
}
|
||||
|
||||
{properties.activeCriteria === "month" &&
|
||||
<DaysOfMonthOption
|
||||
daysOfMonth={properties.daysOfMonth}
|
||||
setDaysOfMonth={(daysOfMonth) => setProperties({...properties, daysOfMonth})}
|
||||
/>
|
||||
}
|
||||
</>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
interface DaysOfWeekOptionProps {
|
||||
daysOfWeek: DayOfWeek[];
|
||||
setDaysOfweek: (daysOfWeek: DayOfWeek[]) => void;
|
||||
}
|
||||
const DaysOfWeekOption = ({ daysOfWeek, setDaysOfweek }: DaysOfWeekOptionProps) => {
|
||||
|
||||
// 날짜 하나하나 클릭시 선택/해제 콜백
|
||||
const onDayClick = useCallback((e: React.MouseEvent) => {
|
||||
e.currentTarget.classList.toggle("dr-routine-option-days__day--active");
|
||||
const isActive = e.currentTarget.classList.contains("dr-routine-option-days__day--active");
|
||||
const dayOfWeek = DayOfWeek[e.currentTarget.getAttribute('data-day-of-week') as keyof typeof DayOfWeek];
|
||||
const targetDOW = DayOfWeek[e.currentTarget.getAttribute('data-day-of-week') as keyof typeof DayOfWeek];
|
||||
if(isActive){
|
||||
onDaysChange("add", dayOfWeek);
|
||||
setDaysOfweek([...daysOfWeek, targetDOW] );
|
||||
} else {
|
||||
onDaysChange("remove", dayOfWeek);
|
||||
setDaysOfweek(daysOfWeek.filter(d => d !== targetDOW));
|
||||
}
|
||||
}, [onDaysChange])
|
||||
}, [daysOfWeek, setDaysOfweek])
|
||||
|
||||
return (
|
||||
<div className={clsx(className, "dr-routine-option-days")}>
|
||||
<div className={clsx("dr-routine-option-days")}>
|
||||
<h6>Days</h6>
|
||||
<div className="dr-routine-option-days__list">
|
||||
{DAYS_OF_WEEK.map((dayOfWeek, idx) => {
|
||||
const isActive = getDays().includes(dayOfWeek);
|
||||
const isActive = daysOfWeek.includes(dayOfWeek);
|
||||
return (
|
||||
<button key={idx} data-day-of-week={dayOfWeek} onClick={onDayClick} className={clsx(
|
||||
"dr-routine-option-days__day",
|
||||
|
|
@ -42,4 +101,118 @@ export const DaysOption = ({ className, getDays, onDaysChange }: DaysOptionProps
|
|||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
interface DaysOfMonthOptionProps {
|
||||
daysOfMonth: number[];
|
||||
setDaysOfMonth: (daysOfMonth: number[]) => void;
|
||||
}
|
||||
const DaysOfMonthOption = ({ daysOfMonth, setDaysOfMonth }: DaysOfMonthOptionProps) => {
|
||||
|
||||
|
||||
|
||||
// 받은 날짜가 있다면 제거 없다면 추가해주는 함수
|
||||
const toggleDay = useCallback((day: number) => {
|
||||
if(daysOfMonth.includes(day)){
|
||||
setDaysOfMonth(daysOfMonth.filter(d => d !== day));
|
||||
} else {
|
||||
setDaysOfMonth([...daysOfMonth, day]);
|
||||
}
|
||||
}, [daysOfMonth, setDaysOfMonth]);
|
||||
|
||||
// BEM 선언
|
||||
const bem = dr("days-of-month-option-calendar");
|
||||
|
||||
|
||||
// 달력의 빈 공간에 Last Day of Month 버튼을 추가
|
||||
const lastDayBtn = useRef<ButtonComponent>(null);
|
||||
useEffect(() => {
|
||||
const calendarFlex = document.querySelector(".react-calendar__month-view__days");
|
||||
if(!calendarFlex) return;
|
||||
|
||||
const div = document.createElement("div");
|
||||
calendarFlex.appendChild(div);
|
||||
div.setCssStyles({
|
||||
display: "flex",
|
||||
justifyContent: "space-around",
|
||||
alignItems: "center",
|
||||
flexGrow: "1",
|
||||
});
|
||||
|
||||
const cn = bem("last-day-tile", {
|
||||
active: daysOfMonth.includes(0)
|
||||
}).split(" ");
|
||||
|
||||
const btn = new ButtonComponent(div)
|
||||
// @ts-ignore
|
||||
lastDayBtn.current = btn;
|
||||
btn.setClass(cn[0])
|
||||
if(cn[1]) btn.setClass(cn[1])
|
||||
|
||||
btn.setButtonText("Last Day of Month")
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []); // 리렌더링시 재실행하지 않음
|
||||
|
||||
|
||||
// onClick 이벤트를 등록. 해당 로직은 toggleDay 함수가 변경되었을 때, 같이 변경해주지 않으면 버그가 발생하기에 따로 떼어서 리렌더링
|
||||
useEffect(() => {
|
||||
if(!lastDayBtn.current) return;
|
||||
// 클릭시 0일로 추가/제거 , 배경색 토글
|
||||
lastDayBtn.current.onClick((e) => {
|
||||
// @ts-ignore
|
||||
e.currentTarget.classList.toggle(bem("last-day-tile", "active").split(" ")[1]);
|
||||
toggleDay(0);
|
||||
})
|
||||
}, [bem, toggleDay]);
|
||||
|
||||
|
||||
// 날짜타일 클릭시 콜백
|
||||
const onClickDay = useCallback((v: Date, e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
const date = v.getDate();
|
||||
toggleDay(date);
|
||||
}, [toggleDay]);
|
||||
|
||||
|
||||
// 달력의 날짜 타일 하나하나를 렌더링하는 방식을 정의
|
||||
const tileContent = ({ date, view }: { date: Date, view: string }) => {
|
||||
return (
|
||||
<div
|
||||
className={bem("tile")}
|
||||
css={{
|
||||
width: "4em",
|
||||
height: "4em",
|
||||
border: "1px solid var(--color-base-50)",
|
||||
borderRadius: "50%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
backgroundColor: daysOfMonth.includes(date.getDate()) ? "var(--color-accent-1)" : "transparent",
|
||||
}}
|
||||
>
|
||||
{date.getDate().toString()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={bem()}
|
||||
css={{
|
||||
width: "100%",
|
||||
}}>
|
||||
<Calendar
|
||||
tileContent={tileContent}
|
||||
value={new Date(2024, 0, 1)}
|
||||
allowPartialRange={false}
|
||||
selectRange={false}
|
||||
showNavigation={false}
|
||||
onClickDay={onClickDay}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,107 +1,108 @@
|
|||
import { Routine, routineManager } from "entities/routine/routine";
|
||||
//////////////////////
|
||||
import { plugin } from "shared/plugin-service-locator";
|
||||
import { Modal, TextComponent } from "obsidian";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { DaysOption } from "./DaysOption";
|
||||
import { DAYS_OF_WEEK, DayOfWeek } from "shared/day";
|
||||
import React, { useRef, useState, useEffect, useReducer, memo, useCallback } from "react";
|
||||
// import { routineManager } from "entities/routine";
|
||||
// import { Routine } from "entities/routine";
|
||||
// //////////////////////
|
||||
// import { plugin } from "shared/plugin-service-locator";
|
||||
// import { Modal, TextComponent } from "obsidian";
|
||||
// import { createRoot } from "react-dom/client";
|
||||
// import { DaysOption } from "./DaysOption";
|
||||
// import { DAYS_OF_WEEK, DayOfWeek } from "shared/day";
|
||||
// import { useRef, useEffect, useReducer, memo, useCallback } from "react";
|
||||
|
||||
|
||||
|
||||
export const openAddRoutineModal = () => {
|
||||
new AddRoutineModal().open();
|
||||
}
|
||||
// export const openAddRoutineModal = () => {
|
||||
// new AddRoutineModal().open();
|
||||
// }
|
||||
|
||||
// Obsidian Modal
|
||||
class AddRoutineModal extends Modal {
|
||||
constructor() {
|
||||
super(plugin().app);
|
||||
const el = document.createElement('div');
|
||||
createRoot(el).render(<AddRoutineModalComponent modal={this} />);
|
||||
const content = document.createDocumentFragment();
|
||||
content.appendChild(el);
|
||||
super.setContent(content);
|
||||
}
|
||||
}
|
||||
// // Obsidian Modal
|
||||
// class AddRoutineModal extends Modal {
|
||||
// constructor() {
|
||||
// super(plugin().app);
|
||||
// const el = document.createElement('div');
|
||||
// createRoot(el).render(<AddRoutineModalComponent modal={this} />);
|
||||
// const content = document.createDocumentFragment();
|
||||
// content.appendChild(el);
|
||||
// super.setContent(content);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
type RoutineReducerAction =
|
||||
| {type: "NAME", payload: string}
|
||||
| {type: "ADD_DAYS", payload: DayOfWeek}
|
||||
| {type: "DELETE_DAYS", payload: DayOfWeek}
|
||||
// type RoutineReducerAction =
|
||||
// | {type: "NAME", payload: string}
|
||||
// | {type: "ADD_DAYS", payload: DayOfWeek}
|
||||
// | {type: "DELETE_DAYS", payload: DayOfWeek}
|
||||
|
||||
type Reducer = (state: Routine, action: RoutineReducerAction)=>Routine;
|
||||
const routineReducer: Reducer = (state, action) => {
|
||||
switch (action.type) {
|
||||
case "NAME":
|
||||
return { ...state, name: action.payload };
|
||||
case "ADD_DAYS":
|
||||
return {
|
||||
...state,
|
||||
properties: { ...state.properties, daysOfWeek: [...state.properties.daysOfWeek, action.payload] }
|
||||
};
|
||||
case "DELETE_DAYS":
|
||||
return {
|
||||
...state,
|
||||
properties: { ...state.properties, daysOfWeek: state.properties.daysOfWeek.filter(day => day !== action.payload) }
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
// type Reducer = (state: Routine, action: RoutineReducerAction)=>Routine;
|
||||
// const routineReducer: Reducer = (state, action) => {
|
||||
// switch (action.type) {
|
||||
// case "NAME":
|
||||
// return { ...state, name: action.payload };
|
||||
// case "ADD_DAYS":
|
||||
// return {
|
||||
// ...state,
|
||||
// properties: { ...state.properties, daysOfWeek: [...state.properties.daysOfWeek, action.payload] }
|
||||
// };
|
||||
// case "DELETE_DAYS":
|
||||
// return {
|
||||
// ...state,
|
||||
// properties: { ...state.properties, daysOfWeek: state.properties.daysOfWeek.filter(day => day !== action.payload) }
|
||||
// };
|
||||
// default:
|
||||
// return state;
|
||||
// }
|
||||
// };
|
||||
|
||||
const defaultRoutine = {
|
||||
name: "new daily routine",
|
||||
properties: {
|
||||
order: 0,
|
||||
daysOfWeek: DAYS_OF_WEEK
|
||||
}
|
||||
}
|
||||
const AddRoutineModalComponent = memo(function AddRoutineModalComponent({ modal }: { modal: AddRoutineModal }) {
|
||||
const [routine, dispatch] = useReducer<Reducer>(routineReducer, defaultRoutine);
|
||||
// const defaultRoutine = {
|
||||
// name: "new daily routine",
|
||||
// properties: {
|
||||
// order: 0,
|
||||
// daysOfWeek: DAYS_OF_WEEK
|
||||
// }
|
||||
// }
|
||||
// const AddRoutineModalComponent = memo(function AddRoutineModalComponent({ modal }: { modal: AddRoutineModal }) {
|
||||
// const [routine, dispatch] = useReducer<Reducer>(routineReducer, defaultRoutine);
|
||||
|
||||
// 이름 수정
|
||||
const nameEditElRef = useRef<HTMLDivElement>(null);
|
||||
useEffect(() => {
|
||||
if(!nameEditElRef.current) return;
|
||||
const textComp = new TextComponent(nameEditElRef.current)
|
||||
.setValue(routine.name)
|
||||
.onChange((value) => {
|
||||
dispatch({type: "NAME", payload: value});
|
||||
});
|
||||
textComp.inputEl.focus();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
// // 이름 수정
|
||||
// const nameEditElRef = useRef<HTMLDivElement>(null);
|
||||
// useEffect(() => {
|
||||
// if(!nameEditElRef.current) return;
|
||||
// const textComp = new TextComponent(nameEditElRef.current)
|
||||
// .setValue(routine.name)
|
||||
// .onChange((value) => {
|
||||
// dispatch({type: "NAME", payload: value});
|
||||
// });
|
||||
// textComp.inputEl.focus();
|
||||
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// }, [])
|
||||
|
||||
// 루틴 생성
|
||||
const createNewRoutine = useCallback(() => {
|
||||
routineManager.create(routine);
|
||||
modal.close();
|
||||
}, [modal, routine]);
|
||||
// // 루틴 생성
|
||||
// const createNewRoutine = useCallback(() => {
|
||||
// routineManager.create(routine);
|
||||
// modal.close();
|
||||
// }, [modal, routine]);
|
||||
|
||||
// 요일 수정
|
||||
const onDaysChange = useCallback((action: "add" | "remove", day: DayOfWeek) => {
|
||||
if(action === "add"){
|
||||
dispatch({type: "ADD_DAYS", payload: day});
|
||||
} else {
|
||||
dispatch({type: "DELETE_DAYS", payload: day});
|
||||
}
|
||||
}, [])
|
||||
// // 요일 수정
|
||||
// const onDaysChange = useCallback((action: "add" | "remove", day: DayOfWeek) => {
|
||||
// if(action === "add"){
|
||||
// dispatch({type: "ADD_DAYS", payload: day});
|
||||
// } else {
|
||||
// dispatch({type: "DELETE_DAYS", payload: day});
|
||||
// }
|
||||
// }, [])
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h4>Add New Routine</h4>
|
||||
{/* Name */}
|
||||
<div className="dr-routine-option__section dr-routine-option-name">
|
||||
<h6>Name</h6>
|
||||
<div ref={nameEditElRef} />
|
||||
</div>
|
||||
{/* Days */}
|
||||
<DaysOption className="routine" getDays={() => routine.properties.daysOfWeek} onDaysChange={onDaysChange} />
|
||||
{/* Save */}
|
||||
<button onClick={() => createNewRoutine()}>Save</button>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
// return (
|
||||
// <div>
|
||||
// <h4>Add New Routine</h4>
|
||||
// {/* Name */}
|
||||
// <div className="dr-routine-option__section dr-routine-option-name">
|
||||
// <h6>Name</h6>
|
||||
// <div ref={nameEditElRef} />
|
||||
// </div>
|
||||
// {/* Days */}
|
||||
// <DaysOption className="routine" getDays={() => routine.properties.daysOfWeek} onDaysChange={onDaysChange} />
|
||||
// {/* Save */}
|
||||
// <button onClick={() => createNewRoutine()}>Save</button>
|
||||
// </div>
|
||||
// )
|
||||
// })
|
||||
104
src/features/routine/days-of-month-calendar-style.scss
Normal file
104
src/features/routine/days-of-month-calendar-style.scss
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
// 색상 변수
|
||||
$color-border: #a0a096;
|
||||
$color-disabled-bg: #f0f0f0;
|
||||
$color-disabled-text: #ababab;
|
||||
$color-disabled-neighbor: #cdcdcd;
|
||||
$color-hover-bg: #e6e6e6;
|
||||
|
||||
// 공통 스타일
|
||||
.react-calendar,
|
||||
.react-calendar *,
|
||||
.react-calendar *:before,
|
||||
.react-calendar *:after {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
// 마지막날짜 선택 버튼 타일
|
||||
.dr-days-of-month-option-calendar {
|
||||
&__last-day-tile {
|
||||
cursor: pointer;
|
||||
&--active {
|
||||
background-color: var(--color-accent-1) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// react-calendar 기본 스타일
|
||||
.dr-days-of-month-option-calendar .react-calendar {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
background: white;
|
||||
// border: 1px solid $color-border;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
line-height: 1.125em;
|
||||
|
||||
.react-calendar__tile {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
outline: none;
|
||||
background-color: transparent !important;
|
||||
&:enabled:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 요일
|
||||
.react-calendar__month-view__weekdays {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.dr-days-of-month-option-calendar .react-calendar__month-view__weekNumbers .react-calendar__tile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font: inherit;
|
||||
font-size: 0.75em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
// 날짜 타일 스타일
|
||||
.dr-days-of-month-option-calendar .react-calendar__month-view__days {
|
||||
gap: 0.5em 0;
|
||||
|
||||
&__day {
|
||||
position: relative;
|
||||
padding: 0 !important;
|
||||
box-shadow: none !important;
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
abbr {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
// 2, 3, 4일 타일
|
||||
.dr-days-of-month-option-calendar .react-calendar__month-view__days button:nth-child(32),
|
||||
.dr-days-of-month-option-calendar .react-calendar__month-view__days button:nth-child(33),
|
||||
.dr-days-of-month-option-calendar .react-calendar__month-view__days button:nth-child(34),
|
||||
.dr-days-of-month-option-calendar .react-calendar__month-view__days button:nth-child(35) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
// react-calendar 다른 모든 타일
|
||||
.dr-days-of-month-option-calendar .react-calendar__tile {
|
||||
max-width: 100%;
|
||||
height: 4em;
|
||||
padding: 1em;
|
||||
background: none;
|
||||
text-align: center;
|
||||
line-height: 1em;
|
||||
font: inherit;
|
||||
font-size: 0.7em;
|
||||
|
||||
&:hover {
|
||||
background-color: $color-hover-bg;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +1,3 @@
|
|||
import "./style.scss"
|
||||
export { openAddRoutineModal } from "./add-routine";
|
||||
export { openRoutineOptionModal } from "./routine-option";
|
||||
// export { openAddRoutineModal } from "./add-routine";
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { Routine, routineManager, RoutineProperties } from "entities/routine/routine";
|
||||
import { DayOfWeek } from "shared/day";
|
||||
/** @jsxImportSource @emotion/react */
|
||||
import { routineManager } from 'entities/routine';
|
||||
import { Routine, RoutineProperties } from 'entities/routine';
|
||||
import { Modal, Notice, TextComponent } from "obsidian";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { plugin } from "shared/plugin-service-locator";
|
||||
|
|
@ -7,6 +8,8 @@ import React from "react";
|
|||
import { createRoot } from "react-dom/client";
|
||||
import { DaysOption } from "./DaysOption";
|
||||
import { createStore, StoreApi, useStore } from "zustand";
|
||||
import { Button } from 'shared/components/Button';
|
||||
import { text } from 'stream/consumers';
|
||||
|
||||
|
||||
|
||||
|
|
@ -15,22 +18,64 @@ export const openRoutineOptionModal = (routine: Routine) => {
|
|||
}
|
||||
|
||||
|
||||
// routine option store
|
||||
interface RoutineOptionStore {
|
||||
original: Routine;
|
||||
routine: Routine;
|
||||
properties: RoutineProperties;
|
||||
updateProperties: (props: RoutineProperties) => void;
|
||||
renameRoutine: (newName: string) => void;
|
||||
setProperties: (props: RoutineProperties) => void;
|
||||
updateMutations: () => void;
|
||||
}
|
||||
const createRoutineOptionStore = (r: Routine): StoreApi<RoutineOptionStore> => createStore<RoutineOptionStore>((set, get) => ({
|
||||
|
||||
original: r,
|
||||
|
||||
routine: r,
|
||||
|
||||
renameRoutine: (newName) => {
|
||||
set({
|
||||
routine: {
|
||||
...get().routine,
|
||||
name: newName
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setProperties: (props) => {
|
||||
set({
|
||||
routine: {
|
||||
...get().routine,
|
||||
properties: props
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateMutations: () => {
|
||||
const originalName = get().original.name;
|
||||
const routine = get().routine;
|
||||
|
||||
// 이름 변경
|
||||
if(originalName !== routine.name && routine.name.trim() !== ""){
|
||||
routineManager.rename(originalName, routine.name);
|
||||
}
|
||||
|
||||
routineManager.editProperties(originalName, routine.properties);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
|
||||
// Modal Component
|
||||
class RoutineOptionModal extends Modal {
|
||||
#store: StoreApi<RoutineOptionStore>;
|
||||
|
||||
constructor(routine: Routine) {
|
||||
super(plugin().app);
|
||||
this.#store = createStore<RoutineOptionStore>((set) => ({
|
||||
routine: routine,
|
||||
properties: routine.properties,
|
||||
updateProperties: (props) => set({properties: props})
|
||||
}));
|
||||
|
||||
// zustand store
|
||||
this.#store = createRoutineOptionStore(routine);
|
||||
|
||||
// render react component
|
||||
const el = this.contentEl;
|
||||
createRoot(el).render(<RoutineOptionModalComponent modal={this} />);
|
||||
}
|
||||
|
|
@ -41,8 +86,7 @@ class RoutineOptionModal extends Modal {
|
|||
|
||||
// 닫힐 때 저장
|
||||
override onClose(): void {
|
||||
const { routine, properties} = this.#store.getState();
|
||||
routineManager.editProperties(routine.name, properties);
|
||||
this.#store.getState().updateMutations();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,32 +96,41 @@ interface RoutineOptionModalProps {
|
|||
modal: RoutineOptionModal;
|
||||
}
|
||||
const RoutineOptionModalComponent = React.memo(function RoutineOptionModalComponent({ modal }: RoutineOptionModalProps){
|
||||
// Modal과 상태를 공유하기 위한 store
|
||||
const { properties, routine, updateProperties } = useStore(modal.store);
|
||||
// option store
|
||||
const { routine, renameRoutine, updateMutations, setProperties } = useStore(modal.store);
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// 이름 수정
|
||||
const nameEditElRef = useRef<HTMLDivElement>(null);
|
||||
// 이름 편집 모드 상태
|
||||
const [nameEditMode, setNameEditMode] = useState<"edit" | "idle">("idle");
|
||||
|
||||
// 이름 편집 input ref
|
||||
const nameEditRef = useRef<HTMLDivElement>(null);
|
||||
const [name, setName] = useState(routine.name);
|
||||
// 이름 저장 콜백
|
||||
const onSaveRoutineName = useCallback(() => {
|
||||
routineManager.rename(routine.name, name);
|
||||
}, [name, routine.name]);
|
||||
// 이름 변경 input 컴포넌트
|
||||
useEffect(() => {
|
||||
if(!nameEditElRef.current) return;
|
||||
const textComp = new TextComponent(nameEditElRef.current)
|
||||
if(!nameEditRef.current) return;
|
||||
const textComp = new TextComponent(nameEditRef.current)
|
||||
.setValue(name)
|
||||
.onChange((value) => setName(value))
|
||||
textComp.inputEl.addEventListener('keydown', (e) => { if(e.key === 'Enter') onSaveRoutineName() });
|
||||
.onChange((value) => setName(value));
|
||||
textComp.inputEl.focus();
|
||||
|
||||
// @ts-ignore
|
||||
const enterKeyDown = (e: KeyboardEvent) => { if(e.key === "Enter") onDoneNameEditDoneClick(e.currentTarget.value);};
|
||||
textComp.inputEl.addEventListener("keydown", enterKeyDown)
|
||||
return () => {
|
||||
textComp.inputEl.removeEventListener("keydown", enterKeyDown);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
}, [nameEditMode]); // 한번만 렌더링 해야함
|
||||
|
||||
// 편집 완료 버튼 클릭시
|
||||
const onDoneNameEditDoneClick = useCallback((newName: string) => {
|
||||
setNameEditMode("idle")
|
||||
renameRoutine(newName);
|
||||
}, [renameRoutine]);
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// 삭제
|
||||
/**
|
||||
* 삭제 버튼 클릭시 confirm modal을 띄우고, 확인시 루틴을 삭제한다.
|
||||
*/
|
||||
const onDeleteBtnClick = useCallback((e: React.MouseEvent) => {
|
||||
const confirmModal = new Modal(plugin().app);
|
||||
confirmModal.modalEl.addClass('dr-routine-option-delete-modal');
|
||||
|
|
@ -90,7 +143,9 @@ const RoutineOptionModalComponent = React.memo(function RoutineOptionModalCompon
|
|||
<div>
|
||||
<button className="dr-routine-option-delete-modal__cancel" onClick={() => confirmModal.close()}>Cancel</button>
|
||||
<button className="dr-routine-option-delete-modal__confirm" onClick={() => {
|
||||
// 실제로 루틴 삭제
|
||||
routineManager.delete(routine.name);
|
||||
// 모달 닫고 알림 띄우기
|
||||
confirmModal.close();
|
||||
modal.close();
|
||||
new Notice(`Routine ${routine.name} deleted.`);
|
||||
|
|
@ -104,48 +159,33 @@ const RoutineOptionModalComponent = React.memo(function RoutineOptionModalCompon
|
|||
}, [modal, routine.name])
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
// 요일 변경
|
||||
const onDaysChange = useCallback((action: "add" | "remove", day: DayOfWeek) => {
|
||||
const days = properties.daysOfWeek;
|
||||
if(action === "add"){
|
||||
updateProperties({
|
||||
...properties,
|
||||
daysOfWeek: [...days, day]
|
||||
});
|
||||
} else {
|
||||
updateProperties({
|
||||
...properties,
|
||||
daysOfWeek: days.filter(d => d !== day)
|
||||
});
|
||||
}
|
||||
}, [properties, updateProperties])
|
||||
|
||||
|
||||
///////////////////////////
|
||||
// 컴포넌트
|
||||
if(!routine) return <div>Loading...</div>
|
||||
return (
|
||||
<div className="dr-routine-option">
|
||||
{/* 헤더 */}
|
||||
<div className="dr-routine-option__header">
|
||||
<h4>{routine.name}</h4>
|
||||
|
||||
{nameEditMode === "idle" && (<>
|
||||
<div>{routine.name}</div>
|
||||
<button onClick={() => setNameEditMode("edit")}>Edit</button>
|
||||
</>)}
|
||||
|
||||
{nameEditMode === "edit" && (<>
|
||||
<div ref={nameEditRef} />
|
||||
<button onClick={()=>onDoneNameEditDoneClick(name)}>Done</button>
|
||||
</>)}
|
||||
|
||||
</div>
|
||||
|
||||
{/* 본문 */}
|
||||
<section>
|
||||
{/* 이름 */}
|
||||
<div className="dr-routine-option__section dr-routine-option-name">
|
||||
<h6>Name</h6>
|
||||
<div ref={nameEditElRef} />
|
||||
<button onClick={onSaveRoutineName}>Save</button>
|
||||
</div>
|
||||
{/* 요일 */}
|
||||
<DaysOption getDays={() => properties.daysOfWeek} onDaysChange={onDaysChange}/>
|
||||
{/* daysOfWeek OR daysOfMonth */}
|
||||
<DaysOption properties={routine.properties} setProperties={setProperties} />
|
||||
{/* 삭제 */}
|
||||
<div className="dr-routine-option__section dr-routine-option-delete">
|
||||
<h6>Delete The Routine</h6>
|
||||
<button onClick={onDeleteBtnClick}>Delete</button>
|
||||
<Button variant='danger' onClick={onDeleteBtnClick}>Delete</Button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { setPlugin } from './shared/plugin-service-locator';
|
|||
import { DailyRoutinePluginSettings, DailyRoutineSettingTab, DEFAULT_SETTINGS } from './settings/DailyRoutineSettingTab';
|
||||
import { DailyRoutineObsidianView } from './app';
|
||||
import { activateView } from './shared/view/activate-view';
|
||||
import { openRoutineOptionModal } from 'features/routine';
|
||||
import { routineManager } from 'entities/routine';
|
||||
|
||||
export default class DailyRoutinePlugin extends Plugin {
|
||||
settings: DailyRoutinePluginSettings;
|
||||
|
|
@ -29,6 +31,10 @@ export default class DailyRoutinePlugin extends Plugin {
|
|||
// @ts-ignore
|
||||
this.app.emulateMobile(!this.app.isMobile);
|
||||
});
|
||||
|
||||
setTimeout(async() => {
|
||||
openRoutineOptionModal(await routineManager.get("🖊️ 공식문서 작성"));
|
||||
}, 100);
|
||||
}
|
||||
|
||||
onunload() {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { loadOrCreateRoutineNote } from "entities/utils";
|
||||
import { RoutineNote as RoutineNoteEntity, routineNoteService } from "entities/routine-note";
|
||||
import { openAddRoutineModal } from "features/routine";
|
||||
import { DaysNav } from "features/days/DaysNav";
|
||||
// import { openAddRoutineModal } from "features/routine";
|
||||
import { DaysNav } from "features/days";
|
||||
import { useDaysNav } from "features/days";
|
||||
import { TaskList } from "widgets/tasks";
|
||||
/////////////////////
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Day } from "shared/day";
|
||||
import "./routine-note.scss";
|
||||
import { TaskList } from "widgets/tasks";
|
||||
|
||||
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ export const RoutineNote = ({ day: propsDay }: RoutineNoteProps) => {
|
|||
////////////////////////////////////////
|
||||
// routine 추가 버튼 콜백
|
||||
const onAddRoutineBtnClick = useCallback(() => {
|
||||
openAddRoutineModal();
|
||||
// openAddRoutineModal();
|
||||
}, []);
|
||||
|
||||
|
||||
|
|
|
|||
28
src/shared/components/Button.tsx
Normal file
28
src/shared/components/Button.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/** @jsxImportSource @emotion/react */
|
||||
import styled from "@emotion/styled";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
interface ButtonProps {
|
||||
variant?: "primary" | "danger";
|
||||
width?: string;
|
||||
height?: string;
|
||||
fontSize?: string;
|
||||
}
|
||||
export const Button = styled.button<ButtonProps>`
|
||||
cursor: pointer;
|
||||
${p => p.width ? `width: ${p.width};` : ""}
|
||||
${p => p.height ? `height: ${p.height};` : ""}
|
||||
${p => p.fontSize ? `font-size: ${p.fontSize};` : ""}
|
||||
color: ${p => {
|
||||
const variant = p.variant??'primary';
|
||||
switch(p.variant){
|
||||
case "primary": return "black";
|
||||
case "danger": return "var(--color-red)";
|
||||
}
|
||||
}}
|
||||
`;
|
||||
|
|
@ -35,12 +35,12 @@ const Circle = ({ color, percentage, transition=true }: CircleProps) => {
|
|||
);
|
||||
};
|
||||
|
||||
interface PerCentageCircleProps {
|
||||
interface PercentageCircleProps {
|
||||
percentage: number;
|
||||
text: string;
|
||||
transition?: boolean;
|
||||
}
|
||||
export const PerCentageCircle = ({ percentage, text, transition=true }: PerCentageCircleProps) => {
|
||||
export const PercentageCircle = ({ percentage, text, transition=true }: PercentageCircleProps) => {
|
||||
const pct = cleanPercentage(percentage);
|
||||
const color = pct > 70 ? "hsla(var(--color-accent-1-hsl), 1)" : "hsla(var(--color-accent-2-hsl), 1)";
|
||||
return (
|
||||
|
|
|
|||
14
src/shared/daily-routine-bem.ts
Normal file
14
src/shared/daily-routine-bem.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import BEMHelper, { WordSet } from "react-bem-helper"
|
||||
|
||||
|
||||
type DailyRoutineBEM = (element?: string, modifiers?: WordSet, extra?: WordSet) => string;
|
||||
export const dr = (name: string): DailyRoutineBEM => {
|
||||
const ben = new BEMHelper({
|
||||
prefix: "dr-",
|
||||
name: name,
|
||||
})
|
||||
|
||||
return (element?: string, modifiers?: WordSet, extra?: WordSet) => {
|
||||
return ben(element, modifiers, extra).className;
|
||||
}
|
||||
}
|
||||
|
|
@ -33,7 +33,6 @@ export class Day {
|
|||
static now(): Day{
|
||||
return new Day(moment());
|
||||
}
|
||||
|
||||
format(format: string){
|
||||
return this.#moment.format(format);
|
||||
}
|
||||
|
|
|
|||
229
styles.css
229
styles.css
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue