From c5a675c52c701b4dd3365cdbe3bbb647d35470b9 Mon Sep 17 00:00:00 2001 From: YuGilJong <101111364+XionWCFM@users.noreply.github.com> Date: Tue, 11 Feb 2025 12:08:48 +0900 Subject: [PATCH] feat: add useQueryString | Image Automation (#91) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: querystirng, vite configuration * feat: image migration * fix: build error fix * fix: 자동변환 로직 추가 --- imageConstantsGenerator.mts | 100 ++ package-lock.json | 1216 +++++++++++++++-- package.json | 7 +- packages/http/index.ts | 6 +- .../BookRecordWriteProgressStep.tsx | 26 +- .../components/SearchStep/WriteSearchList.tsx | 16 +- src/entities/user/api/postUsersTest.ts | 21 + src/entities/user/model/user.model.ts | 3 + .../timer/components/TimerSpeechBubble.tsx | 7 +- src/features/timer/lib/timer.constants.ts | 5 - src/features/userExp/HabitSection.tsx | 15 +- src/features/userInfo/UserInfoSection.tsx | 9 +- src/pages/OnBoardingPage.tsx | 11 +- src/pages/ProfilePage.tsx | 11 +- src/pages/TimerPage.tsx | 4 +- src/shared/hooks/useBooleanQueryString.ts | 19 + src/shared/hooks/useQueryString.ts | 146 ++ .../images/bookrecord/bookrecordImages.ts | 9 + src/shared/images/common/commonImages.ts | 6 + src/shared/images/gauge/gaugeImages.ts | 5 + src/shared/images/habit/habitImages.ts | 4 + src/shared/images/home/homeImages.ts | 4 + src/shared/images/logo/logoImages.ts | 4 + .../images/notification/notificationImages.ts | 3 + src/shared/images/timer/timerImages.ts | 5 + src/shared/images/toast/toastImages.ts | 3 + tsconfig.app.json | 3 +- vite.config.ts | 12 +- 28 files changed, 1501 insertions(+), 179 deletions(-) create mode 100644 imageConstantsGenerator.mts create mode 100644 src/entities/user/api/postUsersTest.ts delete mode 100644 src/features/timer/lib/timer.constants.ts create mode 100644 src/shared/hooks/useBooleanQueryString.ts create mode 100644 src/shared/hooks/useQueryString.ts create mode 100644 src/shared/images/bookrecord/bookrecordImages.ts create mode 100644 src/shared/images/common/commonImages.ts create mode 100644 src/shared/images/gauge/gaugeImages.ts create mode 100644 src/shared/images/habit/habitImages.ts create mode 100644 src/shared/images/home/homeImages.ts create mode 100644 src/shared/images/logo/logoImages.ts create mode 100644 src/shared/images/notification/notificationImages.ts create mode 100644 src/shared/images/timer/timerImages.ts create mode 100644 src/shared/images/toast/toastImages.ts diff --git a/imageConstantsGenerator.mts b/imageConstantsGenerator.mts new file mode 100644 index 0000000..f1eefd9 --- /dev/null +++ b/imageConstantsGenerator.mts @@ -0,0 +1,100 @@ +import fs from "node:fs"; +import path from "node:path"; +import sharp from "sharp"; + +const __dirname = path.dirname(new URL(import.meta.url).pathname); + +const publicImagesDir = path.join(__dirname, "public/images"); +const srcDir = path.join(__dirname, "src/shared/images"); + +// 이미지 파일을 WebP 형식으로 변환하는 함수 +const convertToWebP = async (inputPath: string, outputPath: string) => { + try { + await sharp(inputPath) + .webp({ quality: 80 }) // 80% 품질로 WebP로 변환 + .toFile(outputPath); + } catch (error) { + console.error(`Error converting ${inputPath}: ${error}`); + } +}; + +// 원본 파일 삭제 함수 +const deleteOriginalFile = (filePath: string) => { + try { + fs.unlinkSync(filePath); + } catch (error) { + console.error(`Error deleting file: ${filePath} - ${error}`); + } +}; + +const getImageFiles = (dir: string) => { + const files = fs.readdirSync(dir); + return files.filter((file) => + ["webp", "png", "jpg", "jpeg"].includes(path.extname(file).slice(1)), + ); +}; + +const toPascalCase = (str: string) => { + return str + .replace(/([a-zA-Z0-9])([._-])([a-zA-Z0-9])/g, (_match, p1, _p2, p3) => { + return `${p1.toUpperCase()}_${p3.toUpperCase()}`; + }) + .replace(/^\w/, (match) => match.toUpperCase()) + .replace(/[^A-Za-z0-9_]/g, "_") + .toUpperCase(); +}; + +const createTSFile = (folderName: string, images: string[]) => { + const folderPath = path.join(srcDir, folderName); + + if (!fs.existsSync(folderPath)) { + fs.mkdirSync(folderPath, { recursive: true }); + } + + const tsFilePath = path.join(folderPath, `${folderName}Images.ts`); + const content = `export const ${folderName.toUpperCase()}_ASSETS = { +${images.map((image) => ` ${toPascalCase(image)}: "/images/${folderName}/${image}"`).join(",\n")} +};`; + + fs.writeFileSync(tsFilePath, content); +}; + +// 이미지를 변환하고, TS 파일을 생성하는 함수 +const processImageFiles = async (folderName: string) => { + const imageFiles = getImageFiles(path.join(publicImagesDir, folderName)); + + const processedImages: string[] = []; + + for (const imageFile of imageFiles) { + const extname = path.extname(imageFile).toLowerCase(); + const inputPath = path.join(publicImagesDir, folderName, imageFile); + const webpFileName = `${path.basename(imageFile, extname)}.webp`; + const outputPath = path.join(publicImagesDir, folderName, webpFileName); + + // 이미지가 webp가 아니면 변환 + if (extname !== ".webp") { + await convertToWebP(inputPath, outputPath); + processedImages.push(webpFileName); // 변환된 WebP 파일 추가 + deleteOriginalFile(inputPath); // 원본 파일 삭제 + } else { + processedImages.push(imageFile); // 이미 WebP인 경우 그대로 추가 + } + } + + // 변환이 끝난 후에 코드 생성 + if (processedImages.length > 0) { + createTSFile(folderName, processedImages); + } +}; + +const generateImageTSFiles = async () => { + const subDirs = fs + .readdirSync(publicImagesDir) + .filter((subDir) => fs.statSync(path.join(publicImagesDir, subDir)).isDirectory()); + + for (const subDir of subDirs) { + await processImageFiles(subDir); + } +}; + +generateImageTSFiles(); diff --git a/package-lock.json b/package-lock.json index 091710e..89711ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -80,11 +80,13 @@ "lefthook": "^1.10.1", "msw": "^2.7.0", "postcss": "^8.4.49", + "sharp": "^0.33.5", "storybook": "^8.4.7", "tailwind-merge": "^2.6.0", "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7", "tailwindcss-animated": "^1.1.2", + "tsx": "^4.19.2", "typescript": "~5.6.2", "typescript-eslint": "^8.18.2", "vite": "^6.0.5", @@ -899,6 +901,17 @@ "node": ">=v18" } }, + "node_modules/@emnapi/runtime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.24.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", @@ -1602,165 +1615,545 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@inquirer/confirm": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.2.tgz", - "integrity": "sha512-VKgaKxw2I3cu2smedeMFyxuYyI+HABlFY1Px4j8NueA7xDskKAo9hxEQemTpp1Fu4OiTtOCgU4eK91BVuBKH3g==", + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.1.3", - "@inquirer/type": "^3.0.2" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "@types/node": ">=18" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" } }, - "node_modules/@inquirer/core": { - "version": "10.1.3", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.3.tgz", - "integrity": "sha512-+7/dCYwDku2xfcWJWX6Urxb8aRz6d0K+4lRgIBM08ktE84dm++RPROgnVfWq4hLK5FVu/O4rbO9HnJtaz3pt2w==", + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/figures": "^1.0.9", - "@inquirer/type": "^3.0.2", - "ansi-escapes": "^4.3.2", - "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" } }, - "node_modules/@inquirer/core/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@inquirer/figures": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.9.tgz", - "integrity": "sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==", + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@inquirer/type": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.2.tgz", - "integrity": "sha512-ZhQ4TvhwHZF+lGhQ2O/rsjo80XoZR5/5qhOY3t6FJuX5XBg5Be8YzYTvaUGJnc12AUGI2nr4QSUE4PhKSigx7g==", + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "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" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@isaacs/cliui/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==", + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" } }, - "node_modules/@isaacs/cliui/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==", + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" } }, - "node_modules/@joshwooding/vite-plugin-react-docgen-typescript": { + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.2.tgz", + "integrity": "sha512-VKgaKxw2I3cu2smedeMFyxuYyI+HABlFY1Px4j8NueA7xDskKAo9hxEQemTpp1Fu4OiTtOCgU4eK91BVuBKH3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.3", + "@inquirer/type": "^3.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/core": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.3.tgz", + "integrity": "sha512-+7/dCYwDku2xfcWJWX6Urxb8aRz6d0K+4lRgIBM08ktE84dm++RPROgnVfWq4hLK5FVu/O4rbO9HnJtaz3pt2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.9", + "@inquirer/type": "^3.0.2", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.9.tgz", + "integrity": "sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.2.tgz", + "integrity": "sha512-ZhQ4TvhwHZF+lGhQ2O/rsjo80XoZR5/5qhOY3t6FJuX5XBg5Be8YzYTvaUGJnc12AUGI2nr4QSUE4PhKSigx7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "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-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/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, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "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/@isaacs/cliui/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, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.4.2.tgz", "integrity": "sha512-feQ+ntr+8hbVudnsTUapiMN9q8T90XA1d5jn9QzY09sNoj4iD9wi0PY1vsBFTda4ZjEaxRK9S81oarR2nj7TFQ==", @@ -5406,6 +5799,20 @@ "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==", + "dev": true, + "license": "MIT", + "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", @@ -5426,10 +5833,21 @@ "dev": true, "license": "MIT" }, - "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "license": "MIT", "engines": { "node": ">=18" @@ -5709,6 +6127,16 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -6687,6 +7115,19 @@ "node": ">= 0.4" } }, + "node_modules/get-tsconfig": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/git-raw-commits": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", @@ -9051,6 +9492,16 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -9202,6 +9653,46 @@ "node": ">= 0.4" } }, + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -9245,6 +9736,23 @@ "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/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==", + "dev": true, + "license": "MIT" + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9863,6 +10371,474 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", + "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } + }, "node_modules/turbo-stream": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", diff --git a/package.json b/package.json index 7c8a7bb..fc973fa 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite --host", + "dev": "npm run generate:image && vite --host", "build": "tsc -b && vite build", "preview": "vite preview", "storybook": "storybook dev -p 6006", @@ -14,7 +14,8 @@ "ci:test": "vitest run", "report": "vitest run --coverage.enabled true", "ci:check": "npx @biomejs/biome check --config-path=./biome-ci.json --diagnostic-level=error --write .", - "ci:check:nowrite": "npx @biomejs/biome check --config-path=./biome-ci.json --diagnostic-level=error ." + "ci:check:nowrite": "npx @biomejs/biome check --config-path=./biome-ci.json --diagnostic-level=error .", + "generate:image": "tsx imageConstantsGenerator.mts" }, "dependencies": { "@hookform/resolvers": "^3.9.1", @@ -89,11 +90,13 @@ "lefthook": "^1.10.1", "msw": "^2.7.0", "postcss": "^8.4.49", + "sharp": "^0.33.5", "storybook": "^8.4.7", "tailwind-merge": "^2.6.0", "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7", "tailwindcss-animated": "^1.1.2", + "tsx": "^4.19.2", "typescript": "~5.6.2", "typescript-eslint": "^8.18.2", "vite": "^6.0.5", diff --git a/packages/http/index.ts b/packages/http/index.ts index bfd4708..68fb5a4 100644 --- a/packages/http/index.ts +++ b/packages/http/index.ts @@ -3,7 +3,11 @@ import { createHttp } from "./createHttp"; import { isHttpError } from "./error"; import type { ApiSuccessResponse } from "./type"; -const http = createHttp({ prefixUrl: env.VITE_API_URL, retry: { limit: 0 } }); +const http = createHttp({ + prefixUrl: env.VITE_API_URL, + retry: { limit: 0 }, + credentials: "include", +}); export { createHttp, isHttpError, http }; diff --git a/src/entities/record/components/ProgressStep/BookRecordWriteProgressStep.tsx b/src/entities/record/components/ProgressStep/BookRecordWriteProgressStep.tsx index 00a6eaa..4d7a1e5 100644 --- a/src/entities/record/components/ProgressStep/BookRecordWriteProgressStep.tsx +++ b/src/entities/record/components/ProgressStep/BookRecordWriteProgressStep.tsx @@ -9,6 +9,7 @@ import { Stack } from "@repo/ui/Stack"; import { useDraft } from "@xionwcfm/react"; import { memo } from "react"; import { getGaugeMessage } from "~/entities/record/model/record.constants"; +import { GAUGE_ASSETS } from "~/shared/images/gauge/gaugeImages"; export interface BookRecordWriteProgressStepProps { gauge?: number; @@ -79,8 +80,12 @@ const ImageSection = memo((props: { status: "0" | "50" | "100"; value: number }) key={"0"} transition={{ duration: GAUGE_DURATION_POLICY, ease: GAUGE_EASE_POLICY }} > - read gauge 0 image - + read gauge 0 image + {props.value}% @@ -90,7 +95,11 @@ const ImageSection = memo((props: { status: "0" | "50" | "100"; value: number }) key={"50"} transition={{ duration: GAUGE_DURATION_POLICY, ease: GAUGE_EASE_POLICY }} > - read gauge 50 image + read gauge 50 image {props.value}% @@ -101,7 +110,11 @@ const ImageSection = memo((props: { status: "0" | "50" | "100"; value: number }) key={"100"} transition={{ duration: GAUGE_DURATION_POLICY, ease: GAUGE_EASE_POLICY }} > - read gauge 100 image + read gauge 100 image {props.value}% @@ -115,11 +128,6 @@ const ImageSection = memo((props: { status: "0" | "50" | "100"; value: number }) const GAUGE_DURATION_POLICY = 0.3; // 300ms duration const GAUGE_EASE_POLICY = "easeOut" as const; -const GAUGE_ASSETS = { - "0": "/images/gauge/gauge_0.webp", - "50": "/images/gauge/gauge_50.webp", - "100": "/images/gauge/gauge_100.webp", -}; const getStatus = (value: number) => { if (value >= 70) { diff --git a/src/entities/record/components/SearchStep/WriteSearchList.tsx b/src/entities/record/components/SearchStep/WriteSearchList.tsx index 4033714..be320f7 100644 --- a/src/entities/record/components/SearchStep/WriteSearchList.tsx +++ b/src/entities/record/components/SearchStep/WriteSearchList.tsx @@ -10,6 +10,7 @@ import { useInfiniteQuery } from "@tanstack/react-query"; import { InView } from "@xionwcfm/react"; import { getBooksSearchInfiniteQueryOptions } from "~/entities/record/api/getBooksSearch"; import type { Book } from "~/entities/record/model/book.model"; +import { BOOKRECORD_ASSETS } from "~/shared/images/bookrecord/bookrecordImages"; import { SearchBookItem } from "./WriteSearchBookItem"; import { useWriteSearchStore } from "./WriteSearchStep.store"; @@ -65,11 +66,6 @@ export const WriteSearchList = wrap.Suspense().on( }, ); -const SEARCH_ASSETS = { - FIRST_FALLBACK: "/images/bookrecord/bookrecord_search_empty_fallback.webp", - SEARCH_RESULT_EMPTY_FALLBACK: "/images/bookrecord/bookrecord_tab_no_search_result_fallback.webp", -}; - const FirstFallback = (props: { isLoading?: boolean }) => { const { isLoading } = props; return ( @@ -81,7 +77,10 @@ const FirstFallback = (props: { isLoading?: boolean }) => { )} > - 검색 결과 없음 + 검색 결과 없음 { - 검색 결과 없음 + 검색 결과 없음 diff --git a/src/entities/user/api/postUsersTest.ts b/src/entities/user/api/postUsersTest.ts new file mode 100644 index 0000000..e49fcce --- /dev/null +++ b/src/entities/user/api/postUsersTest.ts @@ -0,0 +1,21 @@ +import { http } from "@repo/http"; + +type PostUsersTestRequestBody = { + email: string; + isShortLivedAccessToken?: boolean; +}; + +type PostUsersTestResponse = { + id: number | string; + nickname: string; + email: string; + exp: number; +}; + +export const postUsersTest = async (body: PostUsersTestRequestBody) => { + const response = await http.post( + "/users/test", + body, + ); + return response.data; +}; diff --git a/src/entities/user/model/user.model.ts b/src/entities/user/model/user.model.ts index 84e80df..b8975cb 100644 --- a/src/entities/user/model/user.model.ts +++ b/src/entities/user/model/user.model.ts @@ -1,4 +1,7 @@ export interface User { + id: number | string; + nickname: string; + email: string; exp: number; } diff --git a/src/features/timer/components/TimerSpeechBubble.tsx b/src/features/timer/components/TimerSpeechBubble.tsx index 5ce4f8b..731d23a 100644 --- a/src/features/timer/components/TimerSpeechBubble.tsx +++ b/src/features/timer/components/TimerSpeechBubble.tsx @@ -4,8 +4,8 @@ import { Text } from "@repo/design-system/Text"; import { cn } from "@repo/design-system/cn"; import { Box } from "@repo/ui/Box"; import type { ComponentPropsWithoutRef } from "react"; +import { TIMER_ASSETS } from "~/shared/images/timer/timerImages"; import { getTimerSpeechBubbleText } from "../lib/getTimerSpeechBubbleText"; -import { TIMER_ASSETS } from "../lib/timer.constants"; import { useTimerStore } from "../model/TimerProvider"; interface TimerSpeechBubbleProps extends ComponentPropsWithoutRef<"div"> {} @@ -17,7 +17,10 @@ export const TimerSpeechBubble = (props: Omit - timer speech bubble background image + timer speech bubble background image { const { normalText, boldText } = props; return ( @@ -172,14 +172,18 @@ const TodayHabit = () => { {"6일 연속 \n성공했어요!"} - mercury character + mercury character habit block { ); }; - -const HABIIT_ASSETS = { - LOGO: "/images/habit/mercury_habit_logo.webp", - BLOCK: "/images/habit/habit_block.webp", -}; diff --git a/src/features/userInfo/UserInfoSection.tsx b/src/features/userInfo/UserInfoSection.tsx index 650a039..439c6f4 100644 --- a/src/features/userInfo/UserInfoSection.tsx +++ b/src/features/userInfo/UserInfoSection.tsx @@ -10,6 +10,7 @@ import { motion } from "motion/react"; import { useTestUserQueryOptions } from "~/entities/user/api/getTestUser"; import { ExpProgressBar } from "~/entities/user/components/ExpProgressBar"; import { calculateUserLevel, getExpPercentage, getGoalExp } from "~/entities/user/model/user.model"; +import { HOME_ASSETS } from "~/shared/images/home/homeImages"; const ExpSection = (props: { exp: number; goalExp: number; percentage: number; level: string }) => { const { exp, goalExp, percentage, level } = props; @@ -45,7 +46,7 @@ const Fallback = () => { 머큐리와 함께한 지 000일 - mercury character + mercury character @@ -90,7 +91,7 @@ export const MainSection = wrap mercury character ); }); - -const HOME_ASSETS = { - HOME_MERCURY: "/images/home/home_mercury.webp", -}; diff --git a/src/pages/OnBoardingPage.tsx b/src/pages/OnBoardingPage.tsx index 04f4448..ec4a19d 100644 --- a/src/pages/OnBoardingPage.tsx +++ b/src/pages/OnBoardingPage.tsx @@ -1,6 +1,7 @@ import { AspectRatio } from "@repo/design-system/AspectRatio"; import { Image } from "@repo/design-system/Image"; import { Text, textVariants } from "@repo/design-system/Text"; + import { toast } from "@repo/design-system/Toast"; import { cn } from "@repo/design-system/cn"; import { Center } from "@repo/ui/Center"; @@ -9,6 +10,7 @@ import { Flex } from "@repo/ui/Flex"; import { Spacing } from "@repo/ui/Spacing"; import { Stack } from "@repo/ui/Stack"; import { Link } from "react-router"; +import { LOGO_ASSETS } from "~/shared/images/logo/logoImages"; import { AppleButton } from "~/shared/ui/AppleButton"; import { GoogleButton } from "~/shared/ui/GoogleButton"; import { KakaoButton } from "~/shared/ui/KakaoButton"; @@ -27,13 +29,13 @@ const MercuryImageSection = () => { - mercury logo + mercury logo wordmark logo @@ -71,8 +73,3 @@ const SignUpSection = () => { ); }; - -const ONBOARDING_ASSETS = { - MERCURY_LOGIN_LOGO: "/images/logo/mercury_login_logo.webp", - WORDMARKLOGO_DARKBG: "/images/logo/wordmarklogo_darkbg.webp", -}; diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx index 71d8c9b..c4cf8de 100644 --- a/src/pages/ProfilePage.tsx +++ b/src/pages/ProfilePage.tsx @@ -2,6 +2,7 @@ import { AspectRatio } from "@repo/design-system/AspectRatio"; import { Image } from "@repo/design-system/Image"; import { Stack } from "@repo/ui/Stack"; import { motion } from "motion/react"; +import { LOGO_ASSETS } from "~/shared/images/logo/logoImages"; export default function Page() { return ( @@ -20,7 +21,11 @@ export default function Page() { transition={{ duration: 1.5, delay: 0.8 }} > - profile_logo + profile_logo ); } - -const PROFILE_ASSETS = { - PROFILE_LOGO: "/images/logo/mercury_login_logo.webp", -}; diff --git a/src/pages/TimerPage.tsx b/src/pages/TimerPage.tsx index fbe9a35..b418ea4 100644 --- a/src/pages/TimerPage.tsx +++ b/src/pages/TimerPage.tsx @@ -9,8 +9,8 @@ import { TimerButtonSection } from "~/features/timer/components/TimerButtonSecti import { TimerDescription } from "~/features/timer/components/TimerDescription"; import { TimerSpeechBubble } from "~/features/timer/components/TimerSpeechBubble"; import { TimerText } from "~/features/timer/components/TimerText"; -import { TIMER_ASSETS } from "~/features/timer/lib/timer.constants"; import { TimerEffector } from "~/features/timer/model/TimerEffector"; +import { TIMER_ASSETS } from "~/shared/images/timer/timerImages"; export default function TimerPage() { return ( @@ -32,7 +32,7 @@ export default function TimerPage() { - timer character + timer character diff --git a/src/shared/hooks/useBooleanQueryString.ts b/src/shared/hooks/useBooleanQueryString.ts new file mode 100644 index 0000000..a631a5a --- /dev/null +++ b/src/shared/hooks/useBooleanQueryString.ts @@ -0,0 +1,19 @@ +import { useCallback } from "react"; +import { useQueryString } from "~/shared/hooks/useQueryString"; + +export const useBooleanQueryString = (key: string, initialValue: boolean) => { + const [query, setQuery] = useQueryString({ [key]: initialValue }, { dependencies: [key] }); + + const onOpenChange = useCallback( + (bool: boolean) => { + setQuery({ [key]: bool }); + }, + [setQuery, key], + ); + + const toggle = useCallback(() => { + setQuery({ [key]: !query[key] }); + }, [setQuery, query, key]); + + return [query[key] ?? initialValue, onOpenChange, toggle] as const; +}; diff --git a/src/shared/hooks/useQueryString.ts b/src/shared/hooks/useQueryString.ts new file mode 100644 index 0000000..e8ddeb0 --- /dev/null +++ b/src/shared/hooks/useQueryString.ts @@ -0,0 +1,146 @@ +import { useRef, useSyncExternalStore } from "react"; + +type UseQueryStringProps = Record; + +export const useQueryString = ( + initialValue: T, + options?: { dependencies?: Array }, +) => { + const lastSnapshot = useRef(null); + const lastSearch = useRef(null); + + const getSnapshot = (): T => { + const currentSearch = window.location.search; + + // 이전 검색 문자열과 동일하면 캐시된 스냅샷 반환 + if (lastSearch.current === currentSearch && lastSnapshot.current) { + return lastSnapshot.current; + } + + const params = new URLSearchParams(currentSearch); + const obj: Partial = { ...initialValue }; + + params.forEach((value, key) => { + if (key in initialValue) { + const initialType = typeof initialValue[key as keyof T]; + //@ts-ignore + obj[key as keyof T] = + initialType === "number" + ? (Number(value) as T[keyof T]) + : initialType === "boolean" + ? value === ("true" as T[keyof T]) + : (value as T[keyof T]); + } + }); + + // 새로운 스냅샷과 검색 문자열 캐시 + lastSnapshot.current = obj as T; + lastSearch.current = currentSearch; + + return obj as T; + }; + + const getServerSnapshot = (): T => initialValue; + + const subscribe = (callback: () => void) => { + let previousValues: Partial = {}; + + if (options?.dependencies) { + const currentValues = getSnapshot(); + previousValues = options.dependencies.reduce( + (acc, key) => { + acc[key] = currentValues[key]; + return acc; + }, + {} as Partial, + ); + } + + const onChange = () => { + if (options?.dependencies) { + const currentValues = getSnapshot(); + const hasChanges = options.dependencies.some( + (key) => !isEqual(previousValues[key], currentValues[key]), + ); + + if (hasChanges) { + previousValues = options.dependencies.reduce( + (acc, key) => { + acc[key] = currentValues[key]; + return acc; + }, + {} as Partial, + ); + callback(); + } + } else { + callback(); + } + }; + + window.addEventListener("popstate", onChange); + + const patchHistoryMethod = (method: "pushState" | "replaceState") => { + const original = history[method]; + history[method] = function (...args) { + original.apply(this, args); + onChange(); + }; + }; + + patchHistoryMethod("pushState"); + patchHistoryMethod("replaceState"); + + return () => { + window.removeEventListener("popstate", onChange); + }; + }; + + const query = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); + + const setQuery = (newState: Partial, options: { replace?: boolean } = {}) => { + const params = new URLSearchParams(window.location.search); + + Object.entries(newState).forEach(([key, value]) => { + if (value === undefined || value === null) { + params.delete(key); + } else { + params.set(key, String(value)); + } + }); + + const newUrl = `${window.location.pathname}?${params.toString()}`; + + if (options.replace) { + window.history.replaceState({}, "", newUrl); + } else { + window.history.pushState({}, "", newUrl); + } + + window.dispatchEvent(new Event("popstate")); // 강제 상태 업데이트 + }; + + return [query, setQuery] as const; +}; + +function isEqual(a: any, b: any): boolean { + if (a === b) { + return true; + } + if (typeof a !== typeof b) { + return false; + } + + if (typeof a === "object") { + const aEntries = Object.entries(a); + const bEntries = Object.entries(b); + + if (aEntries.length !== bEntries.length) { + return false; + } + + return aEntries.every(([key, value]) => b[key as any] === value); + } + + return false; +} diff --git a/src/shared/images/bookrecord/bookrecordImages.ts b/src/shared/images/bookrecord/bookrecordImages.ts new file mode 100644 index 0000000..e95b652 --- /dev/null +++ b/src/shared/images/bookrecord/bookrecordImages.ts @@ -0,0 +1,9 @@ +export const BOOKRECORD_ASSETS = { + BOOKRECORD_SEARCH_EMPTY_FALLBACK_WEBP: "/images/bookrecord/bookrecord_search_empty_fallback.webp", + BOOKRECORD_TAB_EMPTY_FALLBACK_WEBP: "/images/bookrecord/bookrecord_tab_empty_fallback.webp", + BOOKRECORD_TAB_NO_RECORD_RESULT_FALLBACK_WEBP: + "/images/bookrecord/bookrecord_tab_no_record_result_fallback.webp", + BOOKRECORD_TAB_NO_SEARCH_RESULT_FALLBACK_WEBP: + "/images/bookrecord/bookrecord_tab_no_search_result_fallback.webp", + FLOATING_ICON_WEBP: "/images/bookrecord/floating_icon.webp", +}; diff --git a/src/shared/images/common/commonImages.ts b/src/shared/images/common/commonImages.ts new file mode 100644 index 0000000..b09e1c4 --- /dev/null +++ b/src/shared/images/common/commonImages.ts @@ -0,0 +1,6 @@ +export const COMMON_ASSETS = { + APPLE_BUTTON_WEBP: "/images/common/apple_button.webp", + GOOGLE_BUTTON_WEBP: "/images/common/google_button.webp", + KAKAO_BUTTON_WEBP: "/images/common/kakao_button.webp", + POLYGON_YELLOW_GREEN_WEBP: "/images/common/polygon_yellow_green.webp", +}; diff --git a/src/shared/images/gauge/gaugeImages.ts b/src/shared/images/gauge/gaugeImages.ts new file mode 100644 index 0000000..e473a9e --- /dev/null +++ b/src/shared/images/gauge/gaugeImages.ts @@ -0,0 +1,5 @@ +export const GAUGE_ASSETS = { + GAUGE_0_WEBP: "/images/gauge/gauge_0.webp", + GAUGE_100_WEBP: "/images/gauge/gauge_100.webp", + GAUGE_50_WEBP: "/images/gauge/gauge_50.webp", +}; diff --git a/src/shared/images/habit/habitImages.ts b/src/shared/images/habit/habitImages.ts new file mode 100644 index 0000000..374130c --- /dev/null +++ b/src/shared/images/habit/habitImages.ts @@ -0,0 +1,4 @@ +export const HABIT_ASSETS = { + HABIT_BLOCK_WEBP: "/images/habit/habit_block.webp", + MERCURY_HABIT_LOGO_WEBP: "/images/habit/mercury_habit_logo.webp", +}; diff --git a/src/shared/images/home/homeImages.ts b/src/shared/images/home/homeImages.ts new file mode 100644 index 0000000..c7e798c --- /dev/null +++ b/src/shared/images/home/homeImages.ts @@ -0,0 +1,4 @@ +export const HOME_ASSETS = { + HOME_LOGO_WEBP: "/images/home/home_logo.webp", + HOME_MERCURY_WEBP: "/images/home/home_mercury.webp", +}; diff --git a/src/shared/images/logo/logoImages.ts b/src/shared/images/logo/logoImages.ts new file mode 100644 index 0000000..3eef70b --- /dev/null +++ b/src/shared/images/logo/logoImages.ts @@ -0,0 +1,4 @@ +export const LOGO_ASSETS = { + MERCURY_LOGIN_LOGO_WEBP: "/images/logo/mercury_login_logo.webp", + WORDMARKLOGO_DARKBG_WEBP: "/images/logo/wordmarklogo_darkbg.webp", +}; diff --git a/src/shared/images/notification/notificationImages.ts b/src/shared/images/notification/notificationImages.ts new file mode 100644 index 0000000..95a8ccb --- /dev/null +++ b/src/shared/images/notification/notificationImages.ts @@ -0,0 +1,3 @@ +export const NOTIFICATION_ASSETS = { + NOTIFICATION_EMPTY_WEBP: "/images/notification/notification_empty.webp", +}; diff --git a/src/shared/images/timer/timerImages.ts b/src/shared/images/timer/timerImages.ts new file mode 100644 index 0000000..331f3cc --- /dev/null +++ b/src/shared/images/timer/timerImages.ts @@ -0,0 +1,5 @@ +export const TIMER_ASSETS = { + TIMER_CHARACTER_WEBP: "/images/timer/timer_character.webp", + TIMER_SPEECH_BUBBLE_BG_WEBP: "/images/timer/timer_speech_bubble_bg.webp", + TIMER_THUMB_WEBP: "/images/timer/timer_thumb.webp", +}; diff --git a/src/shared/images/toast/toastImages.ts b/src/shared/images/toast/toastImages.ts new file mode 100644 index 0000000..890896d --- /dev/null +++ b/src/shared/images/toast/toastImages.ts @@ -0,0 +1,3 @@ +export const TOAST_ASSETS = { + TOAST_MERCURY_ICON_WEBP: "/images/toast/toast_mercury_icon.webp", +}; diff --git a/tsconfig.app.json b/tsconfig.app.json index 2094155..ad62e85 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -30,6 +30,7 @@ "vitest.config.mts", ".storybook/Configure.mdx", "__tests__", - ".storybook/**/*.tsx" + ".storybook/**/*.tsx", + "vite.config.ts" ] } diff --git a/vite.config.ts b/vite.config.ts index 5b08c0c..8702216 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,11 @@ import react from "@vitejs/plugin-react-swc"; -import { defineConfig } from "vite"; +import { defineConfig, loadEnv } from "vite"; import tsConfigPaths from "vite-tsconfig-paths"; -export default defineConfig({ - plugins: [react(), tsConfigPaths()], -}); +export default ({ mode }: { mode: string }) => { + process.env = { ...process.env, ...loadEnv(mode, process.cwd()) }; + return defineConfig({ + plugins: [react(), tsConfigPaths()], + server: {}, + }); +};