diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/.gitignore b/yongjae/projects/FEDC5-3_VanillaJS_1/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/index.html b/yongjae/projects/FEDC5-3_VanillaJS_1/index.html new file mode 100644 index 0000000..3f32d0c --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/index.html @@ -0,0 +1,13 @@ + + + + + + + TS Todo + + +
+ + + diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/package-lock.json b/yongjae/projects/FEDC5-3_VanillaJS_1/package-lock.json new file mode 100644 index 0000000..cffe8f2 --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/package-lock.json @@ -0,0 +1,732 @@ +{ + "name": "fedc5-3-vanillajs-1", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "fedc5-3-vanillajs-1", + "version": "0.0.0", + "devDependencies": { + "typescript": "^5.2.2", + "vite": "^5.0.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.8.tgz", + "integrity": "sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz", + "integrity": "sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.8.tgz", + "integrity": "sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz", + "integrity": "sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz", + "integrity": "sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz", + "integrity": "sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz", + "integrity": "sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz", + "integrity": "sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz", + "integrity": "sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz", + "integrity": "sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz", + "integrity": "sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz", + "integrity": "sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz", + "integrity": "sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz", + "integrity": "sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz", + "integrity": "sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz", + "integrity": "sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz", + "integrity": "sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz", + "integrity": "sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz", + "integrity": "sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz", + "integrity": "sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz", + "integrity": "sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz", + "integrity": "sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.6.1.tgz", + "integrity": "sha512-0WQ0ouLejaUCRsL93GD4uft3rOmB8qoQMU05Kb8CmMtMBe7XUDLAltxVZI1q6byNqEtU7N1ZX1Vw5lIpgulLQA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.6.1.tgz", + "integrity": "sha512-1TKm25Rn20vr5aTGGZqo6E4mzPicCUD79k17EgTLAsXc1zysyi4xXKACfUbwyANEPAEIxkzwue6JZ+stYzWUTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.6.1.tgz", + "integrity": "sha512-cEXJQY/ZqMACb+nxzDeX9IPLAg7S94xouJJCNVE5BJM8JUEP4HeTF+ti3cmxWeSJo+5D+o8Tc0UAWUkfENdeyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.6.1.tgz", + "integrity": "sha512-LoSU9Xu56isrkV2jLldcKspJ7sSXmZWkAxg7sW/RfF7GS4F5/v4EiqKSMCFbZtDu2Nc1gxxFdQdKwkKS4rwxNg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.6.1.tgz", + "integrity": "sha512-EfI3hzYAy5vFNDqpXsNxXcgRDcFHUWSx5nnRSCKwXuQlI5J9dD84g2Usw81n3FLBNsGCegKGwwTVsSKK9cooSQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.6.1.tgz", + "integrity": "sha512-9lhc4UZstsegbNLhH0Zu6TqvDfmhGzuCWtcTFXY10VjLLUe4Mr0Ye2L3rrtHaDd/J5+tFMEuo5LTCSCMXWfUKw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.6.1.tgz", + "integrity": "sha512-FfoOK1yP5ksX3wwZ4Zk1NgyGHZyuRhf99j64I5oEmirV8EFT7+OhUZEnP+x17lcP/QHJNWGsoJwrz4PJ9fBEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.6.1.tgz", + "integrity": "sha512-DNGZvZDO5YF7jN5fX8ZqmGLjZEXIJRdJEdTFMhiyXqyXubBa0WVLDWSNlQ5JR2PNgDbEV1VQowhVRUh+74D+RA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.6.1.tgz", + "integrity": "sha512-RkJVNVRM+piYy87HrKmhbexCHg3A6Z6MU0W9GHnJwBQNBeyhCJG9KDce4SAMdicQnpURggSvtbGo9xAWOfSvIQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.6.1.tgz", + "integrity": "sha512-v2FVT6xfnnmTe3W9bJXl6r5KwJglMK/iRlkKiIFfO6ysKs0rDgz7Cwwf3tjldxQUrHL9INT/1r4VA0n9L/F1vQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.6.1.tgz", + "integrity": "sha512-YEeOjxRyEjqcWphH9dyLbzgkF8wZSKAKUkldRY6dgNR5oKs2LZazqGB41cWJ4Iqqcy9/zqYgmzBkRoVz3Q9MLw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.6.1.tgz", + "integrity": "sha512-0zfTlFAIhgz8V2G8STq8toAjsYYA6eci1hnXuyOTUFnymrtJwnS6uGKiv3v5UrPZkBlamLvrLV2iiaeqCKzb0A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/esbuild": { + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.8.tgz", + "integrity": "sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.19.8", + "@esbuild/android-arm64": "0.19.8", + "@esbuild/android-x64": "0.19.8", + "@esbuild/darwin-arm64": "0.19.8", + "@esbuild/darwin-x64": "0.19.8", + "@esbuild/freebsd-arm64": "0.19.8", + "@esbuild/freebsd-x64": "0.19.8", + "@esbuild/linux-arm": "0.19.8", + "@esbuild/linux-arm64": "0.19.8", + "@esbuild/linux-ia32": "0.19.8", + "@esbuild/linux-loong64": "0.19.8", + "@esbuild/linux-mips64el": "0.19.8", + "@esbuild/linux-ppc64": "0.19.8", + "@esbuild/linux-riscv64": "0.19.8", + "@esbuild/linux-s390x": "0.19.8", + "@esbuild/linux-x64": "0.19.8", + "@esbuild/netbsd-x64": "0.19.8", + "@esbuild/openbsd-x64": "0.19.8", + "@esbuild/sunos-x64": "0.19.8", + "@esbuild/win32-arm64": "0.19.8", + "@esbuild/win32-ia32": "0.19.8", + "@esbuild/win32-x64": "0.19.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/postcss": { + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.6.1.tgz", + "integrity": "sha512-jZHaZotEHQaHLgKr8JnQiDT1rmatjgKlMekyksz+yk9jt/8z9quNjnKNRoaM0wd9DC2QKXjmWWuDYtM3jfF8pQ==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.6.1", + "@rollup/rollup-android-arm64": "4.6.1", + "@rollup/rollup-darwin-arm64": "4.6.1", + "@rollup/rollup-darwin-x64": "4.6.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.6.1", + "@rollup/rollup-linux-arm64-gnu": "4.6.1", + "@rollup/rollup-linux-arm64-musl": "4.6.1", + "@rollup/rollup-linux-x64-gnu": "4.6.1", + "@rollup/rollup-linux-x64-musl": "4.6.1", + "@rollup/rollup-win32-arm64-msvc": "4.6.1", + "@rollup/rollup-win32-ia32-msvc": "4.6.1", + "@rollup/rollup-win32-x64-msvc": "4.6.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.6.tgz", + "integrity": "sha512-MD3joyAEBtV7QZPl2JVVUai6zHms3YOmLR+BpMzLlX2Yzjfcc4gTgNi09d/Rua3F4EtC8zdwPU8eQYyib4vVMQ==", + "dev": true, + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.32", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + } + } +} diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/package.json b/yongjae/projects/FEDC5-3_VanillaJS_1/package.json new file mode 100644 index 0000000..d35041d --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/package.json @@ -0,0 +1,15 @@ +{ + "name": "fedc5-3-vanillajs-1", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "devDependencies": { + "typescript": "^5.2.2", + "vite": "^5.0.0" + } +} diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/public/vite.svg b/yongjae/projects/FEDC5-3_VanillaJS_1/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/App.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/App.ts new file mode 100644 index 0000000..9cf336a --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/App.ts @@ -0,0 +1,64 @@ +import { AppProps } from "../types/components"; +import { Todos } from "../types/states"; +import { setItem } from "../utils/storage"; +import { validateState } from "../utils/validateState"; +import Header from "./Header"; +import TodoCount from "./TodoCount"; +import TodoForm from "./TodoForm"; +import TodoList from "./TodoList"; + +interface AppContext {} +const App = function (this: AppContext, { $target, initialState }: AppProps) { + // ... + initialState = validateState(initialState); + + const syncState = (state: Todos) => { + const validatedState = validateState(state); + todoList.setState(validatedState); + todoCount.setState(validatedState); + }; + new Header({ + $target, + text: "Renewed Todo List", + }); + + new TodoForm({ + $target, + onSubmit: (text: string) => { + const nextState = [ + ...todoList.state, + { id: String(Date.now()), text, isCompleted: false }, + ]; + + syncState(nextState); + + setItem("todos", nextState); + }, + }); + + const todoList = new TodoList({ + $target, + initialState, + onToggle: (todoId: string) => { + const nextState = todoList.state.map((todo) => { + if (todo.id === todoId) todo.isCompleted = !todo.isCompleted; + return todo; + }); + syncState(nextState); + }, + onDelete: (todoId: string) => { + const nextState = todoList.state.filter((todo) => { + if (todo.id === todoId) return false; + return true; + }); + syncState(nextState); + }, + }); + + const todoCount = new TodoCount({ + $target, + initialState, + }); +} as any as { new (props: AppProps): AppContext }; + +export default App; diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/Header.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/Header.ts new file mode 100644 index 0000000..d2f1b47 --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/Header.ts @@ -0,0 +1,21 @@ +import { + HeaderProps, + TodoComponentStatelessContext, +} from "../types/components"; + +const Header = function ( + this: TodoComponentStatelessContext, + { $target, text }: HeaderProps +) { + const $header = document.createElement("h1"); + + $target.appendChild($header); + + this.render = () => { + $header.textContent = text; + }; + + this.render(); +} as any as { new (props: HeaderProps): TodoComponentStatelessContext }; + +export default Header; diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoCount.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoCount.ts new file mode 100644 index 0000000..8fd4d98 --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoCount.ts @@ -0,0 +1,35 @@ +import { + TodoComponentStatefulContext, + TodoCountProps, +} from "../types/components"; +import { Todos } from "../types/states"; + +const TodoCount = function ( + this: TodoComponentStatefulContext, + { $target, initialState }: TodoCountProps +) { + this.state = initialState; + + const $todoCount = document.createElement("h3"); + $target.appendChild($todoCount); + + this.setState = (nextState: Todos) => { + this.state = nextState; + this.render(); + }; + + this.render = () => { + const completedNum = this.state.filter( + ({ isCompleted }) => isCompleted + ).length; + + const totalNum = this.state.length; + $todoCount.innerHTML = `${completedNum} / ${totalNum}`; + }; + + this.render(); +} as any as { + new (props: TodoCountProps): TodoComponentStatefulContext; +}; + +export default TodoCount; diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoForm.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoForm.ts new file mode 100644 index 0000000..bbaa05c --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoForm.ts @@ -0,0 +1,42 @@ +import { + TodoComponentStatelessContext, + TodoFormProps, +} from "../types/components"; + +const TodoForm = function ( + this: TodoComponentStatelessContext, + { $target, onSubmit }: TodoFormProps +) { + const $form = document.createElement("form"); + let isInit = false; + $target.appendChild($form); + + this.render = () => { + $form.innerHTML = ` + + `; + if (!isInit) { + $form.addEventListener("submit", (e) => { + e.preventDefault(); + + const $todo = $form.querySelector(`input[name=todo]`); + + let text = ""; + if ($todo && $todo.value) { + text = $todo.value; + } + + if (text.length > 1 && text.trim()) { + if ($todo) { + $todo.value = ""; + onSubmit(text); + } + } + }); + } + }; + + this.render(); +} as any as { new (props: TodoFormProps): TodoComponentStatelessContext }; + +export default TodoForm; diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoItem.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoItem.ts new file mode 100644 index 0000000..0118e2f --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoItem.ts @@ -0,0 +1,32 @@ +import { + TodoComponentStatelessContext, + TodoItemProps, +} from "../types/components"; + +const TodoItem = function ( + this: TodoComponentStatelessContext, + { $target, initialValue, onToggle, onDelete }: TodoItemProps +) { + const { id, text, isCompleted } = initialValue; + + const $todoItem = document.createElement("li"); + $todoItem.textContent = text; + $todoItem.style.textDecoration = isCompleted ? "line-through" : "none"; + const $todoButton = document.createElement("button"); + $todoButton.textContent = "삭제"; + + $todoItem.appendChild($todoButton); + $target.appendChild($todoItem); + + this.render = () => { + $todoButton.addEventListener("click", () => { + onDelete(id); + }); + $todoItem.addEventListener("click", () => { + onToggle(id); + }); + }; + this.render(); +} as any as { new (props: TodoItemProps): TodoComponentStatelessContext }; + +export default TodoItem; diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoList.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoList.ts new file mode 100644 index 0000000..f0e833c --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/components/TodoList.ts @@ -0,0 +1,39 @@ +import { + TodoComponentStatefulContext, + TodoListProps, +} from "../types/components"; +import { Todos } from "../types/states"; +import { setItem } from "../utils/storage"; +import TodoItem from "./TodoItem"; + +const TodoList = function ( + this: TodoComponentStatefulContext, + { initialState, $target, onToggle, onDelete }: TodoListProps +) { + this.state = initialState; + + const $todoList = document.createElement("ul"); + $target.appendChild($todoList); + + this.setState = (nextState: Todos) => { + this.state = nextState; + setItem("todos", this.state); + this.render(); + }; + + this.render = () => { + $todoList.innerHTML = ""; + this.state.map( + (itemContext) => + new TodoItem({ + $target: $todoList, + initialValue: itemContext, + onToggle, + onDelete, + }) + ); + }; + this.render(); +} as any as { new (props: TodoListProps): TodoComponentStatefulContext }; + +export default TodoList; diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/constants.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/constants.ts new file mode 100644 index 0000000..f9c8627 --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/constants.ts @@ -0,0 +1,14 @@ +export const STORAGE_KEY = "todos"; + +const KNOWN_ERROR_MESSAGES = { + invalidState: "올바르지 않은 상태 형식입니다", +}; + +export const ERROR_MESSAGES = new Proxy(KNOWN_ERROR_MESSAGES, { + get: function (target: { [key: string]: string }, prop: string) { + if (prop.length < 1) { + return "알 수 없는 에러입니다."; + } + return target[prop] ?? prop; + }, +}); diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/main.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/main.ts new file mode 100644 index 0000000..75b21cd --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/main.ts @@ -0,0 +1,11 @@ +import { getItem } from "./utils/storage"; +import App from "./components/App.ts"; + +const initialState = getItem("todos", []); + +const $app = document.querySelector("#app")!; + +new App({ + $target: $app, + initialState, +}); diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/types/components.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/types/components.ts new file mode 100644 index 0000000..d4160e0 --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/types/components.ts @@ -0,0 +1,46 @@ +import { Todo, Todos } from "./states"; +// 컴포넌트 구조 typing +// 컴포넌트 Context + +export type TodoComponentContext = { + state?: Todos; + setState?: (nextState: Todos) => void; + render: () => void; +}; +export type TodoComponentStatefulContext = { + [K in keyof TodoComponentContext]-?: TodoComponentContext[K]; +}; + +export type TodoComponentStatelessContext = Omit< + TodoComponentContext, + "state" | "setState" +>; + +// 컴포넌트 Props +export interface CoreComponentProps { + $target: HTMLElement; +} + +interface TodoStatefulComponentProps extends CoreComponentProps { + initialState: Todos; +} +export interface TodoItemProps extends CoreComponentProps { + initialValue: Todo; + onToggle: (id: string) => void; + onDelete: (id: string) => void; +} +export interface TodoListProps extends TodoStatefulComponentProps { + onToggle: (id: string) => void; + onDelete: (id: string) => void; +} + +export interface TodoCountProps extends TodoStatefulComponentProps {} + +export interface TodoFormProps extends CoreComponentProps { + onSubmit: (text: string) => void; +} + +export interface AppProps extends TodoStatefulComponentProps {} +export interface HeaderProps extends CoreComponentProps { + text: string; +} diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/types/states.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/types/states.ts new file mode 100644 index 0000000..f20587b --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/types/states.ts @@ -0,0 +1,6 @@ +export interface Todo { + text: string; + id: string; + isCompleted: boolean; +} +export type Todos = Todo[]; diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/typescript.svg b/yongjae/projects/FEDC5-3_VanillaJS_1/src/typescript.svg new file mode 100644 index 0000000..d91c910 --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/typescript.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/utils/storage.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/utils/storage.ts new file mode 100644 index 0000000..3f77718 --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/utils/storage.ts @@ -0,0 +1,32 @@ +import { ERROR_MESSAGES } from "../constants"; +import { Todos } from "../types/states"; + +export type setStorage = (key: string, value: T) => void; +export type getStorage = (key: string, defaultValue: T) => T; + +const storage = window.localStorage; + +export const setItem: setStorage = (key: string, value: Todos) => { + try { + storage.setItem(key, JSON.stringify(value)); + } catch (e: unknown) { + if (e instanceof Error) { + console.warn(ERROR_MESSAGES[e.message]); + } + } +}; + +export const getItem: getStorage = (key: string, defaultValue = []) => { + try { + const storedValue = storage.getItem(key); + if (storedValue) { + return JSON.parse(storedValue); + } + return defaultValue; + } catch (e: unknown) { + if (e instanceof Error) { + console.warn(ERROR_MESSAGES[e.message]); + return defaultValue; + } + } +}; diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/utils/validateState.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/utils/validateState.ts new file mode 100644 index 0000000..48089c3 --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/utils/validateState.ts @@ -0,0 +1,45 @@ +import { ERROR_MESSAGES } from "../constants"; +import { Todos } from "../types/states"; +// todo 상태의 유효검사 함수 +export function validateState(state: Todos, origin: Todos = []) { + if ( + Array.isArray(state) && + state.every( + (val) => + val && + Object.hasOwn(val, "text") && + val.text.split(" ").join("").length && + Object.hasOwn(val, "isCompleted") && + typeof val.isCompleted === "boolean" && + Object.hasOwn(val, "id") && + typeof val.id === "string" + ) + ) { + return state; + } + console.warn(ERROR_MESSAGES["invalidState"]); + return origin; +} + +export function filterValidStorageState( + state: Todos, + defaultState: Todos = [] +) { + try { + return state.filter( + (val) => + val && + Object.hasOwn(val, "text") && + val.text.split(" ").join("").length && + Object.hasOwn(val, "isCompleted") && + typeof val.isCompleted === "boolean" && + Object.hasOwn(val, "id") && + typeof val.id === "string" + ); + } catch (e) { + if (e instanceof Error) { + console.warn(ERROR_MESSAGES[e.message]); + } + return defaultState; + } +} diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/src/vite-env.d.ts b/yongjae/projects/FEDC5-3_VanillaJS_1/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/yongjae/projects/FEDC5-3_VanillaJS_1/tsconfig.json b/yongjae/projects/FEDC5-3_VanillaJS_1/tsconfig.json new file mode 100644 index 0000000..f28fcc0 --- /dev/null +++ b/yongjae/projects/FEDC5-3_VanillaJS_1/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +}