diff --git a/.gitignore b/.gitignore index cce881f09..ff34c2007 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ yarn-error.log* # local env files .env*.local +.env # vercel .vercel diff --git a/next.config.js b/next.config.js new file mode 100644 index 000000000..32b465c55 --- /dev/null +++ b/next.config.js @@ -0,0 +1,16 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + images: { + formats: ["image/webp", "image/avif"], + remotePatterns: [ + { + protocol: "https", + hostname: "**", + port: "", + }, + ], + }, +}; + +module.exports = nextConfig; diff --git a/package-lock.json b/package-lock.json index 6b1d261da..c38ec6c16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,15 @@ "name": "4-weekly-mission", "version": "0.1.0", "dependencies": { - "next": "14.1.4", + "@nextui-org/skeleton": "^2.0.27", + "@tanstack/react-query": "^5.35.1", + "@tanstack/react-query-devtools": "^5.35.1", + "classnames": "^2.5.1", + "next": "13.5.6", "react": "^18", "react-dom": "^18", - "react-hook-form": "^7.51.2", - "usehooks-ts": "^3.1.0" + "react-hook-form": "^7.51.4", + "sass": "^1.76.0" }, "devDependencies": { "@types/node": "^20", @@ -33,11 +37,22 @@ "node": ">=0.10.0" } }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@babel/runtime": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", - "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", - "dev": true, + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", + "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -138,6 +153,103 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "peer": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "peer": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "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==", + "peer": true, + "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==", + "peer": true, + "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==", + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "peer": true + }, + "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==", + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@next/env": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.6.tgz", + "integrity": "sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw==" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.6.tgz", + "integrity": "sha512-ng7pU/DDsxPgT6ZPvuprxrkeew3XaRf4LAT4FabaEO/hAbvVx4P7wqnqdbTdDn1kgTvsI4tpIgT4Awn/m0bGbg==", "dev": true, "dependencies": { "string-width": "^5.1.2", @@ -327,11 +439,107 @@ "node": ">= 10" } }, + "node_modules/@nextui-org/react-rsc-utils": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@nextui-org/react-rsc-utils/-/react-rsc-utils-2.0.12.tgz", + "integrity": "sha512-s2IG4pM1K+kbm6A2g3UpqrS592AExpGixtZNPJ2lV5+UQi1ld3vb4EiBIOViZMoSCNCoNdaeO5Yqo6cKghwCPA==" + }, + "node_modules/@nextui-org/react-utils": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@nextui-org/react-utils/-/react-utils-2.0.13.tgz", + "integrity": "sha512-4DM1Cph1lVY64T/HDyEqcxYkInXx6hdL1Kp9StLza9yqgYmVipTaPkWZdmWbfkhP+dVVqrH3DVFfHtpLTQ625w==", + "dependencies": { + "@nextui-org/react-rsc-utils": "2.0.12", + "@nextui-org/shared-utils": "2.0.5" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/shared-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nextui-org/shared-utils/-/shared-utils-2.0.5.tgz", + "integrity": "sha512-aFc/CUL8RVfBh0IotIpxkpKjyUPc/zJaMJd5pRCQA1kIpKLdSrlh3//MLYMaP/fo/NQtE3DPeXqfKhHRr1fkEw==" + }, + "node_modules/@nextui-org/skeleton": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/@nextui-org/skeleton/-/skeleton-2.0.27.tgz", + "integrity": "sha512-AolxdzJ4xCyb7i2DwZ1iQGSaLGUBYh/rorO8llBqsXDpvhBANcFF3DbRO3kQ+EVGr5AEbEeurd3RabC2F6wVDA==", + "dependencies": { + "@nextui-org/react-utils": "2.0.13", + "@nextui-org/shared-utils": "2.0.5", + "@nextui-org/system-rsc": "2.1.1" + }, + "peerDependencies": { + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/system-rsc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@nextui-org/system-rsc/-/system-rsc-2.1.1.tgz", + "integrity": "sha512-gkTKNAbTZVl81SVJsaLHp4iqyd956y40UIGUXPeq0pwOGLM0xGWSkLbkNT8WtdPUt3bSD9y0xuKbiV3tpSBGOA==", + "dependencies": { + "clsx": "^1.2.1" + }, + "peerDependencies": { + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "tailwind-variants": ">=0.1.13" + } + }, + "node_modules/@nextui-org/theme": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@nextui-org/theme/-/theme-2.2.3.tgz", + "integrity": "sha512-p8gZ+4dQxA4ZO9RxVljAs37EYtQsw0n9DtXD6f395gpl0DLKRq/d4oCQ887oC6lHDyTibtaHHtOu+MKzK6j7Gw==", + "peer": true, + "dependencies": { + "color": "^4.2.3", + "color2k": "^2.0.2", + "deepmerge": "4.3.1", + "flat": "^5.0.2", + "lodash.foreach": "^4.5.0", + "lodash.get": "^4.4.2", + "lodash.kebabcase": "^4.1.1", + "lodash.mapkeys": "^4.6.0", + "lodash.omit": "^4.5.0", + "tailwind-variants": "^0.1.20" + }, + "peerDependencies": { + "tailwindcss": ">=3.4.0" + } + }, + "node_modules/@nextui-org/theme/node_modules/tailwind-merge": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz", + "integrity": "sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/@nextui-org/theme/node_modules/tailwind-variants": { + "version": "0.1.20", + "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-0.1.20.tgz", + "integrity": "sha512-AMh7x313t/V+eTySKB0Dal08RHY7ggYK0MSn/ad8wKWOrDUIzyiWNayRUm2PIJ4VRkvRnfNuyRuKbLV3EN+ewQ==", + "peer": true, + "dependencies": { + "tailwind-merge": "^1.14.0" + }, + "engines": { + "node": ">=16.x", + "pnpm": ">=7.x" + }, + "peerDependencies": { + "tailwindcss": "*" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -344,7 +552,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -353,7 +560,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -366,8 +572,8 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "optional": true, + "peer": true, "engines": { "node": ">=14" } @@ -386,6 +592,55 @@ "tslib": "^2.4.0" } }, + "node_modules/@tanstack/query-core": { + "version": "5.35.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.35.1.tgz", + "integrity": "sha512-0Dnpybqb8+ps6WgqBnqFEC+1F/xLvUosRAq+wiGisTgolOZzqZfkE2995dEXmhuzINiTM7/a6xSGznU0NIvBkw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-devtools": { + "version": "5.32.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.32.1.tgz", + "integrity": "sha512-7Xq57Ctopiy/4atpb0uNY5VRuCqRS/1fi/WBCKKX6jHMa6cCgDuV/AQuiwRXcKARbq2OkVAOrW2v4xK9nTbcCA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.35.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.35.1.tgz", + "integrity": "sha512-i2T7m2ffQdNqlX3pO+uMsnQ0H4a59Ens2GxtlMsRiOvdSB4SfYmHb27MnvFV8rGmtWRaa4gPli0/rpDoSS5LbQ==", + "dependencies": { + "@tanstack/query-core": "5.35.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "5.35.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.35.1.tgz", + "integrity": "sha512-G2TP8ekCo+C9IPdEswKB9mqG5pxV+DWq86lmNw/VbUpdyNwNFvKi7GdcqW1pLDi5al+zifSjGSO7QZ7zDMJcQg==", + "dependencies": { + "@tanstack/query-devtools": "5.32.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^5.35.1", + "react": "^18.0.0" + } + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -600,7 +855,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -609,7 +863,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -620,11 +873,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "peer": true + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "devOptional": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -633,6 +891,12 @@ "node": ">= 8" } }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "peer": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -858,8 +1122,18 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/binary-extensions": { "version": "2.3.0", @@ -887,7 +1161,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "devOptional": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -934,6 +1207,15 @@ "node": ">=6" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "peer": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001600", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", @@ -973,7 +1255,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "devOptional": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -997,7 +1278,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -1005,16 +1285,41 @@ "node": ">= 6" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1025,8 +1330,32 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "peer": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color2k": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/color2k/-/color2k-2.0.3.tgz", + "integrity": "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog==", + "peer": true + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "peer": true, + "engines": { + "node": ">= 6" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -1038,7 +1367,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1048,6 +1376,18 @@ "node": ">= 8" } }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "peer": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -1134,6 +1474,15 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -1177,6 +1526,12 @@ "node": ">=6" } }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "peer": true + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -1189,6 +1544,12 @@ "node": ">=8" } }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "peer": true + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1205,13 +1566,12 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "peer": true }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/enhanced-resolve": { "version": "5.16.0", @@ -1818,7 +2178,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -1834,7 +2193,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -1855,10 +2213,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dependencies": { "reusify": "^1.0.4" } @@ -1879,7 +2236,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "devOptional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1903,6 +2259,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "peer": true, + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -1936,7 +2301,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, + "peer": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -1958,7 +2323,6 @@ "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": [ @@ -1972,7 +2336,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2078,7 +2441,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -2253,10 +2615,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", "dependencies": { "function-bind": "^1.1.2" }, @@ -2276,8 +2637,7 @@ "node_modules/immutable": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", - "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", - "devOptional": true + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -2350,6 +2710,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "peer": true + }, "node_modules/is-async-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", @@ -2381,7 +2747,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "devOptional": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -2421,7 +2786,6 @@ "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, "dependencies": { "hasown": "^2.0.0" }, @@ -2463,7 +2827,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -2484,7 +2847,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, + "peer": true, "engines": { "node": ">=8" } @@ -2508,7 +2871,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "devOptional": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -2544,7 +2906,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, "engines": { "node": ">=0.12.0" } @@ -2710,8 +3071,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/iterator.prototype": { "version": "1.1.2", @@ -2730,7 +3090,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, + "peer": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -2744,6 +3104,15 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "peer": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2846,6 +3215,21 @@ "node": ">= 0.8.0" } }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "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==", + "peer": true + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2861,10 +3245,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + "node_modules/lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==", + "peer": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "peer": true + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "peer": true + }, + "node_modules/lodash.mapkeys": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mapkeys/-/lodash.mapkeys-4.6.0.tgz", + "integrity": "sha512-0Al+hxpYvONWtg+ZqHpa/GaVzxuN3V7Xeo2p+bY06EaK/n+Y9R7nBePPN2o1LxmL0TWQSwP8LYZ008/hc9JzhA==", + "peer": true }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -2872,6 +3275,12 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==", + "peer": true + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -2896,7 +3305,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } @@ -2905,7 +3313,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -2936,10 +3343,10 @@ } }, "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", + "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "peer": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -2950,6 +3357,17 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "peer": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -3022,7 +3440,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -3031,11 +3448,19 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "peer": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -3242,7 +3667,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -3250,26 +3674,50 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", - "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", - "dev": true, + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "peer": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-type": { + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "peer": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", @@ -3287,7 +3735,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "devOptional": true, "engines": { "node": ">=8.6" }, @@ -3295,13 +3742,22 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "peer": true, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "peer": true, + "engines": { + "node": ">= 6" } }, "node_modules/postcss": { @@ -3331,6 +3787,127 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "peer": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "peer": true + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -3364,7 +3941,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -3404,9 +3980,9 @@ } }, "node_modules/react-hook-form": { - "version": "7.51.2", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.2.tgz", - "integrity": "sha512-y++lwaWjtzDt/XNnyGDQy6goHskFualmDlf+jzEZvjvz6KWDf7EboL7pUvRCzPTJd0EOPpdekYaQLEvvG6m6HA==", + "version": "7.51.4", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.4.tgz", + "integrity": "sha512-V14i8SEkh+V1gs6YtD0hdHYnoL4tp/HX/A45wWQN15CYr9bFRmmRdYStSO5L65lCCZRF+kYiSKhm9alqbcdiVA==", "engines": { "node": ">=12.22.0" }, @@ -3424,11 +4000,19 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "peer": true, + "dependencies": { + "pify": "^2.3.0" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "devOptional": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -3458,10 +4042,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", @@ -3485,7 +4068,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -3520,7 +4102,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -3565,7 +4146,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -3620,10 +4200,9 @@ } }, "node_modules/sass": { - "version": "1.72.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.72.0.tgz", - "integrity": "sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA==", - "devOptional": true, + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.76.0.tgz", + "integrity": "sha512-nc3LeqvF2FNW5xGF1zxZifdW3ffIz5aBb7I7tSvOoNu7z1RQ6pFt9MBuiPtjgaI62YWrM/txjWlOCFiGtf2xpw==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -3707,7 +4286,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -3719,7 +4297,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -3746,7 +4323,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, + "peer": true, "engines": { "node": ">=14" }, @@ -3754,6 +4331,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "peer": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -3783,6 +4369,71 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "peer": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "peer": true + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "peer": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", + "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", @@ -3923,7 +4574,19 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -3987,6 +4650,74 @@ } } }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.3.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", + "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", + "peer": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.11.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -4003,7 +4734,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -4011,6 +4741,72 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tailwind-merge": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.3.0.tgz", + "integrity": "sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.24.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwind-variants": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-0.2.1.tgz", + "integrity": "sha512-2xmhAf4UIc3PijOUcJPA1LP4AbxhpcHuHM2C26xM0k81r0maAO6uoUSHl3APmvHZcY5cZCY/bYuJdfFa4eGoaw==", + "peer": true, + "dependencies": { + "tailwind-merge": "^2.2.0" + }, + "engines": { + "node": ">=16.x", + "pnpm": ">=7.x" + }, + "peerDependencies": { + "tailwindcss": "*" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", + "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", + "peer": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -4026,11 +4822,31 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "peer": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "peer": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -4050,6 +4866,12 @@ "typescript": ">=4.2.0" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "peer": true + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -4207,10 +5029,16 @@ "punycode": "^2.1.0" } }, - "node_modules/usehooks-ts": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.0.tgz", - "integrity": "sha512-bBIa7yUyPhE1BCc0GmR96VU/15l/9gP1Ch5mYdLcFBaFGQsdmXkvjV0TtOqW1yUd6VjIwDunm+flSciCQXujiw==", + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "peer": true + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dependencies": { "lodash.debounce": "^4.0.8" }, @@ -4225,7 +5053,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -4296,30 +5123,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, + "peer": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -4337,7 +5145,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -4354,13 +5162,13 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "peer": true }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, + "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -4374,7 +5182,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, + "peer": true, "engines": { "node": ">=12" }, @@ -4386,7 +5194,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, + "peer": true, "engines": { "node": ">=12" }, @@ -4398,7 +5206,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, + "peer": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -4421,6 +5229,18 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yaml": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index fb696dd56..aa766ce4b 100644 --- a/package.json +++ b/package.json @@ -9,19 +9,22 @@ "lint": "next lint" }, "dependencies": { - "next": "14.1.4", + "@nextui-org/skeleton": "^2.0.27", + "@tanstack/react-query": "^5.35.1", + "@tanstack/react-query-devtools": "^5.35.1", + "classnames": "^2.5.1", + "next": "13.5.6", "react": "^18", "react-dom": "^18", - "react-hook-form": "^7.51.2", - "usehooks-ts": "^3.1.0" + "react-hook-form": "^7.51.4", + "sass": "^1.76.0" }, "devDependencies": { "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "eslint": "^8", - "eslint-config-next": "14.1.4", - "sass": "^1.72.0", + "eslint-config-next": "13.5.6", "typescript": "^5" } } diff --git a/pages/RootLayout.tsx b/pages/RootLayout.tsx new file mode 100644 index 000000000..0dca9e7c6 --- /dev/null +++ b/pages/RootLayout.tsx @@ -0,0 +1,26 @@ +import { Metadata } from "next"; +import { ReactNode } from "react"; + +import { Footer, GNB } from "../src/components/common"; +import type { User } from "@/src/types/type"; + +export const metadata: Metadata = { + title: "Linkbrary", + description: "세상의 모든 정보를 쉽게 저장하고 관리해 보세요", + // metadataBase: new URL("") +}; + +interface RootLayoutProps { + children: ReactNode; + userData?: User[]; +} + +export default function RootLayout({ children, userData }: RootLayoutProps) { + return ( +
+ +
{children}
+
+ ); +} diff --git a/pages/_app.tsx b/pages/_app.tsx new file mode 100644 index 000000000..a19df7d28 --- /dev/null +++ b/pages/_app.tsx @@ -0,0 +1,51 @@ +import { ReactElement, ReactNode, useState } from "react"; +import { NextPage } from "next"; +import { + QueryClient, + QueryClientProvider, + DehydratedState, + HydrationBoundary, +} from "@tanstack/react-query"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; + +import type { AppProps } from "next/app"; +import type { User } from "@/src/types/type"; + +import "@/styles/reset.css"; + +type NextPageWithLayout = NextPage & { + getLayout?: (getLayoutProps: { + page: ReactElement; + userData?: User[]; + }) => ReactNode; +}; + +type AppPropsWithLayout = AppProps & { + Component: NextPageWithLayout; + dehydratedState: DehydratedState; +}; + +export default function App({ Component, pageProps }: AppPropsWithLayout) { + const getLayout = Component.getLayout ?? (({ page }) => page); + const [queryClient] = useState( + () => + new QueryClient({ + defaultOptions: { + queries: { + staleTime: 60 * 1000, + }, + }, + }) + ); + + const page = ( + + + + + + + ); + + return getLayout({ page, userData: pageProps.userData }); +} diff --git a/pages/folder/index.tsx b/pages/folder/index.tsx new file mode 100644 index 000000000..c48a10de3 --- /dev/null +++ b/pages/folder/index.tsx @@ -0,0 +1,81 @@ +import { ReactNode } from "react"; +import { GetServerSideProps } from "next"; +import { + DehydratedState, + HydrationBoundary, + QueryClient, + dehydrate, +} from "@tanstack/react-query"; + +import { Folder, RootLayout } from "@/src/components"; +import { getFoldersData, getLinksData, getUserData } from "@/src/apis"; +import { ROUTER } from "@/src/constants"; +import type { User } from "@/src/types/type"; + +interface FolderPageProps { + dehydratedState: DehydratedState; +} + +interface getLayoutProps { + page: ReactNode; + userData?: User[]; +} + +export default function FolderPage({ dehydratedState }: FolderPageProps) { + return ( + <> + + + + + ); +} + +FolderPage.getLayout = function getLayout({ page, userData }: getLayoutProps) { + return {page}; +}; + +export const getServerSideProps: GetServerSideProps = async (context) => { + const queryClient = new QueryClient(); + const TOKEN = context.req?.cookies.accessToken; + + // 토큰이 없는경우 예외처리 + if (!TOKEN) { + return { + redirect: { + destination: ROUTER.SIGN_IN, + permanent: false, + }, + }; + } + + // userData prefetch + await queryClient.prefetchQuery({ + queryKey: ["userData"], + queryFn: () => getUserData(TOKEN), + }); + + const userData = queryClient.getQueryData(["userData"]); + + // Folder List prefetch + await queryClient.prefetchQuery({ + queryKey: ["favorites"], + queryFn: () => getFoldersData(TOKEN), + }); + + // LinksData prefetch + await queryClient.prefetchQuery({ + queryKey: ["linksData"], + queryFn: () => getLinksData(TOKEN), + }); + + // 캐싱 데이터 dehydrateState로 설정 + const dehydratedState = dehydrate(queryClient); + + return { + props: { + userData: userData || null, + dehydratedState, + }, + }; +}; diff --git a/pages/index.tsx b/pages/index.tsx new file mode 100644 index 000000000..279d31295 --- /dev/null +++ b/pages/index.tsx @@ -0,0 +1,49 @@ +import { ReactNode } from "react"; +import { GetServerSideProps } from "next"; +import { QueryClient } from "@tanstack/react-query"; + +import { LandingContainer, LandingHeader, RootLayout } from "@/src/components"; +import { getUserData } from "@/src/apis"; +import type { User } from "@/src/types/type"; + +interface getLayoutProps { + page: ReactNode; + userData?: User[]; +} + +export default function Home() { + return ( + <> + + + + ); +} + +Home.getLayout = function getLayout({ page, userData }: getLayoutProps) { + return {page}; +}; + +export const getServerSideProps: GetServerSideProps = async (context) => { + const queryClient = new QueryClient(); + const token = context.req?.cookies.accessToken; + + if (!token) { + return { + props: { userData: null }, + }; + } + + await queryClient.prefetchQuery({ + queryKey: ["accessToken"], + queryFn: () => getUserData(token), + }); + + const userData = queryClient.getQueryData(["accessToken"]); + + return { + props: { + userData: userData || null, + }, + }; +}; diff --git a/pages/sign-in/SignInPage.module.scss b/pages/sign-in/SignInPage.module.scss new file mode 100644 index 000000000..1898538a2 --- /dev/null +++ b/pages/sign-in/SignInPage.module.scss @@ -0,0 +1,12 @@ +.page { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100vw; + height: 100vh; + gap: 32px; + padding: 32px; + + background: var(--Linkbrary-bg, #f0f6ff); +} diff --git a/pages/sign-in/index.tsx b/pages/sign-in/index.tsx new file mode 100644 index 000000000..41170340e --- /dev/null +++ b/pages/sign-in/index.tsx @@ -0,0 +1,43 @@ +import classNames from "classnames/bind"; +import { GetServerSideProps } from "next"; +import { useRouter } from "next/router"; + +import { LinkBox, LogoBox, SignInForm } from "@/src/components"; +import { ROUTER } from "@/src/constants"; + +import styles from "./SignInPage.module.scss"; + +const cn = classNames.bind(styles); + +export default function SignInPage() { + const router = useRouter(); + + return ( +
+ + + +
+ ); +} + +export const getServerSideProps: GetServerSideProps = async (context) => { + const token = context.req?.cookies.accessToken; + + if (token) { + return { + redirect: { + destination: ROUTER.FOLDER, + permanent: false, + }, + }; + } + + return { + props: {}, + }; +}; diff --git a/pages/sign-up/index.tsx b/pages/sign-up/index.tsx new file mode 100644 index 000000000..b0b16b542 --- /dev/null +++ b/pages/sign-up/index.tsx @@ -0,0 +1,43 @@ +import classNames from "classnames/bind"; +import { GetServerSideProps } from "next"; +import { useRouter } from "next/router"; + +import { LinkBox, LogoBox, SignUpForm } from "@/src/components"; +import { ROUTER } from "@/src/constants"; + +import styles from "../sign-in/SignInPage.module.scss"; + +const cn = classNames.bind(styles); + +export default function SignUpPage() { + const router = useRouter(); + + return ( +
+ + + +
+ ); +} + +export const getServerSideProps: GetServerSideProps = async (context) => { + const token = context.req?.cookies.accessToken; + + if (token) { + return { + redirect: { + destination: ROUTER.FOLDER, + permanent: false, + }, + }; + } + + return { + props: {}, + }; +}; diff --git a/public/imgs/img_example.png b/public/imgs/img_example.png new file mode 100644 index 000000000..bf0ea76e3 Binary files /dev/null and b/public/imgs/img_example.png differ diff --git a/public/imgs/img_link.png b/public/imgs/img_link.png new file mode 100644 index 000000000..776933db9 Binary files /dev/null and b/public/imgs/img_link.png differ diff --git a/public/imgs/img_manage.png b/public/imgs/img_manage.png new file mode 100644 index 000000000..427621f4d Binary files /dev/null and b/public/imgs/img_manage.png differ diff --git a/public/imgs/img_serch.png b/public/imgs/img_serch.png new file mode 100644 index 000000000..f84deca78 Binary files /dev/null and b/public/imgs/img_serch.png differ diff --git a/public/imgs/img_share.png b/public/imgs/img_share.png new file mode 100644 index 000000000..1bc291458 Binary files /dev/null and b/public/imgs/img_share.png differ diff --git a/public/index.ts b/public/index.ts new file mode 100644 index 000000000..2cbb73aea --- /dev/null +++ b/public/index.ts @@ -0,0 +1,15 @@ +export { default as Img_Example } from "./imgs/img_example.png"; +export { default as Img_Link } from "./imgs/img_link.png"; +export { default as Img_Manage } from "./imgs/img_manage.png"; +export { default as Img_Share } from "./imgs/img_share.png"; +export { default as Img_Serch } from "./imgs/img_serch.png"; + +export { default as Ic_Logo } from "./svgs/ic_logo"; +export { default as Ic_Instagram } from "./svgs/ic_instagram"; +export { default as Ic_Youtube } from "./svgs/ic_youtube"; +export { default as Ic_Twitter } from "./svgs/ic_twitter"; +export { default as Ic_Facebook } from "./svgs/ic_facebook"; +export { default as Ic_Eye_On } from "./svgs/ic_eye_on"; +export { default as Ic_Eye_Off } from "./svgs/ic_eye_off"; +export { default as Ic_Google } from "./svgs/ic_google"; +export { default as Ic_Talk } from "./svgs/ic_talk"; diff --git a/public/svgs/ic_eye_off.tsx b/public/svgs/ic_eye_off.tsx new file mode 100644 index 000000000..1f2cf47b2 --- /dev/null +++ b/public/svgs/ic_eye_off.tsx @@ -0,0 +1,17 @@ +export default function Ic_Eye_Off() { + return ( + + + + + ); +} diff --git a/public/svgs/ic_eye_on.tsx b/public/svgs/ic_eye_on.tsx new file mode 100644 index 000000000..5acacea24 --- /dev/null +++ b/public/svgs/ic_eye_on.tsx @@ -0,0 +1,17 @@ +export default function Ic_Eye_On() { + return ( + + + + + ); +} diff --git a/public/svgs/ic_facebook.tsx b/public/svgs/ic_facebook.tsx new file mode 100644 index 000000000..16d0b3e67 --- /dev/null +++ b/public/svgs/ic_facebook.tsx @@ -0,0 +1,18 @@ +export default function Ic_Facebook() { + return ( + + + + ); +} diff --git a/public/svgs/ic_google.tsx b/public/svgs/ic_google.tsx new file mode 100644 index 000000000..2c2ee41bb --- /dev/null +++ b/public/svgs/ic_google.tsx @@ -0,0 +1,30 @@ +export default function Ic_Google() { + return ( + + + + + + + + + + ); +} diff --git a/public/svgs/ic_instagram.tsx b/public/svgs/ic_instagram.tsx new file mode 100644 index 000000000..52c72b483 --- /dev/null +++ b/public/svgs/ic_instagram.tsx @@ -0,0 +1,16 @@ +export default function Ic_Instagram() { + return ( + + + + ); +} diff --git a/public/svgs/ic_logo.tsx b/public/svgs/ic_logo.tsx new file mode 100644 index 000000000..36bb05a68 --- /dev/null +++ b/public/svgs/ic_logo.tsx @@ -0,0 +1,58 @@ +interface ic_logoProps { + width?: string; + height?: string; + fill?: string; +} + +export default function ic_logo({ + width = "112", + height = "24", + fill = "none", +}: ic_logoProps) { + return ( + + + + + + + + + + + + ); +} diff --git a/public/svgs/ic_talk.tsx b/public/svgs/ic_talk.tsx new file mode 100644 index 000000000..ab8c3c96f --- /dev/null +++ b/public/svgs/ic_talk.tsx @@ -0,0 +1,27 @@ +export default function Ic_Talk() { + return ( + + + + + + + + + + + + ); +} diff --git a/public/svgs/ic_twitter.tsx b/public/svgs/ic_twitter.tsx new file mode 100644 index 000000000..eda4d56bd --- /dev/null +++ b/public/svgs/ic_twitter.tsx @@ -0,0 +1,16 @@ +export default function Ic_Twitter() { + return ( + + + + ); +} diff --git a/public/svgs/ic_youtube.tsx b/public/svgs/ic_youtube.tsx new file mode 100644 index 000000000..e0b1f7ce1 --- /dev/null +++ b/public/svgs/ic_youtube.tsx @@ -0,0 +1,23 @@ +export default function Ic_Youtube() { + return ( + + + + + + + + + + + ); +} diff --git a/src/apis/index.ts b/src/apis/index.ts new file mode 100644 index 000000000..935002095 --- /dev/null +++ b/src/apis/index.ts @@ -0,0 +1,141 @@ +import { FieldValues } from "react-hook-form"; + +// sign-in +export async function postSignIn(payload: FieldValues) { + try { + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_BASE_URL}/auth/sign-in`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(payload), + } + ); + + const result = await response.json(); + + if (!response.ok) { + throw new Error(); + } + + return result; + } catch (error) { + console.error("postSignIn 실패", error); + throw error; + } +} + +// sign-up +export async function postSignUp(payload: FieldValues) { + try { + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_BASE_URL}/auth/sign-up`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(payload), + } + ); + + const result = await response.json(); + + if (!response.ok) { + throw new Error(); + } + + return result; + } catch (error) { + console.error("postSignUp 실패", error); + throw error; + } +} + +// 이메일 중복 check +export async function checkEmail(email: string) { + try { + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_BASE_URL}/users/check-email`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ email }), + } + ); + + return await response.json(); + } catch (error) { + console.error("checkEmail 실패", error); + throw error; + } +} + +// userData +export async function getUserData(token: string) { + try { + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_BASE_URL}/users`, + { + headers: { Authorization: `Bearer ${token}` }, + } + ); + + return await response.json(); + } catch (error) { + console.error("getUserData 실패", error); + throw error; + } +} + +// FoderList Data +export async function getFoldersData(token: string) { + try { + const respoese = await fetch( + `${process.env.NEXT_PUBLIC_API_BASE_URL}/folders`, + { + headers: { Authorization: `Bearer ${token}` }, + } + ); + + return await respoese.json(); + } catch (error) { + console.error("getFoldersData 실패", error); + throw error; + } +} + +// LinkList Data +export async function getLinksData(token: string) { + try { + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_BASE_URL}/links`, + { + headers: { Authorization: `Bearer ${token}` }, + } + ); + + return await response.json(); + } catch (error) { + console.error("getLinksData 실패", error); + throw error; + } +} + +// FolderId LinksData +export async function getFolderIdLinksData(folderId: number) { + try { + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_BASE_URL}/folders/${folderId}/links` + ); + + return await response.json(); + } catch (error) { + console.error("getFolderIdLinksData 실패", error); + throw error; + } +} diff --git a/src/components/auth/AuthForm/AuthForm.module.scss b/src/components/auth/AuthForm/AuthForm.module.scss new file mode 100644 index 000000000..094897ef6 --- /dev/null +++ b/src/components/auth/AuthForm/AuthForm.module.scss @@ -0,0 +1,30 @@ +.form { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + max-width: 400px; + gap: 40px; + + .button { + display: flex; + width: inherit; + padding: 16px 20px; + justify-content: center; + align-items: center; + gap: 10px; + + border-radius: 8px; + border: none; + background: var( + --gra-purpleblue-to-skyblue, + linear-gradient(91deg, #6d6afe 0.12%, #6ae3fe 101.84%) + ); + + color: var(--Grey-Light, #f5f5f5); + font-size: 18px; + font-weight: 600; + line-height: normal; + } +} diff --git a/src/components/auth/AuthForm/SignInForm.tsx b/src/components/auth/AuthForm/SignInForm.tsx new file mode 100644 index 000000000..43c86a259 --- /dev/null +++ b/src/components/auth/AuthForm/SignInForm.tsx @@ -0,0 +1,98 @@ +import classNames from "classnames/bind"; +import { useRouter } from "next/router"; +import { useForm, SubmitHandler, FieldValues } from "react-hook-form"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; + +import { InputField } from "@/src/components/common"; +import { postSignIn } from "@/src/apis"; +import { ROUTER } from "@/src/constants"; + +import styles from "./AuthForm.module.scss"; + +const cn = classNames.bind(styles); + +const regExpEm = + /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i; + +export default function SignInForm() { + const router = useRouter(); + const queryClient = useQueryClient(); + const { + register, + handleSubmit, + setValue, + setError, + formState: { errors }, + } = useForm({ + mode: "all", + defaultValues: { + email: "", + password: "", + }, + }); + + const { mutate: loginMutation } = useMutation({ + mutationFn: postSignIn, + mutationKey: ["token"], + onSuccess: () => { + // token값을 cookie에 저장하여 사용중인데 localStorage관련한 로직을 추가적으로 넣어주는게 맞는지 고민중입니다 + // queryClient.invalidateQueries({ + // queryKey: ["accessToken"], + // }); + // queryClient.invalidateQueries({ + // queryKey: ["refreshToken"], + // }); + }, + }); + + const onSubmit: SubmitHandler = (payload) => { + loginMutation(payload, { + onSuccess: (response) => { + localStorage.setItem("accessToken", response.accessToken); + localStorage.setItem("refreshToken", response.refreshToken); + + document.cookie = `accessToken=${response.accessToken}; path=${ROUTER.HOME};`; + + router.replace(ROUTER.FOLDER); + }, + onError: () => { + setError("email", { message: "이메일을 확인해 주세요" }); + setError("password", { message: "비밀번호를 확인해 주세요" }); + }, + }); + setValue("password", ""); + }; + + return ( +
+ + + + + ); +} diff --git a/src/components/auth/AuthForm/SignUpForm.tsx b/src/components/auth/AuthForm/SignUpForm.tsx new file mode 100644 index 000000000..aca4c2ac0 --- /dev/null +++ b/src/components/auth/AuthForm/SignUpForm.tsx @@ -0,0 +1,131 @@ +import classNames from "classnames/bind"; +import { useRouter } from "next/router"; +import { useForm, SubmitHandler, FieldValues } from "react-hook-form"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; + +import { InputField } from "@/src/components/common"; +import { checkEmail, postSignUp } from "@/src/apis"; +import { ROUTER } from "@/src/constants"; + +import styles from "./AuthForm.module.scss"; + +const cn = classNames.bind(styles); + +const regExpEm = + /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i; +const regExgPw = /^[A-Za-z0-9]{8,20}$/; + +export default function SignUpForm() { + const router = useRouter(); + const queryClient = useQueryClient(); + const { + register, + handleSubmit, + setError, + watch, + formState: { errors, isValid }, + } = useForm({ + mode: "all", + defaultValues: { + email: "", + password: "", + passwordValidate: "", + }, + }); + + const { mutate: checkEmailMutation } = useMutation({ + mutationFn: checkEmail, + onSuccess: (response) => { + if (!response.ok && !errors.email) { + setError("email", { message: response.message }); + } + }, + }); + + const { mutate: signUpMutation } = useMutation({ + mutationFn: postSignUp, + onSuccess: () => { + // token값을 cookie에 저장하여 사용중인데 localStorage관련한 로직을 추가적으로 넣어주는게 맞는지 고민중입니다 + // queryClient.invalidateQueries({ + // queryKey: ["accessToken"], + // }); + // queryClient.invalidateQueries({ + // queryKey: ["refreshToken"], + // }); + }, + }); + + const onSubmit: SubmitHandler = (payload) => { + signUpMutation(payload, { + onSuccess: (response) => { + // localStorage.setItem("accessToken", response.accessToken); + // localStorage.setItem("refreshToken", response.refreshToken); + document.cookie = `accessToken=${response.accessToken}; path=${ROUTER.HOME};`; + + router.replace(ROUTER.FOLDER); + }, + onError: () => { + setError("email", { message: "이메일을 확인해 주세요" }); + setError("password", { message: "비밀번호를 확인해 주세요" }); + setError("passwordValidate", { message: "비밀번호를 확인해 주세요" }); + }, + }); + }; + + return ( +
+ { + const emailValue = e.target.value; + checkEmailMutation(emailValue); + }, + })} + /> + + { + if (watch("password") !== value) { + return "비밀번호가 일치하지 않아요"; + } + }, + })} + /> + + + ); +} diff --git a/src/components/auth/LinkBox/LinkBox.module.scss b/src/components/auth/LinkBox/LinkBox.module.scss new file mode 100644 index 000000000..416321326 --- /dev/null +++ b/src/components/auth/LinkBox/LinkBox.module.scss @@ -0,0 +1,54 @@ +.linkBox { + border-radius: 8px; + border: 1px solid var(--Linkbrary-gray20, #ccd5e3); + background: var(--Linkbrary-gray10, #e7effb); + + width: 100%; + max-width: 400px; + display: flex; + padding: 12px 24px; + justify-content: space-between; + align-items: center; + + .text { + color: var(--Linkbrary-gray100, #373740); + font-size: 14px; + font-weight: 400; + line-height: normal; + } + + .snsBox { + display: flex; + gap: 16px; + + .google { + width: 42px; + height: 42px; + flex-shrink: 0; + border-radius: 9999px; + border: 1px solid #d3d4dd; + padding: 10px; + + display: flex; + align-items: center; + justify-content: center; + + background: #ffffff; + } + + .kakao { + width: 42px; + height: 42px; + flex-shrink: 0; + border-radius: 9999px; + border: 1px solid #d3d4dd; + padding: 8px; + + display: flex; + align-items: center; + justify-content: center; + + background: #f5e14b; + } + } +} diff --git a/src/components/auth/LinkBox/LinkBox.tsx b/src/components/auth/LinkBox/LinkBox.tsx new file mode 100644 index 000000000..86f53449a --- /dev/null +++ b/src/components/auth/LinkBox/LinkBox.tsx @@ -0,0 +1,31 @@ +import classNames from "classnames/bind"; +import { Ic_Google, Ic_Talk } from "@/public"; +import { SNS_LINK } from "@/src/constants"; + +import styles from "./LinkBox.module.scss"; + +const cn = classNames.bind(styles); + +interface LinkBoxProps { + text: string; +} + +export default function LinkBox({ text }: LinkBoxProps) { + return ( + + ); +} diff --git a/src/components/auth/LogoBox/LogoBox.module.scss b/src/components/auth/LogoBox/LogoBox.module.scss new file mode 100644 index 000000000..2a242a24c --- /dev/null +++ b/src/components/auth/LogoBox/LogoBox.module.scss @@ -0,0 +1,18 @@ +.logobox { + display: flex; + flex-direction: column; + gap: 16px; + + .textBox { + display: flex; + justify-content: space-between; + align-items: center; + gap: 4px; + + color: var(--black, #000); + + font-size: 16px; + font-weight: 400; + line-height: 24px; + } +} diff --git a/src/components/auth/LogoBox/LogoBox.tsx b/src/components/auth/LogoBox/LogoBox.tsx new file mode 100644 index 000000000..0b74d54a1 --- /dev/null +++ b/src/components/auth/LogoBox/LogoBox.tsx @@ -0,0 +1,30 @@ +import classNames from "classnames/bind"; +import Link from "next/link"; +import { Ic_Logo } from "@/public"; +import { ROUTER } from "@/src/constants"; + +import styles from "./LogoBox.module.scss"; + +const cn = classNames.bind(styles); + +interface LogoBoxProps { + text: string; + href: string; + hrefText: string; +} + +export default function LogoBox({ text, href, hrefText }: LogoBoxProps) { + return ( +
+ + + +
+ {text} + + {hrefText} + +
+
+ ); +} diff --git a/src/components/common/Footer/Footer.module.scss b/src/components/common/Footer/Footer.module.scss new file mode 100644 index 000000000..f39a043ff --- /dev/null +++ b/src/components/common/Footer/Footer.module.scss @@ -0,0 +1,22 @@ +.footer { + padding: 32px 104px 62px; + display: flex; + align-items: center; + background: #111322; + justify-content: space-between; + font-family: Arial; + font-size: 16px; + font-weight: 400; + color: #676767; + text-decoration: none; + + .linkBox { + display: flex; + gap: 30px; + } + + .snsBox { + display: flex; + gap: 12px; + } +} diff --git a/src/components/common/Footer/Footer.tsx b/src/components/common/Footer/Footer.tsx new file mode 100644 index 000000000..c99b3329c --- /dev/null +++ b/src/components/common/Footer/Footer.tsx @@ -0,0 +1,42 @@ +import classNames from "classnames/bind"; +import Link from "next/link"; +import { ROUTER, SNS_LINK } from "../../../constants"; +import { Ic_Facebook, Ic_Instagram, Ic_Twitter, Ic_Youtube } from "@/public"; + +import styles from "./Footer.module.scss"; + +const cn = classNames.bind(styles); + +export default function Footer() { + return ( + + ); +} diff --git a/src/components/common/GNB/GNB.module.scss b/src/components/common/GNB/GNB.module.scss new file mode 100644 index 000000000..a08248202 --- /dev/null +++ b/src/components/common/GNB/GNB.module.scss @@ -0,0 +1,38 @@ +.gnb { + width: 100vw; + display: flex; + justify-content: center; + align-items: center; + padding: 20px 32px; + background: var(--Linkbrary-bg, #f0f6ff); + + .gnbBox { + width: 100%; + max-width: 1920px; + display: flex; + justify-content: space-between; + align-items: center; + + .button { + color: var(--Grey-Light, #f5f5f5); + font-size: 18px; + font-style: normal; + font-weight: 600; + line-height: normal; + + display: flex; + width: 128px; + padding: 16px 20px; + justify-content: center; + align-items: center; + flex-shrink: 0; + + border-radius: 8px; + border: none; + background: var( + --gra-purpleblue-to-skyblue, + linear-gradient(91deg, #6d6afe 0.12%, #6ae3fe 101.84%) + ); + } + } +} diff --git a/src/components/common/GNB/GNB.tsx b/src/components/common/GNB/GNB.tsx new file mode 100644 index 000000000..330eafb2f --- /dev/null +++ b/src/components/common/GNB/GNB.tsx @@ -0,0 +1,36 @@ +import classNames from "classnames/bind"; +import Link from "next/link"; + +import { Ic_Logo } from "@/public"; +import { ROUTER } from "@/src/constants"; +import { Profile } from "./parts"; +import type { User } from "@/src/types/type"; + +import styles from "./GNB.module.scss"; + +const cn = classNames.bind(styles); + +interface GNBProps { + userData?: User[]; +} + +export default function GNB({ userData }: GNBProps) { + return ( + + ); +} diff --git a/src/components/common/GNB/parts/Profile.module.scss b/src/components/common/GNB/parts/Profile.module.scss new file mode 100644 index 000000000..ac2b043da --- /dev/null +++ b/src/components/common/GNB/parts/Profile.module.scss @@ -0,0 +1,12 @@ +.profile { + display: inline-flex; + justify-content: center; + align-items: center; + gap: 6px; + height: 53px; + + color: var(--Linkbrary-gray100, #373740); + font-size: 14px; + font-weight: 400; + line-height: normal; +} diff --git a/src/components/common/GNB/parts/Profile.tsx b/src/components/common/GNB/parts/Profile.tsx new file mode 100644 index 000000000..e5925b910 --- /dev/null +++ b/src/components/common/GNB/parts/Profile.tsx @@ -0,0 +1,29 @@ +import classNames from "classnames/bind"; +import Image from "next/image"; + +import type { User } from "@/src/types/type"; + +import styles from "./Profile.module.scss"; + +const cn = classNames.bind(styles); + +interface ProfileProps { + userData: User[]; +} + +export default function Profile({ userData }: ProfileProps) { + const { image_source, email } = userData[0]; + + return ( +
+ 프로필 +

{email}

+
+ ); +} diff --git a/src/components/common/GNB/parts/index.ts b/src/components/common/GNB/parts/index.ts new file mode 100644 index 000000000..d3a49de73 --- /dev/null +++ b/src/components/common/GNB/parts/index.ts @@ -0,0 +1 @@ +export { default as Profile } from "./Profile"; diff --git a/src/components/common/InputField/InputField.module.scss b/src/components/common/InputField/InputField.module.scss new file mode 100644 index 000000000..9b1f538e1 --- /dev/null +++ b/src/components/common/InputField/InputField.module.scss @@ -0,0 +1,19 @@ +.inputField { + position: relative; + width: 100%; + display: inline-flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; + gap: 12px; + + .error { + position: absolute; + bottom: -24px; + + color: var(--Linkbrary-red, #ff5b56); + font-size: 14px; + font-weight: 400; + line-height: normal; + } +} diff --git a/src/components/common/InputField/InputField.tsx b/src/components/common/InputField/InputField.tsx new file mode 100644 index 000000000..ee330a29d --- /dev/null +++ b/src/components/common/InputField/InputField.tsx @@ -0,0 +1,48 @@ +import classNames from "classnames/bind"; +import { InputHTMLAttributes, forwardRef, useState } from "react"; +import { Label, SuffixIcon, Input } from "./parts/index"; + +import styles from "./InputField.module.scss"; + +const cn = classNames.bind(styles); + +interface InputFieldProps extends InputHTMLAttributes { + label?: string; + errorMessage?: string; + suffixIcon?: boolean; +} + +export default forwardRef( + function InputField( + { id, label, type, errorMessage, suffixIcon, ...rest }, + ref + ) { + const [inputType, setInputType] = useState(type); + + const onSuffixIconClick = () => { + if (inputType === "password") { + setInputType("text"); + return; + } + + setInputType("password"); + }; + + return ( +
+ {label && } + + {suffixIcon && type === "password" && ( + + )} + {errorMessage && {errorMessage}} +
+ ); + } +); diff --git a/src/components/common/InputField/parts/Input.module.scss b/src/components/common/InputField/parts/Input.module.scss new file mode 100644 index 000000000..07f472780 --- /dev/null +++ b/src/components/common/InputField/parts/Input.module.scss @@ -0,0 +1,23 @@ +.default { + padding: 18px 16px; + width: 100%; + display: flex; + justify-content: center; + align-items: center; + border-radius: 8px; + border: 1px solid var(--Linkbrary-gray20, #ccd5e3); + background: var(--Linkbrary-white, #fff); + + color: var(--Linkbrary-gray100, #373740); + font-size: 16px; + font-weight: 400; + line-height: 24px; + + &:focus { + border: 1px solid var(--Linkbrary-primary-color, #6d6afe); + } +} + +.red { + border: 1px solid var(--Linkbrary-red, #ff5b56); +} diff --git a/src/components/common/InputField/parts/Input.tsx b/src/components/common/InputField/parts/Input.tsx new file mode 100644 index 000000000..685bc5dc2 --- /dev/null +++ b/src/components/common/InputField/parts/Input.tsx @@ -0,0 +1,19 @@ +import classNames from "classnames/bind"; +import { InputHTMLAttributes, forwardRef } from "react"; + +import styles from "./Input.module.scss"; + +const cn = classNames.bind(styles); + +interface InputProps extends InputHTMLAttributes { + isError?: boolean; +} + +export default forwardRef(function Input( + { isError, ...rest }, + ref +) { + return ( + + ); +}); diff --git a/src/components/common/InputField/parts/Label.module.scss b/src/components/common/InputField/parts/Label.module.scss new file mode 100644 index 000000000..94003a437 --- /dev/null +++ b/src/components/common/InputField/parts/Label.module.scss @@ -0,0 +1,7 @@ +.label { + color: var(--black, #000); + + font-size: 14px; + font-weight: 400; + line-height: normal; +} diff --git a/src/components/common/InputField/parts/Label.tsx b/src/components/common/InputField/parts/Label.tsx new file mode 100644 index 000000000..13976c7ff --- /dev/null +++ b/src/components/common/InputField/parts/Label.tsx @@ -0,0 +1,18 @@ +import classNames from "classnames/bind"; +import { LabelHTMLAttributes, ReactNode } from "react"; + +import styles from "./Label.module.scss"; + +const cn = classNames.bind(styles); + +interface LabelProps extends LabelHTMLAttributes { + children: ReactNode; +} + +export default function Label({ htmlFor, children }: LabelProps) { + return ( + + ); +} diff --git a/src/components/common/InputField/parts/SuffixIcon.module.scss b/src/components/common/InputField/parts/SuffixIcon.module.scss new file mode 100644 index 000000000..50d8e8387 --- /dev/null +++ b/src/components/common/InputField/parts/SuffixIcon.module.scss @@ -0,0 +1,6 @@ +.suffixIcon { + position: absolute; + right: 24px; + top: 50%; + transform: translate(0%, 25%); +} diff --git a/src/components/common/InputField/parts/SuffixIcon.tsx b/src/components/common/InputField/parts/SuffixIcon.tsx new file mode 100644 index 000000000..903793cc4 --- /dev/null +++ b/src/components/common/InputField/parts/SuffixIcon.tsx @@ -0,0 +1,19 @@ +import classNames from "classnames/bind"; +import { Ic_Eye_Off, Ic_Eye_On } from "@/public"; +import { InputHTMLAttributes } from "react"; + +import styles from "./SuffixIcon.module.scss"; + +const cn = classNames.bind(styles); + +interface SuffixIconProps extends InputHTMLAttributes { + onClick: () => void; +} + +export default function SuffixIcon({ type, onClick }: SuffixIconProps) { + return ( +
+ {type === "password" ? : } +
+ ); +} diff --git a/src/components/common/InputField/parts/index.ts b/src/components/common/InputField/parts/index.ts new file mode 100644 index 000000000..a98dab38f --- /dev/null +++ b/src/components/common/InputField/parts/index.ts @@ -0,0 +1,3 @@ +export { default as SuffixIcon } from "./SuffixIcon"; +export { default as Label } from "./Label"; +export { default as Input } from "./Input"; diff --git a/src/components/common/index.ts b/src/components/common/index.ts new file mode 100644 index 000000000..744cbefce --- /dev/null +++ b/src/components/common/index.ts @@ -0,0 +1,3 @@ +export { default as GNB } from "./GNB/GNB"; +export { default as Footer } from "./Footer/Footer"; +export { default as InputField } from "./InputField/InputField"; diff --git a/src/components/folder/FavoriteButtonList/FavoriteButton/FavoriteButton.module.scss b/src/components/folder/FavoriteButtonList/FavoriteButton/FavoriteButton.module.scss new file mode 100644 index 000000000..26b84c8c2 --- /dev/null +++ b/src/components/folder/FavoriteButtonList/FavoriteButton/FavoriteButton.module.scss @@ -0,0 +1,22 @@ +.FavoriteButton { + display: inline-flex; + padding: 8px 12px; + align-items: center; + height: 36px; + border-radius: 5px; + border: 1px solid var(--Linkbrary-primary-color, #6d6afe); + background: #fff; + color: #000; + font-size: 16px; + font-weight: 400; + flex-shrink: 0; + + &:hover { + background: var(--Linkbrary-gray10, #e7effb); + } + + &:focus { + color: #fff; + background: var(--Linkbrary-primary-color, #6d6afe); + } +} diff --git a/src/components/folder/FavoriteButtonList/FavoriteButton/FavoriteButton.tsx b/src/components/folder/FavoriteButtonList/FavoriteButton/FavoriteButton.tsx new file mode 100644 index 000000000..5314bf0aa --- /dev/null +++ b/src/components/folder/FavoriteButtonList/FavoriteButton/FavoriteButton.tsx @@ -0,0 +1,27 @@ +import classNames from "classnames/bind"; +import type { Favorite } from "@/src/types/type"; + +import styles from "./FavoriteButton.module.scss"; + +const cn = classNames.bind(styles); + +interface FavoriteButtonProps { + favorite?: Favorite; + onFavoriteClick: (favorite?: Favorite | null) => void; +} + +export default function FavoriteButton({ + favorite, + onFavoriteClick, +}: FavoriteButtonProps) { + const { name } = favorite || { name: "전체" }; + + return ( + + ); +} diff --git a/src/components/folder/FavoriteButtonList/FavoriteButton/index.ts b/src/components/folder/FavoriteButtonList/FavoriteButton/index.ts new file mode 100644 index 000000000..27c9217f8 --- /dev/null +++ b/src/components/folder/FavoriteButtonList/FavoriteButton/index.ts @@ -0,0 +1 @@ +export { default as FavoriteButton } from "./FavoriteButton"; diff --git a/src/components/folder/FavoriteButtonList/FavoriteButtonList.module.scss b/src/components/folder/FavoriteButtonList/FavoriteButtonList.module.scss new file mode 100644 index 000000000..ef3870411 --- /dev/null +++ b/src/components/folder/FavoriteButtonList/FavoriteButtonList.module.scss @@ -0,0 +1,28 @@ +.FavoriteButtonList { + display: flex; + align-items: center; + gap: 8px; + + .totalBtn { + display: inline-flex; + padding: 8px 12px; + align-items: center; + height: 36px; + border-radius: 5px; + border: 1px solid var(--Linkbrary-primary-color, #6d6afe); + background: #fff; + color: #000; + font-size: 16px; + font-weight: 400; + flex-shrink: 0; + + &:hover { + background: var(--Linkbrary-gray10, #e7effb); + } + + &:focus { + color: #fff; + background: var(--Linkbrary-primary-color, #6d6afe); + } + } +} diff --git a/src/components/folder/FavoriteButtonList/FavoriteButtonList.tsx b/src/components/folder/FavoriteButtonList/FavoriteButtonList.tsx new file mode 100644 index 000000000..83dd40c83 --- /dev/null +++ b/src/components/folder/FavoriteButtonList/FavoriteButtonList.tsx @@ -0,0 +1,33 @@ +import classNames from "classnames/bind"; +import { useQuery } from "@tanstack/react-query"; + +import { FavoriteButton } from "./FavoriteButton"; +import type { Favorite } from "@/src/types/type"; + +import styles from "./FavoriteButtonList.module.scss"; + +const cn = classNames.bind(styles); + +interface FavoriteButtonListProps { + handleFavoriteClick: (favorite?: Favorite | null) => void; +} + +export default function FavoriteButtonList({ + handleFavoriteClick, +}: FavoriteButtonListProps) { + const { data: favorites } = useQuery({ queryKey: ["favorites"] }); + + return ( +
+ + {favorites && + favorites.map((favorite) => ( + + ))} +
+ ); +} diff --git a/src/components/folder/Folder.module.scss b/src/components/folder/Folder.module.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/components/folder/Folder.tsx b/src/components/folder/Folder.tsx new file mode 100644 index 000000000..5398f0565 --- /dev/null +++ b/src/components/folder/Folder.tsx @@ -0,0 +1,25 @@ +import { useState } from "react"; + +import { FavoriteButtonList, LinksList } from "."; +import type { Favorite } from "@/src/types/type"; + +export default function Folder() { + const [folderId, setFolderId] = useState(null); + + const handleFavoriteClick = (favorite?: Favorite | null) => { + if (favorite) { + setFolderId(favorite.id); + return; + } + + setFolderId(null); + }; + + return ( + <> + + + + + ); +} diff --git a/src/components/folder/LinksList/LinkOverview/LinkOverview.module.scss b/src/components/folder/LinksList/LinkOverview/LinkOverview.module.scss new file mode 100644 index 000000000..f7020c49b --- /dev/null +++ b/src/components/folder/LinksList/LinkOverview/LinkOverview.module.scss @@ -0,0 +1,68 @@ +.LinkOverview { + max-width: 340px; + width: 100%; + height: 334px; + box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.08); + border-radius: 15px; + overflow: hidden; + text-decoration: none; + flex-shrink: 0; + + .imgBox { + height: 200px; + + .img { + width: 100%; + height: 100%; + } + } + + .caption { + display: flex; + flex-direction: column; + gap: 10px; + padding: 16px 20px; + align-items: flex-start; + height: 134px; + + .updatedAt { + color: #666; + font-size: 13px; + font-weight: 400; + flex-grow: 1; + } + + .description { + color: #000; + overflow: hidden; + white-space: normal; + text-overflow: ellipsis; + font-size: 16px; + line-height: 24px; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + flex-grow: 1; + } + + .createAt { + color: #333; + font-size: 14px; + font-weight: 400; + flex-grow: 1; + } + } + + .emptyCaseBox { + height: 200px; + display: flex; + justify-content: center; + align-items: center; + background: #dddfff; + } + + &:hover { + transform: scale(1.06); + transition: transform 0.3s ease; + } +} diff --git a/src/components/folder/LinksList/LinkOverview/LinkOverview.tsx b/src/components/folder/LinksList/LinkOverview/LinkOverview.tsx new file mode 100644 index 000000000..04fe995e6 --- /dev/null +++ b/src/components/folder/LinksList/LinkOverview/LinkOverview.tsx @@ -0,0 +1,48 @@ +import classNames from "classnames/bind"; +import Link from "next/link"; +import Image from "next/image"; +import { Skeleton } from "@nextui-org/skeleton"; + +import { Ic_Logo } from "@/public"; +import { getElapsedTime, getFormattedDate, getValidUrl } from "@/src/utils"; +import type { TLink } from "@/src/types/type"; + +import styles from "./LinkOverview.module.scss"; + +const cn = classNames.bind(styles); + +interface LinkOverviewProps { + link: TLink; +} + +export default function LinkOverview({ link }: LinkOverviewProps) { + const { image_source: imageUrl, created_at, description, title, url } = link; + const createDate = getElapsedTime(created_at); + const formatDate = getFormattedDate(created_at); + + // 서버 Image-url이 문제가 있어서 그냥 null처리 했읍니다 + const imageSource = getValidUrl(imageUrl); + + return ( + + {imageSource ? ( +
+ {title} +
+ ) : ( +
+ +
+ )} +
+ +

{description}

+ +
+ + ); +} diff --git a/src/components/folder/LinksList/LinkOverview/LinkSkeleton.tsx b/src/components/folder/LinksList/LinkOverview/LinkSkeleton.tsx new file mode 100644 index 000000000..b67a13d4b --- /dev/null +++ b/src/components/folder/LinksList/LinkOverview/LinkSkeleton.tsx @@ -0,0 +1,31 @@ +import classNames from "classnames/bind"; +import { Skeleton } from "@nextui-org/skeleton"; + +import styles from "./LinkOverview.module.scss"; + +const cn = classNames.bind(styles); + +export default function LinkSkeleton() { + return ( +
+ +
+ + + +
+
+ ); +} diff --git a/src/components/folder/LinksList/LinksEmptyCase/LinksEmptyCase.module.scss b/src/components/folder/LinksList/LinksEmptyCase/LinksEmptyCase.module.scss new file mode 100644 index 000000000..98dec156c --- /dev/null +++ b/src/components/folder/LinksList/LinksEmptyCase/LinksEmptyCase.module.scss @@ -0,0 +1,16 @@ +.LinksEmptyCase { + display: flex; + flex-direction: column; + justify-content: center; + align-content: center; + padding-top: 40px; + padding-bottom: 40px; + height: 50vh; + text-align: center; + + .text { + color: #000; + font-size: 16px; + font-weight: 400; + } +} diff --git a/src/components/folder/LinksList/LinksEmptyCase/LinksEmptyCase.tsx b/src/components/folder/LinksList/LinksEmptyCase/LinksEmptyCase.tsx new file mode 100644 index 000000000..551b1ec87 --- /dev/null +++ b/src/components/folder/LinksList/LinksEmptyCase/LinksEmptyCase.tsx @@ -0,0 +1,12 @@ +import classNames from "classnames/bind"; +import styles from "./LinksEmptyCase.module.scss"; + +const cn = classNames.bind(styles); + +export default function LinkEmptyCase() { + return ( +
+

저장된 링크가 없습니다

+
+ ); +} diff --git a/src/components/folder/LinksList/LinksList.module.scss b/src/components/folder/LinksList/LinksList.module.scss new file mode 100644 index 000000000..372b50606 --- /dev/null +++ b/src/components/folder/LinksList/LinksList.module.scss @@ -0,0 +1,7 @@ +.linkList { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + column-gap: 20px; + row-gap: 24px; +} diff --git a/src/components/folder/LinksList/LinksList.tsx b/src/components/folder/LinksList/LinksList.tsx new file mode 100644 index 000000000..77c345514 --- /dev/null +++ b/src/components/folder/LinksList/LinksList.tsx @@ -0,0 +1,42 @@ +import classNames from "classnames/bind"; +import { useQuery } from "@tanstack/react-query"; + +import { LinkOverview, LinksEmptyCase } from "."; +import { getFolderIdLinksData } from "@/src/apis"; +import type { TLink } from "@/src/types/type"; + +import styles from "./LinksList.module.scss"; + +const cn = classNames.bind(styles); + +interface LinksListProps { + folderId?: number | null; +} + +export default function LinksList({ folderId }: LinksListProps) { + const { data: totalLinksData } = useQuery({ + queryKey: ["linksData"], + }); + + const { data: folderIdLinksData } = useQuery({ + queryKey: ["linksData", folderId], + queryFn: () => getFolderIdLinksData(folderId!), + enabled: !!folderId === true, + }); + + const LINKS = folderId ? folderIdLinksData : totalLinksData; + + return ( + <> + {LINKS && LINKS.length > 0 ? ( +
+ {LINKS.map((link) => ( + + ))} +
+ ) : ( + + )} + + ); +} diff --git a/src/components/folder/LinksList/index.ts b/src/components/folder/LinksList/index.ts new file mode 100644 index 000000000..23096229a --- /dev/null +++ b/src/components/folder/LinksList/index.ts @@ -0,0 +1,2 @@ +export { default as LinkOverview } from "./LinkOverview/LinkOverview"; +export { default as LinksEmptyCase } from "./LinksEmptyCase/LinksEmptyCase"; diff --git a/src/components/folder/index.ts b/src/components/folder/index.ts new file mode 100644 index 000000000..e5b6e0fde --- /dev/null +++ b/src/components/folder/index.ts @@ -0,0 +1,2 @@ +export { default as LinksList } from "./LinksList/LinksList"; +export { default as FavoriteButtonList } from "./FavoriteButtonList/FavoriteButtonList"; diff --git a/src/components/index.ts b/src/components/index.ts new file mode 100644 index 000000000..6b7de0722 --- /dev/null +++ b/src/components/index.ts @@ -0,0 +1,15 @@ +// RootLayout +export { default as RootLayout } from "../../pages/RootLayout"; + +// LandingLayout +export { default as LandingHeader } from "./landing/Header/Header"; +export { default as LandingContainer } from "./landing/Container/Container"; + +// AuthLayout +export { default as SignInForm } from "./auth/AuthForm/SignInForm"; +export { default as SignUpForm } from "./auth/AuthForm/SignUpForm"; +export { default as LinkBox } from "./auth/LinkBox/LinkBox"; +export { default as LogoBox } from "./auth/LogoBox/LogoBox"; + +// FolderLayout +export { default as Folder } from "./folder/Folder"; diff --git a/src/components/landing/Container/Container.module.scss b/src/components/landing/Container/Container.module.scss new file mode 100644 index 000000000..beaff15fa --- /dev/null +++ b/src/components/landing/Container/Container.module.scss @@ -0,0 +1,8 @@ +.container { + width: 100vw; + padding: 70px 32px 120px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} diff --git a/src/components/landing/Container/Container.tsx b/src/components/landing/Container/Container.tsx new file mode 100644 index 000000000..a9c4808cf --- /dev/null +++ b/src/components/landing/Container/Container.tsx @@ -0,0 +1,17 @@ +import classNames from "classnames/bind"; +import { LANDING_CONTENTS } from "@/src/constants"; +import { Content } from "./Content"; + +import styles from "./Container.module.scss"; + +const cn = classNames.bind(styles); + +export default function Container() { + return ( +
+ {LANDING_CONTENTS.map((content, i) => { + return ; + })} +
+ ); +} diff --git a/src/components/landing/Container/Content/Content.module.scss b/src/components/landing/Container/Content/Content.module.scss new file mode 100644 index 000000000..a0d21f7c5 --- /dev/null +++ b/src/components/landing/Container/Content/Content.module.scss @@ -0,0 +1,29 @@ +.contentBox { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + gap: 158px; + padding: 50px 32px; + + .textBox { + display: inline-flex; + flex-direction: column; + gap: 10px; + + .title { + color: #000; + font-size: 48px; + font-weight: 700; + letter-spacing: -0.3px; + flex-shrink: 0; + + .gradient { + background: linear-gradient(96deg, #fe8a8a 1.72%, #a4ceff 74.97%); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + } + } +} diff --git a/src/components/landing/Container/Content/Content.tsx b/src/components/landing/Container/Content/Content.tsx new file mode 100644 index 000000000..6cedfe5db --- /dev/null +++ b/src/components/landing/Container/Content/Content.tsx @@ -0,0 +1,36 @@ +import classNames from "classnames/bind"; +import Image from "next/image"; +import { Content as ContentData } from "@/src/types/type"; + +import styles from "./Content.module.scss"; + +const cn = classNames.bind(styles); + +interface ContentProps { + content: ContentData; + id: number; +} + +export default function Content({ content, id }: ContentProps) { + return ( +
+
+

+ {content.title[0]} +
+ {content.title[1]} + {content.title[2]} +

+

{content.description}

+
+ {content.alt} +
+ ); +} diff --git a/src/components/landing/Container/Content/index.ts b/src/components/landing/Container/Content/index.ts new file mode 100644 index 000000000..c40cab978 --- /dev/null +++ b/src/components/landing/Container/Content/index.ts @@ -0,0 +1 @@ +export { default as Content } from "./Content"; diff --git a/src/components/landing/Header/Header.module.scss b/src/components/landing/Header/Header.module.scss new file mode 100644 index 000000000..1f20e5131 --- /dev/null +++ b/src/components/landing/Header/Header.module.scss @@ -0,0 +1,46 @@ +.header { + width: 100vw; + background: #f0f6ff; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 40px; + padding: 70px 32px 0; + + .text { + text-align: center; + font-size: 64px; + font-weight: 700; + line-height: 80px; + color: #000; + + .textGradient { + background: linear-gradient(91deg, #6d6afe 17.28%, #ff9f9f 74.98%); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + } + + .button { + display: flex; + width: 350px; + padding: 16px 20px; + justify-content: center; + align-items: center; + gap: 10px; + + color: var(--Grey-Light, #f5f5f5); + font-size: 18px; + font-weight: 600; + line-height: normal; + + border: none; + border-radius: 8px; + background: var( + --gra-purpleblue-to-skyblue, + linear-gradient(91deg, #6d6afe 0.12%, #6ae3fe 101.84%) + ); + } +} diff --git a/src/components/landing/Header/Header.tsx b/src/components/landing/Header/Header.tsx new file mode 100644 index 000000000..d4efe33ec --- /dev/null +++ b/src/components/landing/Header/Header.tsx @@ -0,0 +1,32 @@ +import classNames from "classnames/bind"; +import Image from "next/image"; +import { Img_Example } from "@/public"; + +import styles from "./Header.module.scss"; +import Link from "next/link"; +import { ROUTER } from "@/src/constants"; + +const cn = classNames.bind(styles); + +export default function Header() { + return ( +
+

+ 세상의 모든 정보
+ 쉽게 저장하고 관리해 보세요 +

+ + + + 예시이미지 +
+ ); +} diff --git a/src/components/share/UserProfile/UserProfile.module.scss b/src/components/share/UserProfile/UserProfile.module.scss new file mode 100644 index 000000000..8076f196f --- /dev/null +++ b/src/components/share/UserProfile/UserProfile.module.scss @@ -0,0 +1,34 @@ +.UserProfile { + padding-top: 113px; + padding-left: 32px; + padding-right: 32px; + padding-bottom: 60px; + background: var(--Linkbrary-bg, #f0f6ff); + + .profileInfos { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: #000; + gap: 12px; + + .profileImg { + width: 60px; + padding: 4px; + border-radius: 47px; + } + + .profileName { + font-size: 16px; + font-weight: 400; + } + + .folderName { + font-feature-settings: "clig" off, "liga" off; + font-size: 40px; + font-weight: 600; + padding-top: 6px; + } + } +} diff --git a/src/components/share/UserProfile/UserProfile.tsx b/src/components/share/UserProfile/UserProfile.tsx new file mode 100644 index 000000000..167b81940 --- /dev/null +++ b/src/components/share/UserProfile/UserProfile.tsx @@ -0,0 +1,31 @@ +import classNames from "classnames/bind"; +import Image from "next/image"; +import type { User } from "@/src/types/type"; + +import styles from "./UserProfile.module.scss"; + +const cn = classNames.bind(styles); + +interface UserProfileProps { + userData: User[]; +} + +export default function UserProfile({ userData }: UserProfileProps) { + const { id, image_source, email, name } = userData[0]; + + return ( +
+
+ user profile image +

{email}

+ {name} +
+
+ ); +} diff --git a/src/constants/index.ts b/src/constants/index.ts index a6b20dc40..0ec74b21f 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -1,14 +1,47 @@ -const API_BASE_URL = "https://bootcamp-api.codeit.kr/api/"; -const TEAM_ID = 11; +import { Img_Link, Img_Manage, Img_Serch, Img_Share } from "@/public"; +import { Content } from "../types/type"; -const SHARED_LINKS = `${API_BASE_URL}sample/folder`; -const FOLDERS = `${API_BASE_URL}users/${TEAM_ID}/folders`; -const LINKS = `${API_BASE_URL}users/${TEAM_ID}/links`; -const USER = `${API_BASE_URL}users/1`; +export const ROUTER = { + HOME: "/", + SIGN_IN: "sign-in", + SIGN_UP: "sign-up", + FOLDER: "/folder", +} as const; -export const END_POINT = { - FOLDERS, - LINKS, - USER, - SHARED_LINKS, -}; +export const SNS_LINK = { + FACEBOOK: "https://www.facebook.com", + TWITTER: "https://twitter.com", + YOUTUBE: "https://www.youtube.com", + INSTAGRAM: "https://www.instagram.com", + GOOGLE: "https://www.google.com", + KAKAO: "https://www.kakaocorp.com/page", +} as const; + +export const LANDING_CONTENTS = [ + { + title: ["원하는 링크를", "저장", "하세요"], + description: + "나중에 읽고 싶은 글, 다시 보고 싶은 영상, 사고 싶은 옷, 기억하고 싶은 모든 것을 한 공간에 저장하세요.", + img: Img_Link, + alt: "example", + }, + { + title: ["링크를 폴더로", "관리", "하세요"], + description: "나만의 폴더를 무제한으로 만들고 다양하게 활용할 수 있습니다.", + img: Img_Manage, + alt: "example", + }, + { + title: ["저장한 링크를", "공유", "해 보세요"], + description: + "여러 링크를 폴더에 담고 공유할 수 있습니다. 가족, 친구, 동료들에게 쉽고 빠르게 링크를 공유해 보세요.", + img: Img_Share, + alt: "example", + }, + { + title: ["저장한 링크를", "검색", "해 보세요"], + description: "중요한 정보들을 검색으로 쉽게 찾아보세요.", + img: Img_Serch, + alt: "example", + }, +] as Content[]; diff --git a/src/types/type.ts b/src/types/type.ts new file mode 100644 index 000000000..731c52075 --- /dev/null +++ b/src/types/type.ts @@ -0,0 +1,33 @@ +import { StaticImageData } from "next/image"; + +export interface Content { + title: string[]; + description: string; + img: StaticImageData; + alt: string; +} + +export interface User { + id: number; + name: string; + image_source: string; + email: string; +} + +export interface Favorite { + created_at: string; + favorite: boolean; + id: number; + link_count: number; + name: string; +} + +export interface TLink { + id: number; + created_at: string; + description: string; + favorite: boolean; + image_source: string; + title: string; + url: string; +} diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 000000000..48a3c4969 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,3 @@ +export { default as getElapsedTime } from "./getElapsedTime"; +export { default as getFormattedDate } from "./getFormattedDate"; +export { default as getValidUrl } from "./getValidUrl"; diff --git a/styles/reset.css b/styles/reset.css new file mode 100644 index 000000000..24c834896 --- /dev/null +++ b/styles/reset.css @@ -0,0 +1,134 @@ +/* /styles/reset.css */ + +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} +body { + line-height: 1; +} +ol, +ul { + list-style: none; +} +blockquote, +q { + quotes: none; +} +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ""; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +* { + box-sizing: border-box; +} + +a { + text-decoration: none; +}