diff --git a/.github/workflows/close-issue.yml b/.github/workflows/close-issue.yml new file mode 100644 index 00000000..c47ac0fd --- /dev/null +++ b/.github/workflows/close-issue.yml @@ -0,0 +1,26 @@ +name: Close Related Issue on Merge + +on: + pull_request: + types: [closed] + branches: [dev-be, dev-fe] + +jobs: + close-issues: + runs-on: ubuntu-latest + + steps: + - name: Close related issue + if: ${{ github.event.pull_request.merged == true }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + ISSUE_NUMBERS=$(echo "${{ github.event.pull_request.body }}" | grep -o -E '([cC]lose #[0-9]+)' | grep -o '[0-9]\+') + + for ISSUE_NUMBER in $ISSUE_NUMBERS; do + echo "Closing issue #$ISSUE_NUMBER" + curl -X PATCH -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER \ + -d '{"state": "closed"}' + done diff --git a/.github/workflows/deploy-frontend.yml b/.github/workflows/deploy-frontend.yml index 79cd98e2..72623155 100644 --- a/.github/workflows/deploy-frontend.yml +++ b/.github/workflows/deploy-frontend.yml @@ -47,10 +47,10 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Build and push backend Docker image + - name: Build and push frontend Docker image run: | - docker build -t ${{ secrets.DOCKER_USERNAME }}/backend:latest -f packages/backend/Dockerfile . - docker push ${{ secrets.DOCKER_USERNAME }}/backend:latest + docker build -t ${{ secrets.DOCKER_USERNAME }}/frontend:latest -f packages/frontend/Dockerfile . + docker push ${{ secrets.DOCKER_USERNAME }}/frontend:latest - name: Deploy to server uses: appleboy/ssh-action@v1.1.0 diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml new file mode 100644 index 00000000..9df02eff --- /dev/null +++ b/.github/workflows/storybook.yml @@ -0,0 +1,53 @@ +name: storybook deploy + +on: + push: + branches: ['dev-fe'] + + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + permissions: + contents: write + concurrency: + group: ${{ github.workflow }} + cancel-in-progress: true + + steps: + - name: Use repository source + uses: actions/checkout@v3 + + - name: Use node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Cache node_modules + id: cache + uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Install dependencies + run: yarn install + if: steps.cache.outputs.cache-hit != 'true' + + - name: Set PUBLIC_URL + run: | + PUBLIC_URL=$(echo $GITHUB_REPOSITORY | sed -r 's/^.+\/(.+)$/\/\1\//') + echo PUBLIC_URL=$PUBLIC_URL > .env + + - name: Build storybook + run: | + yarn client build-storybook + + - name: Deploy to gh-pages branch + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./packages/frontend/storybook-static diff --git a/.husky/commit-msg b/.husky/commit-msg old mode 100644 new mode 100755 diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100644 new mode 100755 index 5221d005..9f50c891 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,4 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -npx eslint --fix \ No newline at end of file +npx eslint --fix diff --git a/.prettierrc b/.prettierrc index 572c8dfc..96a79bf3 100644 --- a/.prettierrc +++ b/.prettierrc @@ -6,5 +6,6 @@ "printWidth": 80, "bracketSpacing": true, "endOfLine": "lf", - "useTabs": false + "useTabs": false, + "plugins": ["prettier-plugin-tailwindcss"] } diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile index 41ae4118..8efeb509 100644 --- a/packages/backend/Dockerfile +++ b/packages/backend/Dockerfile @@ -3,5 +3,10 @@ WORKDIR /packages COPY . . RUN yarn install --frozen-lockfile RUN yarn workspace backend build + +# 한국 시간에 맞춰 변경 +RUN apk add --no-cache tzdata +RUN cp /usr/share/zoneinfo/Asia/Seoul /etc/localtime && echo "Asia/Seoul" > /etc/timezone + EXPOSE 3000 CMD ["yarn", "workspace", "backend", "start:prod"] diff --git a/packages/backend/package.json b/packages/backend/package.json index fd67f9dc..c41b6046 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -26,6 +26,7 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.4.7", + "@nestjs/schedule": "^4.1.1", "@nestjs/swagger": "^8.0.5", "@nestjs/typeorm": "^10.0.2", "@nestjs/websockets": "^10.4.7", diff --git a/packages/backend/src/app.module.ts b/packages/backend/src/app.module.ts index 8b2be06b..d0c5f81d 100644 --- a/packages/backend/src/app.module.ts +++ b/packages/backend/src/app.module.ts @@ -1,6 +1,9 @@ import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { ScheduleModule } from '@nestjs/schedule'; import { TypeOrmModule } from '@nestjs/typeorm'; import { WinstonModule } from 'nest-winston'; +import { ScraperModule } from './scraper/scraper.module'; import { AuthModule } from '@/auth/auth.module'; import { SessionModule } from '@/auth/session.module'; import { ChatModule } from '@/chat/chat.module'; @@ -14,8 +17,9 @@ import { UserModule } from '@/user/user.module'; @Module({ imports: [ - //OpenapiScraperModule, - //StockPriceModule, + ConfigModule.forRoot({ cache: true, isGlobal: true }), + ScheduleModule.forRoot(), + ScraperModule, StockModule, UserModule, TypeOrmModule.forRoot( @@ -27,6 +31,7 @@ import { UserModule } from '@/user/user.module'; AuthModule, ChatModule, SessionModule, + ScraperModule, ], controllers: [], providers: [], diff --git a/packages/backend/src/configs/devTypeormConfig.ts b/packages/backend/src/configs/devTypeormConfig.ts index 41ceff73..2641d8d9 100644 --- a/packages/backend/src/configs/devTypeormConfig.ts +++ b/packages/backend/src/configs/devTypeormConfig.ts @@ -21,5 +21,7 @@ export const typeormDevelopConfig: TypeOrmModuleOptions = { password: process.env.DB_PASS, database: process.env.DB_NAME, entities: [__dirname + '/../**/*.entity.{js,ts}'], - logging: true, + //logging: true, + synchronize: true, }; + diff --git a/packages/backend/src/main.ts b/packages/backend/src/main.ts index 311bcdb9..14613072 100644 --- a/packages/backend/src/main.ts +++ b/packages/backend/src/main.ts @@ -10,6 +10,8 @@ import { useSwagger } from '@/configs/swagger.config'; async function bootstrap() { const app = await NestFactory.create(AppModule); const store = app.get(MEMORY_STORE); + + app.setGlobalPrefix('api'); app.use(session({ ...sessionConfig, store })); app.useGlobalPipes(new ValidationPipe({ transform: true })); useSwagger(app); diff --git a/packages/backend/src/openapi-scraper/korea-stock-info/dto/master-split.dto.ts b/packages/backend/src/openapi-scraper/korea-stock-info/dto/master-split.dto.ts deleted file mode 100644 index d58a1147..00000000 --- a/packages/backend/src/openapi-scraper/korea-stock-info/dto/master-split.dto.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { IsArray } from 'class-validator'; - -export class MasterSplit { - @IsArray() - shortCode: [number, number]; - - @IsArray() - standardCode: [number, number]; - - @IsArray() - koreanName: [number, number]; - - @IsArray() - groupCode: [number, number]; - - @IsArray() - marketCapSize: [number, number]; - - constructor( - shortCode: [number, number], - standardCode: [number, number], - koreanName: [number, number], - groupCode: [number, number], - marketCapSize: [number, number], - ) { - this.shortCode = shortCode; - this.standardCode = standardCode; - this.koreanName = koreanName; - this.groupCode = groupCode; - this.marketCapSize = marketCapSize; - } -} diff --git a/packages/backend/src/openapi-scraper/korea-stock-info/korea-stock-info.controller.spec.ts b/packages/backend/src/openapi-scraper/korea-stock-info/korea-stock-info.controller.spec.ts deleted file mode 100644 index 6818fba0..00000000 --- a/packages/backend/src/openapi-scraper/korea-stock-info/korea-stock-info.controller.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { KoreaStockInfoController } from './korea-stock-info.controller'; - -describe('KoreaStockInfoController', () => { - let controller: KoreaStockInfoController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [KoreaStockInfoController], - }).compile(); - - controller = module.get(KoreaStockInfoController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/packages/backend/src/openapi-scraper/korea-stock-info/korea-stock-info.controller.ts b/packages/backend/src/openapi-scraper/korea-stock-info/korea-stock-info.controller.ts deleted file mode 100644 index 0171b0d6..00000000 --- a/packages/backend/src/openapi-scraper/korea-stock-info/korea-stock-info.controller.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Controller } from '@nestjs/common'; - -@Controller('korea-stock-info') -export class KoreaStockInfoController {} diff --git a/packages/backend/src/openapi-scraper/korea-stock-info/korea-stock-info.service.ts b/packages/backend/src/openapi-scraper/korea-stock-info/korea-stock-info.service.ts deleted file mode 100644 index dd9aad35..00000000 --- a/packages/backend/src/openapi-scraper/korea-stock-info/korea-stock-info.service.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as https from 'https'; -import * as readline from 'readline'; -import * as iconv from 'iconv-lite'; -import * as unzipper from 'unzipper'; -import { MasterDownloadDto } from './dto/master-download.dto'; -import { Master } from './entities/stock.entity'; -import { config as dotenvConfig } from 'dotenv'; - -dotenvConfig(); - -@Injectable() -export class KoreaStockInfoService { - constructor() { - this.downloadMaster({ baseDir: './', target: 'kosdaq_code' }); - this.downloadMaster({ baseDir: './', target: 'kosdaq_code' }); - - this.getKospiMasterData({ baseDir: './', target: 'kosdaq_code' }); - this.getKosdaqMasterData({ baseDir: './', target: 'kosdaq_code' }); - } - - private async downloadFile(url: string, filePath: string): Promise { - return new Promise((resolve, reject) => { - const file = fs.createWriteStream(filePath); - https - .get(url, (response) => { - response.pipe(file); - file.on('finish', () => { - file.close(); - resolve(); - }); - }) - .on('error', (error) => { - fs.unlinkSync(filePath); - reject(error); - }); - }); - } - - private async extractZip(filePath: string, extractTo: string): Promise { - await fs - .createReadStream(filePath) - .pipe(unzipper.Extract({ path: extractTo })) - .promise(); - } - - private getValueFromMst(row: string, start: number, end: number) { - return row.slice(start, end).trim(); - } - - public async downloadMaster(downloadDto: MasterDownloadDto): Promise { - const { baseDir, target } = downloadDto; - const fileName = target + '.zip'; - const targetFileName = target + '.mst'; - const url = - process.env.MST_URL + - target + - '.mst.zip'; - const filePath = path.join(baseDir, fileName); - const extractedFile = path.join(baseDir, targetFileName); - - await this.downloadFile(url, filePath); - await this.extractZip(filePath, baseDir); - - fs.unlink(filePath, (err) => { - if (err) throw err; - }); - - return extractedFile; - } - - public async getKospiMasterData( - downloadDto: MasterDownloadDto, - ): Promise { - const targetFileName = downloadDto.target + '.mst'; - const fileName = path.join(downloadDto.baseDir, targetFileName); - const encoding = 'cp949'; - const kospiMasters: Master[] = []; - - const rl = readline.createInterface({ - input: fs.createReadStream(fileName).pipe(iconv.decodeStream(encoding)), - crlfDelay: Infinity, - }); - - for await (const row of rl) { - const shortCode = this.getValueFromMst(row, 0, 9); - const standardCode = this.getValueFromMst(row, 9, 21); - const koreanName = this.getValueFromMst(row, 21, row.length - 228); - const groupCode = this.getValueFromMst(row, row.length - 228, row.length - 226); - const marketCapSize = this.getValueFromMst(row, row.length - 226, row.length - 225); - - kospiMasters.push({ - shortCode, - standardCode, - koreanName, - groupCode, - marketCapSize, - }); - } - - console.log('Done'); - return kospiMasters; - } - - public async getKosdaqMasterData( - downloadDto: MasterDownloadDto, - ): Promise { - const targetFileName = downloadDto.target + '.mst'; - const fileName = path.join(downloadDto.baseDir, targetFileName); - const encoding = 'cp949'; - const kosdaqMasters: Master[] = []; - - const rl = readline.createInterface({ - input: fs.createReadStream(fileName).pipe(iconv.decodeStream(encoding)), - crlfDelay: Infinity, - }); - - for await (const row of rl) { - const shortCode = this.getValueFromMst(row, 0, 9); - const standardCode = this.getValueFromMst(row, 9, 21); - const koreanName = this.getValueFromMst(row, 21, row.length - 222); - const groupCode = this.getValueFromMst(row, row.length - 222, row.length - 220); - const marketCapSize = this.getValueFromMst(row, row.length - 220, row.length - 219); - - kosdaqMasters.push({ - shortCode, - standardCode, - koreanName, - groupCode, - marketCapSize, - }); - } - - console.log('Done'); - return kosdaqMasters; - } -} diff --git a/packages/backend/src/openapi-scraper/openapi-scraper.controller.ts b/packages/backend/src/openapi-scraper/openapi-scraper.controller.ts deleted file mode 100644 index 56e60188..00000000 --- a/packages/backend/src/openapi-scraper/openapi-scraper.controller.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Controller } from '@nestjs/common'; - -@Controller('openapi-scraper') -export class OpenapiScraperController {} diff --git a/packages/backend/src/openapi-scraper/openapi-scraper.module.ts b/packages/backend/src/openapi-scraper/openapi-scraper.module.ts deleted file mode 100644 index 7f272bd9..00000000 --- a/packages/backend/src/openapi-scraper/openapi-scraper.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Module } from '@nestjs/common'; -import { OpenapiScraperService } from './openapi-scraper.service'; - -@Module({ - imports: [], - controllers: [], - providers: [OpenapiScraperService], -}) -export class OpenapiScraperModule {} diff --git a/packages/backend/src/openapi-scraper/openapi-scraper.service.ts b/packages/backend/src/openapi-scraper/openapi-scraper.service.ts deleted file mode 100644 index a4b14527..00000000 --- a/packages/backend/src/openapi-scraper/openapi-scraper.service.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import axios from 'axios'; -import { openApiConfig } from './openapi.config'; - -@Injectable() -export class OpenapiScraperService { - private readonly config: typeof openApiConfig; - public constructor() { - this.config = openApiConfig; - this.getToken(); - } - - private async fetchOpenApi( - url: string, - query: {} | undefined, - body: {}, - ): Promise { - try { - const response = await axios.post(url + "/oauth2/tokenP", body); - return response.data; // 응답에서 data 부분만 추출 - } catch (error) { - throw new Error(`Request failed: ${error}`); - } - } - - private async getToken() { - const body = { - grant_type: 'client_credentials', - appkey: this.config.APPKEY, - appsecret: this.config.APPSECRET, - }; - const tmp = await this.fetchOpenApi(this.config.PROD!, undefined, body); - console.log(tmp.access_token); - } -} diff --git a/packages/backend/src/openapi-scraper/openapi-scraper.ts b/packages/backend/src/openapi-scraper/openapi-scraper.ts deleted file mode 100644 index 621c0988..00000000 --- a/packages/backend/src/openapi-scraper/openapi-scraper.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class OpenapiScraper {} diff --git a/packages/backend/src/openapi-scraper/openapi.config.ts b/packages/backend/src/openapi-scraper/openapi.config.ts deleted file mode 100644 index 3f3410ed..00000000 --- a/packages/backend/src/openapi-scraper/openapi.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as dotenv from 'dotenv'; - -dotenv.config({ - path: './.env', -}); - -export const openApiConfig = { - PROD: process.env.PROD, - CANO_REAL: process.env.CANO_REAL, - APPKEY: process.env.PROD_APPKEY, - APPSECRET: process.env.PROD_APPSECRET, -}; diff --git a/packages/backend/src/openapi-scraper/korea-stock-info/dto/master-download.dto.ts b/packages/backend/src/scraper/korea-stock-info/dto/master-download.dto.ts similarity index 82% rename from packages/backend/src/openapi-scraper/korea-stock-info/dto/master-download.dto.ts rename to packages/backend/src/scraper/korea-stock-info/dto/master-download.dto.ts index d21c9a80..dd84dd02 100644 --- a/packages/backend/src/openapi-scraper/korea-stock-info/dto/master-download.dto.ts +++ b/packages/backend/src/scraper/korea-stock-info/dto/master-download.dto.ts @@ -1,4 +1,4 @@ -import { IsString } from "class-validator"; +import { IsString } from 'class-validator'; export class MasterDownloadDto { @IsString() diff --git a/packages/backend/src/openapi-scraper/korea-stock-info/entities/stock.entity.ts b/packages/backend/src/scraper/korea-stock-info/entities/stock.entity.ts similarity index 100% rename from packages/backend/src/openapi-scraper/korea-stock-info/entities/stock.entity.ts rename to packages/backend/src/scraper/korea-stock-info/entities/stock.entity.ts diff --git a/packages/backend/src/scraper/korea-stock-info/korea-stock-info.module.ts b/packages/backend/src/scraper/korea-stock-info/korea-stock-info.module.ts new file mode 100644 index 00000000..06abd760 --- /dev/null +++ b/packages/backend/src/scraper/korea-stock-info/korea-stock-info.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { KoreaStockInfoService } from './korea-stock-info.service'; + +@Module({ + imports: [], + controllers: [], + providers: [KoreaStockInfoService], +}) +export class KoreaStockInfoModule {} diff --git a/packages/backend/src/openapi-scraper/korea-stock-info/korea-stock-info.service.spec.ts b/packages/backend/src/scraper/korea-stock-info/korea-stock-info.service.spec.ts similarity index 100% rename from packages/backend/src/openapi-scraper/korea-stock-info/korea-stock-info.service.spec.ts rename to packages/backend/src/scraper/korea-stock-info/korea-stock-info.service.spec.ts diff --git a/packages/backend/src/scraper/korea-stock-info/korea-stock-info.service.ts b/packages/backend/src/scraper/korea-stock-info/korea-stock-info.service.ts new file mode 100644 index 00000000..618bb349 --- /dev/null +++ b/packages/backend/src/scraper/korea-stock-info/korea-stock-info.service.ts @@ -0,0 +1,189 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import * as fs from 'fs'; +import * as https from 'https'; +import * as path from 'path'; +import * as readline from 'readline'; +import { Inject, Injectable } from '@nestjs/common'; +import { Cron } from '@nestjs/schedule'; +import { config as dotenvConfig } from 'dotenv'; +import * as iconv from 'iconv-lite'; +import { DataSource, EntityManager } from 'typeorm'; +import * as unzipper from 'unzipper'; +import { Logger } from 'winston'; +import { MasterDownloadDto } from './dto/master-download.dto'; +import { Stock } from '@/stock/domain/stock.entity'; + +dotenvConfig(); + +@Injectable() +export class KoreaStockInfoService { + constructor( + private readonly datasource: DataSource, + @Inject('winston') private readonly logger: Logger, + ) { + //this.initKoreaStockInfo(); + } + + private async existsStockInfo(stockId: string, manager: EntityManager) { + return await manager.exists(Stock, { + where: { + id: stockId, + }, + }); + } + + private async insertStockData(stock: Stock): Promise { + const manager = this.datasource.manager; + const exists = await this.existsStockInfo(stock.id!, manager); + if (!exists) { + await manager.save(Stock, stock); + } + } + + @Cron('0 0 * * 1-5') + public async initKoreaStockInfo(): Promise { + await this.downloadMaster({ baseDir: './', target: 'kosdaq_code' }); + await this.getKosdaqMasterData({ + baseDir: './', + target: 'kosdaq_code', + }); + + await this.downloadMaster({ baseDir: './', target: 'kospi_code' }); + await this.getKospiMasterData({ + baseDir: './', + target: 'kospi_code', + }); + } + + private async downloadFile(url: string, filePath: string): Promise { + this.logger.info(`Starting download from ${url}`); + const file = fs.createWriteStream(filePath); + + return new Promise((resolve, reject) => { + https + .get(url, (response) => { + if (response.statusCode !== 200) { + reject( + new Error(`Failed to get '${url}' (${response.statusCode})`), + ); + return; + } + + response.pipe(file); + + file.on('finish', () => { + file.close(() => { + this.logger.info('Download completed.'); + resolve(); + }); + }); + }) + .on('error', (err) => { + this.handleUnlinkFile(filePath, err, reject); + }); + }); + } + + private async extractZip(filePath: string, extractTo: string): Promise { + await fs + .createReadStream(filePath) + .pipe(unzipper.Extract({ path: extractTo })) + .promise(); + } + + private getValueFromMst(row: string, start: number, end: number) { + return row.slice(start, end).trim(); + } + + public async downloadMaster(downloadDto: MasterDownloadDto): Promise { + const { baseDir, target } = downloadDto; + const downloadZipFile = target + '.mst.zip'; + const outputFile = target + '.mst'; + const url = process.env.MST_URL + target + '.mst.zip'; + this.logger.info(`Downloading file from ${url} to ${downloadZipFile}`); + const downloadZipFilePath = path.join(baseDir, downloadZipFile); + const extractedFile = path.join(baseDir, outputFile); + + try { + await this.downloadFile(url, downloadZipFilePath); + await this.extractZip(downloadZipFilePath, baseDir); + fs.unlink(downloadZipFilePath, (err) => { + if (err) throw err; + }); + } catch (error) { + this.logger.error('Error during download or extraction:', error); + } + + return extractedFile; + } + + private beforeMasterData(downloadDto: MasterDownloadDto): readline.Interface { + const targetFileName = downloadDto.target + '.mst'; + const fileName = path.join(downloadDto.baseDir, targetFileName); + const encoding = 'cp949'; + + const rl = readline.createInterface({ + input: fs.createReadStream(fileName).pipe(iconv.decodeStream(encoding)), + crlfDelay: Infinity, + }); + return rl; + } + + private handleUnlinkFile( + targetFileName: string, + err?: Error, + callback?: (err: Error) => void, + ) { + fs.unlink(targetFileName, (unlinkError) => { + if (unlinkError) { + this.logger.error(`Error deleting file: ${unlinkError.message}`); + } + if (callback && err) { + callback(err); + } + }); + } + + private async getMasterData( + downloadDto: MasterDownloadDto, + offset: number, + ): Promise { + const targetFileName = downloadDto.target + '.mst'; + const rl = this.beforeMasterData(downloadDto); + + for await (const row of rl) { + const shortCode = this.getValueFromMst(row, 0, 9); + const koreanName = this.getValueFromMst(row, 21, row.length - offset); + const groupCode = this.getValueFromMst( + row, + row.length - offset, + row.length - offset + 2, + ); + + const masterData: Stock = { + id: shortCode, + name: koreanName, + views: 0, + isTrading: true, + groupCode, + }; + await this.insertStockData(masterData); + } + + this.handleUnlinkFile(targetFileName); + } + + public async getKospiMasterData( + downloadDto: MasterDownloadDto, + ): Promise { + await this.getMasterData(downloadDto, 228); + this.logger.info('Kospi master data processing done.'); + } + + public async getKosdaqMasterData( + downloadDto: MasterDownloadDto, + ): Promise { + await this.getMasterData(downloadDto, 222); + this.logger.info('Kosdaq master data processing done.'); + } +} diff --git a/packages/backend/src/scraper/openapi/api/openapiMinuteData.api.ts b/packages/backend/src/scraper/openapi/api/openapiMinuteData.api.ts new file mode 100644 index 00000000..cbc43334 --- /dev/null +++ b/packages/backend/src/scraper/openapi/api/openapiMinuteData.api.ts @@ -0,0 +1,93 @@ +import { Cron } from '@nestjs/schedule'; +import { DataSource } from 'typeorm'; +import { openApiConfig } from '../config/openapi.config'; +import { getCurrentTime, getOpenApi } from '../openapiUtil.api'; +import { + isMinuteData, + MinuteData, + UpdateStockQuery, +} from '../type/openapiMinuteData.type'; +import { openApiToken } from './openapiToken.api'; +import { Stock } from '@/stock/domain/stock.entity'; +import { StockData, StockMinutely } from '@/stock/domain/stockData.entity'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class OpenapiMinuteData { + private stock: Stock[]; + private readonly entity = StockMinutely; + private readonly url: string = + '/uapi/domestic-stock/v1/quotations/inquire-time-itemchartprice'; + public constructor(private readonly datasourse: DataSource) {} + + @Cron('0 1 * * 1-5') + private async getStockData() { + this.stock = await this.datasourse.manager.findBy(Stock, { + isTrading: true, + }); + } + + private convertResToMinuteData(stockId: string, item: MinuteData) { + const stockPeriod = new StockData(); + stockPeriod.stock = { id: stockId } as Stock; + stockPeriod.startTime = new Date( + parseInt(item.stck_bsop_date.slice(0, 4)), + parseInt(item.stck_bsop_date.slice(4, 6)) - 1, + parseInt(item.stck_bsop_date.slice(6, 8)), + ); + stockPeriod.close = parseInt(item.stck_prpr); + stockPeriod.open = parseInt(item.stck_oprc); + stockPeriod.high = parseInt(item.stck_hgpr); + stockPeriod.low = parseInt(item.stck_lwpr); + stockPeriod.volume = parseInt(item.cntg_vol); + stockPeriod.createdAt = new Date(); + return stockPeriod; + } + + private async saveMinuteData(stockPeriod: StockMinutely) { + const manager = this.datasourse.manager; + manager.create(this.entity, stockPeriod); + } + + private async getMinuteDataChunk( + chunk: Stock[], + config: typeof openApiConfig, + ) { + for await (const stock of chunk) { + const time = getCurrentTime(); + const query = this.getUpdateStockQuery(stock.id!, time); + const response = await getOpenApi(this.url, config, query); + const output = (await response.data).output2[0] as MinuteData; + if (output && isMinuteData(output)) { + const stockPeriod = this.convertResToMinuteData(stock.id!, output); + this.saveMinuteData(stockPeriod); + } + } + } + + @Cron('* 9-16 * * 1-5') + private getMinuteData() { + const configCount = openApiToken.configs.length; + const chunkSize = Math.ceil(this.stock.length / configCount); + + for (let i = 0; i < configCount; i++) { + const chunk = this.stock.slice(i * chunkSize, (i + 1) * chunkSize); + this.getMinuteDataChunk(chunk, openApiToken.configs[i]); + } + } + + private getUpdateStockQuery( + stockId: string, + time: string, + isPastData: boolean = true, + marketCode: 'J' | 'W' = 'J', + ): UpdateStockQuery { + return { + fid_etc_cls_code: '', + fid_cond_mrkt_div_code: marketCode, + fid_input_iscd: stockId, + fid_input_hour_1: time, + fid_pw_data_incu_yn: isPastData ? 'Y' : 'N', + }; + } +} diff --git a/packages/backend/src/scraper/openapi/api/openapiPeriodData.api.ts b/packages/backend/src/scraper/openapi/api/openapiPeriodData.api.ts new file mode 100644 index 00000000..74526d54 --- /dev/null +++ b/packages/backend/src/scraper/openapi/api/openapiPeriodData.api.ts @@ -0,0 +1,201 @@ +import { Cron } from '@nestjs/schedule'; +import { DataSource, EntityManager } from 'typeorm'; +import { getOpenApi, getPreviousDate, getTodayDate } from '../openapiUtil.api'; +import { + ChartData, + isChartData, + ItemChartPriceQuery, + Period, +} from '../type/openapiPeriodData'; +import { openApiToken } from './openapiToken.api'; +import { Stock } from '@/stock/domain/stock.entity'; +import { + StockData, + StockDaily, + StockWeekly, + StockMonthly, + StockYearly, +} from '@/stock/domain/stockData.entity'; +import { Injectable } from '@nestjs/common'; + +const DATE_TO_ENTITY = { + D: StockDaily, + W: StockWeekly, + M: StockMonthly, + Y: StockYearly, +}; + +const DATE_TO_MONTH = { + D: 3, + W: 6, + M: 12, + Y: 24, +}; + +const INTERVALS = 4000; + +@Injectable() +export class OpenapiPeriodData { + private readonly url: string = + '/uapi/domestic-stock/v1/quotations/inquire-daily-itemchartprice'; + public constructor(private readonly datasourse: DataSource) { + this.getItemChartPriceCheck(); + } + + @Cron('0 1 * * 1-5') + public async getItemChartPriceCheck() { + const entityManager = this.datasourse.manager; + const stocks = await entityManager.find(Stock); + const configCount = openApiToken.configs.length; + const chunkSize = Math.ceil(stocks.length / configCount); + + for (let i = 0; i < configCount; i++) { + const chunk = stocks.slice(i * chunkSize, (i + 1) * chunkSize); + this.getChartData(chunk, 'D'); + setTimeout(() => this.getChartData(chunk, 'W'), INTERVALS); + setTimeout(() => this.getChartData(chunk, 'M'), INTERVALS * 2); + setTimeout(() => this.getChartData(chunk, 'Y'), INTERVALS * 3); + } + } + + private async getChartData(chunk: Stock[], period: Period) { + const baseTime = INTERVALS * 4; + const entity = DATE_TO_ENTITY[period]; + const manager = this.datasourse.manager; + + let time = 0; + for (const stock of chunk) { + time += baseTime; + setTimeout( + () => this.processStockData(stock, period, entity, manager), + time, + ); + } + } + + private async processStockData( + stock: Stock, + period: Period, + entity: typeof StockData, + manager: EntityManager, + ) { + const stockPeriod = new StockData(); + let configIdx = 0; + let end = getTodayDate(); + let start = getPreviousDate(end, 3); + let isFail = false; + + while (isFail) { + configIdx = (configIdx + 1) % openApiToken.configs.length; + this.setStockPeriod(stockPeriod, stock.id!, end); + + if (await this.existsChartData(stockPeriod, manager, entity)) return; + + const query = this.getItemChartPriceQuery(stock.id!, start, end, period); + + const output = await this.fetchChartData(query, configIdx); + + if (output && isChartData(output[0])) { + await this.saveChartData(entity, stock.id!, output); + ({ endDate: end, startDate: start } = this.updateDates(start, period)); + } else isFail = true; + } + } + + private setStockPeriod( + stockPeriod: StockData, + stockId: string, + endDate: string, + ): void { + stockPeriod.stock = { id: stockId } as Stock; + stockPeriod.startTime = new Date( + parseInt(endDate.slice(0, 4)), + parseInt(endDate.slice(4, 6)) - 1, + parseInt(endDate.slice(6, 8)), + ); + } + + private async fetchChartData( + query: ItemChartPriceQuery, + configIdx: number, + ): Promise { + const response = await getOpenApi( + this.url, + openApiToken.configs[configIdx], + query, + ); + return response.output2 as ChartData[]; + } + + private updateDates( + startDate: string, + period: Period, + ): { endDate: string; startDate: string } { + const endDate = getPreviousDate(startDate, DATE_TO_MONTH[period]); + startDate = getPreviousDate(endDate, DATE_TO_MONTH[period]); + return { endDate, startDate }; + } + + private async existsChartData( + stock: StockData, + manager: EntityManager, + entity: typeof StockData, + ) { + return await manager.findOne(entity, { + where: { + stock: { id: stock.stock.id }, + createdAt: stock.startTime, + }, + }); + } + + private async insertChartData(stock: StockData, entity: typeof StockData) { + const manager = this.datasourse.manager; + if (!(await this.existsChartData(stock, manager, entity))) { + await manager.save(entity, stock); + } + } + + private async saveChartData( + entity: typeof StockData, + stockId: string, + data: ChartData[], + ) { + for (const item of data) { + if (!item || !item.stck_bsop_date) { + continue; + } + const stockPeriod = new StockData(); + stockPeriod.stock = { id: stockId } as Stock; + stockPeriod.startTime = new Date( + parseInt(item.stck_bsop_date.slice(0, 4)), + parseInt(item.stck_bsop_date.slice(4, 6)) - 1, + parseInt(item.stck_bsop_date.slice(6, 8)), + ); + stockPeriod.close = parseInt(item.stck_clpr); + stockPeriod.open = parseInt(item.stck_oprc); + stockPeriod.high = parseInt(item.stck_hgpr); + stockPeriod.low = parseInt(item.stck_lwpr); + stockPeriod.volume = parseInt(item.acml_vol); + stockPeriod.createdAt = new Date(); + await this.insertChartData(stockPeriod, entity); + } + } + + private getItemChartPriceQuery( + stockId: string, + startDate: string, + endDate: string, + period: Period, + marketCode: 'J' | 'W' = 'J', + ): ItemChartPriceQuery { + return { + fid_cond_mrkt_div_code: marketCode, + fid_input_iscd: stockId, + fid_input_date_1: startDate, + fid_input_date_2: endDate, + fid_period_div_code: period, + fid_org_adj_prc: 0, + }; + } +} diff --git a/packages/backend/src/scraper/openapi/api/openapiToken.api.ts b/packages/backend/src/scraper/openapi/api/openapiToken.api.ts new file mode 100644 index 00000000..c4df3cdf --- /dev/null +++ b/packages/backend/src/scraper/openapi/api/openapiToken.api.ts @@ -0,0 +1,87 @@ +import { Inject, NotFoundException } from '@nestjs/common'; +import { Cron } from '@nestjs/schedule'; +import { Logger } from 'winston'; +import { openApiConfig } from '../config/openapi.config'; +import { postOpenApi } from '../openapiUtil.api'; +import { logger } from '@/configs/logger.config'; + +class OpenapiTokenApi { + private config: (typeof openApiConfig)[] = []; + public constructor(@Inject('winston') private readonly logger: Logger) { + const accounts = openApiConfig.STOCK_ACCOUNT!.split(','); + const api_keys = openApiConfig.STOCK_API_KEY!.split(','); + const api_passwords = openApiConfig.STOCK_API_PASSWORD!.split(','); + if ( + accounts.length === 0 || + accounts.length !== api_keys.length || + api_passwords.length !== api_keys.length + ) { + this.logger.warn('Open API Config Error'); + } + for (let i = 0; i < accounts.length; i++) { + this.config.push({ + STOCK_URL: openApiConfig.STOCK_URL, + STOCK_ACCOUNT: accounts[i], + STOCK_API_KEY: api_keys[i], + STOCK_API_PASSWORD: api_passwords[i], + }); + } + this.initAuthenValue(); + } + + public get configs() { + return this.config; + } + + private async initAuthenValue() { + await this.initAccessToken(); + await this.initWebSocketKey(); + } + + @Cron('50 0 * * 1-5') + private async initAccessToken() { + const updatedConfig = await Promise.all( + this.config.map(async (val) => { + val.STOCK_API_TOKEN = await this.getToken(val)!; + return val; + }), + ); + this.config = updatedConfig; + } + + @Cron('50 0 * * 1-5') + private async initWebSocketKey() { + this.config.forEach(async (val) => { + val.STOCK_WEBSOCKET_KEY = await this.getWebSocketKey(val)!; + }); + } + + private async getToken(config: typeof openApiConfig): Promise { + const body = { + grant_type: 'client_credentials', + appkey: config.STOCK_API_KEY, + appsecret: config.STOCK_API_PASSWORD, + }; + const tmp = await postOpenApi('/oauth2/tokenP', config, body); + if (!tmp.access_token) { + throw new NotFoundException('Access Token Failed'); + } + return tmp.access_token as string; + } + + private async getWebSocketKey(config: typeof openApiConfig): Promise { + const body = { + grant_type: 'client_credentials', + appkey: config.STOCK_API_KEY, + secretkey: config.STOCK_API_PASSWORD, + }; + const tmp = await postOpenApi('/oauth2/Approval', config, body); + if (!tmp.approval_key) { + throw new NotFoundException('WebSocket Key Failed'); + } + return tmp.approval_key as string; + } +} + +const openApiToken = new OpenapiTokenApi(logger); +export { openApiToken }; diff --git a/packages/backend/src/scraper/openapi/config/openapi.config.ts b/packages/backend/src/scraper/openapi/config/openapi.config.ts new file mode 100644 index 00000000..8aa12ea3 --- /dev/null +++ b/packages/backend/src/scraper/openapi/config/openapi.config.ts @@ -0,0 +1,17 @@ +import * as dotenv from 'dotenv'; + +dotenv.config(); + +export const openApiConfig: { + STOCK_URL: string | undefined; + STOCK_ACCOUNT: string | undefined; + STOCK_API_KEY: string | undefined; + STOCK_API_PASSWORD: string | undefined; + STOCK_API_TOKEN?: string; + STOCK_WEBSOCKET_KEY?: string; +} = { + STOCK_URL: process.env.STOCK_URL, + STOCK_ACCOUNT: process.env.STOCK_ACCOUNT, + STOCK_API_KEY: process.env.STOCK_API_KEY, + STOCK_API_PASSWORD: process.env.STOCK_API_PASSWORD, +}; diff --git a/packages/backend/src/scraper/openapi/openapi-scraper.module.ts b/packages/backend/src/scraper/openapi/openapi-scraper.module.ts new file mode 100644 index 00000000..00dca421 --- /dev/null +++ b/packages/backend/src/scraper/openapi/openapi-scraper.module.ts @@ -0,0 +1,17 @@ +import { Module } from '@nestjs/common'; +import { OpenapiMinuteData } from './api/openapiMinuteData.api'; +import { OpenapiPeriodData } from './api/openapiPeriodData.api'; +import { OpenapiScraperService } from './openapi-scraper.service'; +import { DataSource } from 'typeorm'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Stock } from '@/stock/domain/stock.entity'; +import { StockDaily, StockMinutely, StockMonthly, StockWeekly, StockYearly } from '@/stock/domain/stockData.entity'; +import { StockLiveData } from '@/stock/domain/stockLiveData.entity'; +import { StockDetail } from '@/stock/domain/stockDetail.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([Stock, StockMinutely , StockDaily, StockWeekly, StockMonthly, StockYearly, StockLiveData, StockDetail])], + controllers: [], + providers: [OpenapiPeriodData, OpenapiMinuteData, OpenapiScraperService], +}) +export class OpenapiScraperModule {} diff --git a/packages/backend/src/scraper/openapi/openapi-scraper.service.ts b/packages/backend/src/scraper/openapi/openapi-scraper.service.ts new file mode 100644 index 00000000..98f27a34 --- /dev/null +++ b/packages/backend/src/scraper/openapi/openapi-scraper.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@nestjs/common'; +import { DataSource } from 'typeorm'; +import { OpenapiMinuteData } from './api/openapiMinuteData.api'; +import { OpenapiPeriodData } from './api/openapiPeriodData.api'; + +@Injectable() +export class OpenapiScraperService { + public constructor( + private readonly datasourse: DataSource, + private readonly openapiPeriodData: OpenapiPeriodData, + private readonly openapiMinuteData: OpenapiMinuteData, + ) {} +} diff --git a/packages/backend/src/scraper/openapi/openapiUtil.api.ts b/packages/backend/src/scraper/openapi/openapiUtil.api.ts new file mode 100644 index 00000000..e09c181c --- /dev/null +++ b/packages/backend/src/scraper/openapi/openapiUtil.api.ts @@ -0,0 +1,65 @@ +import axios from 'axios'; +import { openApiConfig } from './config/openapi.config'; + +const postOpenApi = async ( + url: string, + config: typeof openApiConfig, + body: object, +) => { + try { + const response = await axios.post(config.STOCK_URL + url, body); + return response.data; + } catch (error) { + throw new Error(`Request failed: ${error}`); + } +}; + +const getOpenApi = async ( + url: string, + config: typeof openApiConfig, + query: object, +) => { + try { + const response = await axios.get(config.STOCK_URL + url, { + params: query, + headers: { + Authorization: `Bearer ${config.STOCK_API_TOKEN}`, + appkey: config.STOCK_API_KEY, + appsecret: config.STOCK_API_PASSWORD, + tr_id: 'FHKST03010100', + }, + }); + return response.data; + } catch (error) { + throw new Error(`Request failed: ${error}`); + } +}; + +const getTodayDate = (): string => { + const today = new Date(); + return today.toISOString().split('T')[0].replace(/-/g, ''); +}; + +const getPreviousDate = (date: string, months: number): string => { + const currentDate = new Date( + date.slice(0, 4) + '-' + date.slice(4, 6) + '-' + date.slice(6, 8), + ); + currentDate.setMonth(currentDate.getMonth() - months); + return currentDate.toISOString().split('T')[0].replace(/-/g, ''); +}; + +const getCurrentTime = () => { + const now = new Date(); + const hours = String(now.getHours()).padStart(2, '0'); + const minutes = String(now.getMinutes()).padStart(2, '0'); + const seconds = String(now.getSeconds()).padStart(2, '0'); + return `${hours}${minutes}${seconds}`; +}; + +export { + postOpenApi, + getOpenApi, + getTodayDate, + getPreviousDate, + getCurrentTime, +}; diff --git a/packages/backend/src/scraper/openapi/type/openapiMinuteData.type.ts b/packages/backend/src/scraper/openapi/type/openapiMinuteData.type.ts new file mode 100644 index 00000000..5deb2d9e --- /dev/null +++ b/packages/backend/src/scraper/openapi/type/openapiMinuteData.type.ts @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export type MinuteData = { + stck_bsop_date: string; + stck_cntg_hour: string; + stck_prpr: string; + stck_oprc: string; + stck_hgpr: string; + stck_lwpr: string; + cntg_vol: string; + acml_tr_pbmn: string; +}; + +export type UpdateStockQuery = { + fid_etc_cls_code: string; + fid_cond_mrkt_div_code: 'J' | 'W'; + fid_input_iscd: string; + fid_input_hour_1: string; + fid_pw_data_incu_yn: 'Y' | 'N'; +}; + +export const isMinuteData = (data: any) => { + return ( + typeof data.stck_bsop_date === 'string' && + typeof data.stck_cntg_hour === 'string' && + typeof data.stck_prpr === 'string' && + typeof data.stck_oprc === 'string' && + typeof data.stck_hgpr === 'string' && + typeof data.stck_lwpr === 'string' && + typeof data.cntg_vol === 'string' && + typeof data.acml_tr_pbmn === 'string' + ); +}; diff --git a/packages/backend/src/scraper/openapi/type/openapiPeriodData.ts b/packages/backend/src/scraper/openapi/type/openapiPeriodData.ts new file mode 100644 index 00000000..4acc7f44 --- /dev/null +++ b/packages/backend/src/scraper/openapi/type/openapiPeriodData.ts @@ -0,0 +1,44 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export type Period = 'D' | 'W' | 'M' | 'Y'; +export type ChartData = { + stck_bsop_date: string; + stck_clpr: string; + stck_oprc: string; + stck_hgpr: string; + stck_lwpr: string; + acml_vol: string; + acml_tr_pbmn: string; + flng_cls_code: string; + prtt_rate: string; + mod_yn: string; + prdy_vrss_sign: string; + prdy_vrss: string; + revl_issu_reas: string; +}; + +export type ItemChartPriceQuery = { + fid_cond_mrkt_div_code: 'J' | 'W'; + fid_input_iscd: string; + fid_input_date_1: string; + fid_input_date_2: string; + fid_period_div_code: Period; + fid_org_adj_prc: number; +}; + +export const isChartData = (data: any) => { + return ( + typeof data.stck_bsop_date === 'string' && + typeof data.stck_clpr === 'string' && + typeof data.stck_oprc === 'string' && + typeof data.stck_hgpr === 'string' && + typeof data.stck_lwpr === 'string' && + typeof data.acml_vol === 'string' && + typeof data.acml_tr_pbmn === 'string' && + typeof data.flng_cls_code === 'string' && + typeof data.prtt_rate === 'string' && + typeof data.mod_yn === 'string' && + typeof data.prdy_vrss_sign === 'string' && + typeof data.prdy_vrss === 'string' && + typeof data.revl_issu_reas === 'string' + ); +}; diff --git a/packages/backend/src/scraper/scraper.module.ts b/packages/backend/src/scraper/scraper.module.ts new file mode 100644 index 00000000..96f25299 --- /dev/null +++ b/packages/backend/src/scraper/scraper.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { KoreaStockInfoModule } from './korea-stock-info/korea-stock-info.module'; +import { OpenapiScraperModule } from './openapi/openapi-scraper.module'; + +@Module({ + imports: [KoreaStockInfoModule, OpenapiScraperModule], + controllers: [], + providers: [], +}) +export class ScraperModule {} diff --git a/packages/backend/src/stock-price/stock-price.controller.spec.ts b/packages/backend/src/stock-price/stock-price.controller.spec.ts deleted file mode 100644 index a6fe3fb6..00000000 --- a/packages/backend/src/stock-price/stock-price.controller.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { StockPriceController } from './stock-price.controller'; - -describe('StockPriceController', () => { - let controller: StockPriceController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [StockPriceController], - }).compile(); - - controller = module.get(StockPriceController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/packages/backend/src/stock-price/stock-price.controller.ts b/packages/backend/src/stock-price/stock-price.controller.ts deleted file mode 100644 index 1436c6a1..00000000 --- a/packages/backend/src/stock-price/stock-price.controller.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Controller, HttpCode, Post } from '@nestjs/common'; - -@Controller('stock-price') -export class StockPriceController { -} diff --git a/packages/backend/src/stock-price/stock-price.module.ts b/packages/backend/src/stock-price/stock-price.module.ts deleted file mode 100644 index c6df3a29..00000000 --- a/packages/backend/src/stock-price/stock-price.module.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Module } from '@nestjs/common'; - -@Module({}) -export class StockPriceModule {} diff --git a/packages/backend/src/stock/domain/stock.entity.ts b/packages/backend/src/stock/domain/stock.entity.ts index 86de1abb..033833bf 100644 --- a/packages/backend/src/stock/domain/stock.entity.ts +++ b/packages/backend/src/stock/domain/stock.entity.ts @@ -1,6 +1,13 @@ import { Column, Entity, OneToMany, PrimaryColumn } from 'typeorm'; import { DateEmbedded } from '@/common/dateEmbedded.entity'; import { UserStock } from '@/stock/domain/userStock.entity'; +import { + StockDaily, + StockMinutely, + StockMonthly, + StockWeekly, + StockYearly, +} from './stockData.entity'; @Entity() export class Stock { @@ -24,4 +31,19 @@ export class Stock { @OneToMany(() => UserStock, (userStock) => userStock.stock) userStocks?: UserStock[]; + + @OneToMany(() => StockMinutely, (stockMinutely) => stockMinutely.stock) + stockMinutely?: StockMinutely[]; + + @OneToMany(() => StockDaily, (stockDaily) => stockDaily.stock) + stockDaily?: StockDaily[]; + + @OneToMany(() => StockWeekly, (stockWeekly) => stockWeekly.stock) + stockWeekly?: StockWeekly[]; + + @OneToMany(() => StockMonthly, (stockMonthly) => stockMonthly.stock) + stockMonthly?: StockMonthly[]; + + @OneToMany(() => StockYearly, (stockYearly) => stockYearly.stock) + stockYearly?: StockYearly[]; } diff --git a/packages/backend/src/stock/domain/stockData.entity.ts b/packages/backend/src/stock/domain/stockData.entity.ts index 4a309a54..e9c75407 100644 --- a/packages/backend/src/stock/domain/stockData.entity.ts +++ b/packages/backend/src/stock/domain/stockData.entity.ts @@ -1,3 +1,4 @@ +import { applyDecorators } from '@nestjs/common'; import { Entity, PrimaryGeneratedColumn, @@ -5,10 +6,28 @@ import { CreateDateColumn, JoinColumn, ManyToOne, + ColumnOptions, } from 'typeorm'; import { Stock } from './stock.entity'; -abstract class StockData { +export const GenerateBigintColumn = ( + options?: ColumnOptions, +): PropertyDecorator => { + return applyDecorators( + Column({ + ...options, + type: 'bigint', + transformer: { + to: (value: bigint): string => + typeof value === 'bigint' ? value.toString() : value, + from: (value: string): bigint => + typeof value === 'string' ? BigInt(value) : value, + }, + }), + ); +}; + +export class StockData { @PrimaryGeneratedColumn() id: number; @@ -24,7 +43,7 @@ abstract class StockData { @Column({ type: 'decimal', precision: 15, scale: 2 }) open: number; - @Column({ type: 'bigint' }) + @Column({ type: 'decimal', precision: 15, scale: 2 }) volume: number; @Column({ type: 'timestamp', name: 'start_time' }) @@ -40,7 +59,6 @@ abstract class StockData { @Entity('stock_minutely') export class StockMinutely extends StockData {} - @Entity('stock_daily') export class StockDaily extends StockData {} @Entity('stock_weekly') diff --git a/packages/backend/src/stock/stock.controller.ts b/packages/backend/src/stock/stock.controller.ts index e7716826..042353a3 100644 --- a/packages/backend/src/stock/stock.controller.ts +++ b/packages/backend/src/stock/stock.controller.ts @@ -228,4 +228,16 @@ export class StockController { async getTopStocksByViews(@LimitQuery(5) limit: number) { return await this.stockService.getTopStocksByViews(limit); } + + @Get('topGainers') + @ApiGetStocks('가격 상승률 기반 주식 리스트 조회 API') + async getTopStocksByGainers(@LimitQuery(20) limit: number) { + return await this.stockService.getTopStocksByGainers(limit); + } + + @Get('topLosers') + @ApiGetStocks('가격 하락률 기반 주식 리스트 조회 API') + async getTopStocksByLosers(@LimitQuery(20) limit: number) { + return await this.stockService.getTopStocksByLosers(limit); + } } diff --git a/packages/backend/src/stock/stock.service.spec.ts b/packages/backend/src/stock/stock.service.spec.ts index e40d5854..2675373e 100644 --- a/packages/backend/src/stock/stock.service.spec.ts +++ b/packages/backend/src/stock/stock.service.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-lines-per-function */ import { instanceToPlain } from 'class-transformer'; import { DataSource } from 'typeorm'; import { Logger } from 'winston'; @@ -209,4 +210,160 @@ describe('StockService 테스트', () => { }, ]); }); + + test('주식 상승률 기준 상위 데이터를 반환한다.', async () => { + const limit = 20; + // QueryBuilder Mock + const queryBuilderMock = { + leftJoin: jest.fn().mockReturnThis(), + select: jest.fn().mockReturnThis(), + orderBy: jest.fn().mockReturnThis(), + limit: jest.fn().mockReturnThis(), + getRawMany: jest.fn().mockResolvedValue([ + { + id: 'A005930', + name: '삼성전자', + currentPrice: '100000.0', + changeRate: '2.5', + volume: '500000', + marketCap: '500000000000.00', + }, + { + id: 'A051910', + name: 'LG화학', + currentPrice: '75000.0', + changeRate: '-1.2', + volume: '300000', + marketCap: '20000000000.00', + }, + ]), + }; + + // Manager Mock + const managerMock = { + getRepository: jest.fn().mockReturnValue({ + createQueryBuilder: jest.fn().mockReturnValue(queryBuilderMock), + }), + }; + const dataSource = createDataSourceMock(managerMock); + const stockService = new StockService(dataSource as DataSource, logger); + + const result = await stockService.getTopStocksByGainers(limit); + + expect(managerMock.getRepository).toHaveBeenCalledWith(Stock); + expect(queryBuilderMock.orderBy).toHaveBeenCalledWith( + 'stockLiveData.changeRate', + 'DESC', + ); + expect(queryBuilderMock.limit).toHaveBeenCalledWith(limit); + expect(queryBuilderMock.getRawMany).toHaveBeenCalled(); + + expect(instanceToPlain(result)).toEqual([ + { + id: 'A005930', + name: '삼성전자', + currentPrice: 100000.0, + changeRate: 2.5, + volume: 500000, + marketCap: '500000000000.00', + }, + { + id: 'A051910', + name: 'LG화학', + currentPrice: 75000.0, + changeRate: -1.2, + volume: 300000, + marketCap: '20000000000.00', + }, + ]); + }); + + test('소유 주식인지 확인한다.', async () => { + const managerMock = { + exists: jest.fn().mockResolvedValue(true), + }; + const dataSource = createDataSourceMock(managerMock); + const stockService = new StockService(dataSource as DataSource, logger); + + const result = await stockService.isUserStockOwner(stockId, userId); + + expect(result).toBe(true); + expect(managerMock.exists).toHaveBeenCalled(); + }); + + test('인증된 유저가 아니면 소유 주식은 항상 false를 반환한다.', async () => { + const dataSource = createDataSourceMock({}); + const stockService = new StockService(dataSource as DataSource, logger); + + const result = await stockService.isUserStockOwner(stockId); + + expect(result).toBe(false); + }); + + test('주식 하락률 기준 상위 데이터를 반환한다.', async () => { + const limit = 20; + // QueryBuilder Mock + const queryBuilderMock = { + leftJoin: jest.fn().mockReturnThis(), + select: jest.fn().mockReturnThis(), + orderBy: jest.fn().mockReturnThis(), + limit: jest.fn().mockReturnThis(), + getRawMany: jest.fn().mockResolvedValue([ + { + id: 'A051910', + name: 'LG화학', + currentPrice: '75000.0', + changeRate: '-1.2', + volume: '300000', + marketCap: '20000000000.00', + }, + { + id: 'A005930', + name: '삼성전자', + currentPrice: '100000.0', + changeRate: '2.5', + volume: '500000', + marketCap: '500000000000.00', + }, + ]), + }; + + // Manager Mock + const managerMock = { + getRepository: jest.fn().mockReturnValue({ + createQueryBuilder: jest.fn().mockReturnValue(queryBuilderMock), + }), + }; + const dataSource = createDataSourceMock(managerMock); + const stockService = new StockService(dataSource as DataSource, logger); + + const result = await stockService.getTopStocksByLosers(limit); + + expect(managerMock.getRepository).toHaveBeenCalledWith(Stock); + expect(queryBuilderMock.orderBy).toHaveBeenCalledWith( + 'stockLiveData.changeRate', + 'ASC', + ); + expect(queryBuilderMock.limit).toHaveBeenCalledWith(limit); + expect(queryBuilderMock.getRawMany).toHaveBeenCalled(); + + expect(instanceToPlain(result)).toEqual([ + { + id: 'A051910', + name: 'LG화학', + currentPrice: 75000.0, + changeRate: -1.2, + volume: 300000, + marketCap: '20000000000.00', + }, + { + id: 'A005930', + name: '삼성전자', + currentPrice: 100000.0, + changeRate: 2.5, + volume: 500000, + marketCap: '500000000000.00', + }, + ]); + }); }); diff --git a/packages/backend/src/stock/stock.service.ts b/packages/backend/src/stock/stock.service.ts index b4502dcc..1f23e48f 100644 --- a/packages/backend/src/stock/stock.service.ts +++ b/packages/backend/src/stock/stock.service.ts @@ -145,4 +145,22 @@ export class StockService { return plainToInstance(StocksResponse, rawData); } + + async getTopStocksByGainers(limit: number) { + const rawData = await this.StocksQuery() + .orderBy('stockLiveData.changeRate', 'DESC') + .limit(limit) + .getRawMany(); + + return plainToInstance(StocksResponse, rawData); + } + + async getTopStocksByLosers(limit: number) { + const rawData = await this.StocksQuery() + .orderBy('stockLiveData.changeRate', 'ASC') + .limit(limit) + .getRawMany(); + + return plainToInstance(StocksResponse, rawData); + } } diff --git a/packages/backend/tsconfig.json b/packages/backend/tsconfig.json index 4d6a79d0..f01a23e5 100644 --- a/packages/backend/tsconfig.json +++ b/packages/backend/tsconfig.json @@ -8,5 +8,5 @@ }, "strictPropertyInitialization": false }, - "include": ["src/**/*", "test/**/*"] + "include": ["src/**/*", "test/**/*", "src/scraper/openapi/type/openapiPeriodData.ts"] } diff --git a/packages/frontend/.gitignore b/packages/frontend/.gitignore index a547bf36..f940a995 100644 --- a/packages/frontend/.gitignore +++ b/packages/frontend/.gitignore @@ -22,3 +22,5 @@ dist-ssr *.njsproj *.sln *.sw? + +*storybook.log diff --git a/packages/frontend/.storybook/main.ts b/packages/frontend/.storybook/main.ts new file mode 100644 index 00000000..9240670a --- /dev/null +++ b/packages/frontend/.storybook/main.ts @@ -0,0 +1,28 @@ +import type { StorybookConfig } from '@storybook/react-vite'; + +import { join, dirname } from 'path'; + +/** + * This function is used to resolve the absolute path of a package. + * It is needed in projects that use Yarn PnP or are set up within a monorepo. + */ +function getAbsolutePath(value: string) { + return dirname(require.resolve(join(value, 'package.json'))); +} +const config: StorybookConfig = { + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + addons: [ + getAbsolutePath('@storybook/addon-onboarding'), + getAbsolutePath('@storybook/addon-essentials'), + getAbsolutePath('@chromatic-com/storybook'), + getAbsolutePath('@storybook/addon-interactions'), + ], + framework: { + name: getAbsolutePath('@storybook/react-vite'), + options: {}, + }, + core: { + builder: getAbsolutePath('@storybook/builder-vite'), + }, +}; +export default config; diff --git a/packages/frontend/.storybook/preview.ts b/packages/frontend/.storybook/preview.ts new file mode 100644 index 00000000..b20bf8b4 --- /dev/null +++ b/packages/frontend/.storybook/preview.ts @@ -0,0 +1,11 @@ +import '@/index.css'; + +export const parameters = { + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, +}; diff --git a/packages/frontend/Dockerfile b/packages/frontend/Dockerfile index cbeb22e3..0f9d14d7 100644 --- a/packages/frontend/Dockerfile +++ b/packages/frontend/Dockerfile @@ -7,5 +7,5 @@ RUN yarn workspace frontend build # Nginx 서버로 빌드된 파일 서빙 FROM nginx:alpine COPY --from=builder /packages/packages/frontend/dist /usr/share/nginx/html -EXPOSE 80 +EXPOSE 8080 CMD ["nginx", "-g", "daemon off;"] diff --git a/packages/frontend/index.html b/packages/frontend/index.html index dd168d8e..f352eb24 100644 --- a/packages/frontend/index.html +++ b/packages/frontend/index.html @@ -2,7 +2,7 @@ - + 주춤주춤 diff --git a/packages/frontend/package.json b/packages/frontend/package.json index ce58b019..067b43c4 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -7,15 +7,31 @@ "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", - "preview": "vite preview" + "preview": "vite preview", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" }, "dependencies": { "@tanstack/react-query": "^5.59.19", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "lightweight-charts": "^4.2.1", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-router-dom": "^6.28.0", + "tailwind-merge": "^2.5.4" }, "devDependencies": { + "@chromatic-com/storybook": "3.2.2", "@eslint/js": "^9.13.0", + "@storybook/addon-essentials": "8.4.3", + "@storybook/addon-interactions": "8.4.3", + "@storybook/addon-onboarding": "8.4.3", + "@storybook/blocks": "8.4.3", + "@storybook/builder-vite": "^8.4.3", + "@storybook/react": "8.4.3", + "@storybook/react-vite": "8.4.3", + "@storybook/test": "8.4.3", "@types/node": "^22.8.7", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", @@ -25,11 +41,20 @@ "eslint-plugin-import": "^2.31.0", "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.14", + "eslint-plugin-storybook": "^0.11.0", "globals": "^15.11.0", "postcss": "^8.4.47", + "prettier-plugin-tailwindcss": "^0.6.8", + "storybook": "8.4.3", "tailwindcss": "^3.4.14", "typescript": "~5.6.2", "typescript-eslint": "^8.11.0", - "vite": "^5.4.10" + "vite": "^5.4.10", + "vite-plugin-svgr": "^4.3.0" + }, + "eslintConfig": { + "extends": [ + "plugin:storybook/recommended" + ] } } diff --git a/packages/frontend/public/favicon.ico b/packages/frontend/public/favicon.ico new file mode 100644 index 00000000..66260fe1 Binary files /dev/null and b/packages/frontend/public/favicon.ico differ diff --git a/packages/frontend/public/logoCharacter.png b/packages/frontend/public/logoCharacter.png new file mode 100644 index 00000000..4b821503 Binary files /dev/null and b/packages/frontend/public/logoCharacter.png differ diff --git a/packages/frontend/public/logoTitle.png b/packages/frontend/public/logoTitle.png new file mode 100644 index 00000000..84bf11c3 Binary files /dev/null and b/packages/frontend/public/logoTitle.png differ diff --git a/packages/frontend/public/vite.svg b/packages/frontend/public/vite.svg deleted file mode 100644 index e7b8dfb1..00000000 --- a/packages/frontend/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/frontend/src/App.tsx b/packages/frontend/src/App.tsx index b227abba..c54b6c2e 100644 --- a/packages/frontend/src/App.tsx +++ b/packages/frontend/src/App.tsx @@ -1,23 +1,15 @@ -import { useState } from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { RouterProvider } from 'react-router-dom'; +import { router } from './routes'; const App = () => { - const [count, setCount] = useState(0); + const queryClient = new QueryClient(); return ( - <> -

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

- + + + {/* TODO:react query devtools 설치 */} + ); }; diff --git a/packages/frontend/src/assets/bell.svg b/packages/frontend/src/assets/bell.svg new file mode 100644 index 00000000..fdaadf88 --- /dev/null +++ b/packages/frontend/src/assets/bell.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/frontend/src/assets/home.svg b/packages/frontend/src/assets/home.svg new file mode 100644 index 00000000..6dfeb2fb --- /dev/null +++ b/packages/frontend/src/assets/home.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/frontend/src/assets/plus.svg b/packages/frontend/src/assets/plus.svg new file mode 100644 index 00000000..66ab1ddc --- /dev/null +++ b/packages/frontend/src/assets/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/frontend/src/assets/search.svg b/packages/frontend/src/assets/search.svg new file mode 100644 index 00000000..629bb57d --- /dev/null +++ b/packages/frontend/src/assets/search.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/frontend/src/assets/send.svg b/packages/frontend/src/assets/send.svg new file mode 100644 index 00000000..a37a73f3 --- /dev/null +++ b/packages/frontend/src/assets/send.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/frontend/src/assets/stock.svg b/packages/frontend/src/assets/stock.svg new file mode 100644 index 00000000..0c069492 --- /dev/null +++ b/packages/frontend/src/assets/stock.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/frontend/src/assets/theme.svg b/packages/frontend/src/assets/theme.svg new file mode 100644 index 00000000..601e52de --- /dev/null +++ b/packages/frontend/src/assets/theme.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/frontend/src/assets/user.svg b/packages/frontend/src/assets/user.svg new file mode 100644 index 00000000..0acf170c --- /dev/null +++ b/packages/frontend/src/assets/user.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/frontend/src/components/layouts/Layout.tsx b/packages/frontend/src/components/layouts/Layout.tsx new file mode 100644 index 00000000..ad7fb7e8 --- /dev/null +++ b/packages/frontend/src/components/layouts/Layout.tsx @@ -0,0 +1,13 @@ +import { Outlet } from 'react-router-dom'; +import { Sidebar } from './Sidebar'; + +export const Layout = () => { + return ( +
+ +
+ +
+
+ ); +}; diff --git a/packages/frontend/src/components/layouts/MenuList.tsx b/packages/frontend/src/components/layouts/MenuList.tsx new file mode 100644 index 00000000..dc1940c2 --- /dev/null +++ b/packages/frontend/src/components/layouts/MenuList.tsx @@ -0,0 +1,59 @@ +import { type ReactNode } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { type MenuItemData } from '@/constants/menuItems'; +import { cn } from '@/utils/cn'; + +interface MenuListProps { + items: MenuItemData[]; + isHovered: boolean; +} + +interface MenuItemProps { + icon: ReactNode; + text: string; + isHovered: boolean; + onClick?: () => void; +} + +export const MenuList = ({ items, isHovered }: MenuListProps) => { + const navigate = useNavigate(); + + return ( +
    + {items.map((menu) => { + const { id, icon, text, url } = menu; + return ( + url && navigate(url)} + /> + ); + })} +
+ ); +}; + +const MenuItem = ({ icon, text, onClick, isHovered }: MenuItemProps) => { + return ( +
  • + +

    + {text} +

    +
  • + ); +}; diff --git a/packages/frontend/src/components/layouts/Sidebar.tsx b/packages/frontend/src/components/layouts/Sidebar.tsx new file mode 100644 index 00000000..651ed531 --- /dev/null +++ b/packages/frontend/src/components/layouts/Sidebar.tsx @@ -0,0 +1,41 @@ +import { useState } from 'react'; +import logoCharacter from '/logoCharacter.png'; +import logoTitle from '/logoTitle.png'; +import { MenuList } from './MenuList'; +import { bottomMenuItems, topMenuItems } from '@/constants/menuItems'; +import { cn } from '@/utils/cn'; + +export const Sidebar = () => { + const [isHovered, setIsHovered] = useState(false); + + return ( + + ); +}; diff --git a/packages/frontend/src/components/layouts/index.ts b/packages/frontend/src/components/layouts/index.ts new file mode 100644 index 00000000..a4ffcee9 --- /dev/null +++ b/packages/frontend/src/components/layouts/index.ts @@ -0,0 +1,3 @@ +export * from './Layout'; +export * from './MenuList'; +export * from './Sidebar'; diff --git a/packages/frontend/src/components/ui/button/Button.stories.ts b/packages/frontend/src/components/ui/button/Button.stories.ts new file mode 100644 index 00000000..945bc03b --- /dev/null +++ b/packages/frontend/src/components/ui/button/Button.stories.ts @@ -0,0 +1,60 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Button, type ButtonProps } from '.'; + +const meta: Meta = { + title: 'Example/Button', + component: Button, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + backgroundColor: { + control: 'select', + options: ['default', 'gray', 'orange'], + }, + textColor: { + control: 'select', + options: ['default', 'white'], + }, + size: { + control: 'select', + options: ['default', 'sm'], + }, + }, + args: { children: 'Button' }, +}; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + children: 'Button', + }, +}; + +export const OrangeButton: Story = { + args: { + backgroundColor: 'orange', + textColor: 'white', + children: 'Button', + }, +}; + +export const GrayButton: Story = { + args: { + backgroundColor: 'gray', + textColor: 'white', + children: 'Button', + }, +}; + +export const SmallButton: Story = { + args: { + backgroundColor: 'orange', + textColor: 'white', + children: 'Button', + size: 'sm', + }, +}; diff --git a/packages/frontend/src/components/ui/button/Button.tsx b/packages/frontend/src/components/ui/button/Button.tsx new file mode 100644 index 00000000..7000fb44 --- /dev/null +++ b/packages/frontend/src/components/ui/button/Button.tsx @@ -0,0 +1,56 @@ +import type { ButtonHTMLAttributes, ReactNode } from 'react'; +import { cva, VariantProps } from 'class-variance-authority'; +import { cn } from '@/utils/cn'; + +export const ButtonVariants = cva( + `display-bold12 border rounded shadow-black`, + { + variants: { + backgroundColor: { + default: 'bg-white', + gray: 'bg-gray', + orange: 'bg-orange', + }, + textColor: { + default: 'text-orange', + white: 'text-white', + }, + size: { + default: 'w-24', + sm: 'w-14', + }, + }, + defaultVariants: { + backgroundColor: 'default', + textColor: 'default', + size: 'default', + }, + }, +); + +export interface ButtonProps + extends ButtonHTMLAttributes, + VariantProps { + children: ReactNode; +} + +export const Button = ({ + backgroundColor, + textColor, + size, + children, + className, + ...props +}: ButtonProps) => { + return ( + + ); +}; diff --git a/packages/frontend/src/components/ui/button/index.ts b/packages/frontend/src/components/ui/button/index.ts new file mode 100644 index 00000000..8b166a86 --- /dev/null +++ b/packages/frontend/src/components/ui/button/index.ts @@ -0,0 +1 @@ +export * from './Button'; diff --git a/packages/frontend/src/components/ui/tooltip/Tooltip.stories.tsx b/packages/frontend/src/components/ui/tooltip/Tooltip.stories.tsx new file mode 100644 index 00000000..ed63f5e7 --- /dev/null +++ b/packages/frontend/src/components/ui/tooltip/Tooltip.stories.tsx @@ -0,0 +1,31 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { Tooltip, TooltipProps } from '.'; + +const TooltipWrapper = ({ children }: TooltipProps) => { + return ( +
    + {children} + +
    + ); +}; + +const meta: Meta = { + title: 'Example/Tooltip', + component: TooltipWrapper, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + + args: { children: 'Tooltip' }, +}; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + children: 'Tooltip', + }, +}; diff --git a/packages/frontend/src/components/ui/tooltip/Tooltip.tsx b/packages/frontend/src/components/ui/tooltip/Tooltip.tsx new file mode 100644 index 00000000..8972ce02 --- /dev/null +++ b/packages/frontend/src/components/ui/tooltip/Tooltip.tsx @@ -0,0 +1,22 @@ +import { type ReactNode } from 'react'; +import { cn } from '@/utils/cn'; + +export interface TooltipProps { + className?: string; + children?: ReactNode; +} + +export const Tooltip = ({ className, children }: TooltipProps) => { + return ( +
    + {children} +
    +
    + ); +}; diff --git a/packages/frontend/src/components/ui/tooltip/index.ts b/packages/frontend/src/components/ui/tooltip/index.ts new file mode 100644 index 00000000..7594a8f0 --- /dev/null +++ b/packages/frontend/src/components/ui/tooltip/index.ts @@ -0,0 +1 @@ +export * from './Tooltip'; diff --git a/packages/frontend/src/constants/METRIC_DETAILS.ts b/packages/frontend/src/constants/METRIC_DETAILS.ts new file mode 100644 index 00000000..2f5150e8 --- /dev/null +++ b/packages/frontend/src/constants/METRIC_DETAILS.ts @@ -0,0 +1,38 @@ +export const METRIC_DETAILS = { + tradingVolume: { + name: '거래량', + message: '특정 기간 동안 거래된 주식의 수량이에요.', + }, + price: { + currentPrice: { + name: '현재가', + message: '현재 주식의 거래 가격이에요.', + }, + tradingVolume: { + name: '거래량', + message: '해당 기간 동안 거래된 주식의 수량이에요.', + }, + fluctuationRate: { + name: '변동률', + message: '전일 대비 주가 변동 비율이에요.', + }, + fiftyTwoWeekRange: { + name: '52주 최고/최저가', + message: '최근 52주 동안의 최고/최저 주가예요.', + }, + }, + enterpriseValue: { + marketCap: { + name: '시가총액', + message: '발행 주식 수와 현재 가격을 곱한 값으로, 기업가치를 나타내요.', + }, + per: { + name: 'PER', + message: '주가/주당순이익으로, 주식의 투자 매력도를 나타내요.', + }, + eps: { + name: 'EPS', + message: '주당순이익으로, 기업의 수익성을 보여줘요.', + }, + }, +}; diff --git a/packages/frontend/src/constants/menuItems.tsx b/packages/frontend/src/constants/menuItems.tsx new file mode 100644 index 00000000..abedf45f --- /dev/null +++ b/packages/frontend/src/constants/menuItems.tsx @@ -0,0 +1,31 @@ +import { type ReactElement } from 'react'; +import Bell from '@/assets/bell.svg?react'; +import Home from '@/assets/home.svg?react'; +import Search from '@/assets/search.svg?react'; +import Stock from '@/assets/stock.svg?react'; +import Theme from '@/assets/theme.svg?react'; +import User from '@/assets/user.svg?react'; + +export interface MenuItemData { + icon: ReactElement; + text: string; + id: number; + url?: string; +} + +export const topMenuItems: MenuItemData[] = [ + { icon: , text: '검색', id: 1 }, + { icon: , text: '홈', id: 2, url: '/' }, + { icon: , text: '주식', id: 3, url: '/stocks' }, + { icon: , text: '알림', id: 4 }, +]; + +export const bottomMenuItems: MenuItemData[] = [ + { icon: , text: '다크모드', id: 1 }, + { + icon: , + text: '마이페이지', + id: 2, + url: '/my-page', + }, +]; diff --git a/packages/frontend/src/constants/metricItem.ts b/packages/frontend/src/constants/metricItem.ts new file mode 100644 index 00000000..609ecdf9 --- /dev/null +++ b/packages/frontend/src/constants/metricItem.ts @@ -0,0 +1,23 @@ +export type MetricItemValue = { + id: number; + label: string; +}; + +type MetricItem = { + trading_volume: MetricItemValue[]; + enterprise_value: MetricItemValue[]; +}; + +export const METRIC_ITEM: MetricItem = { + trading_volume: [ + { id: 0, label: '현재가' }, + { id: 1, label: '52주 최고가' }, + { id: 2, label: '변동률' }, + { id: 3, label: '52주 최저가' }, + ], + enterprise_value: [ + { id: 0, label: '시가총액' }, + { id: 1, label: 'EPS' }, + { id: 2, label: 'PER' }, + ], +}; diff --git a/packages/frontend/src/index.css b/packages/frontend/src/index.css index b5c61c95..7b68d633 100644 --- a/packages/frontend/src/index.css +++ b/packages/frontend/src/index.css @@ -1,3 +1,56 @@ @tailwind base; @tailwind components; @tailwind utilities; + +@font-face { + font-family: 'Pretendard-Regular'; + src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff') + format('woff'); + font-weight: 400; + font-style: normal; +} + +@layer base { + html { + font-family: 'Pretendard-Regular'; + background-color: #f0f0f0; + } +} + +@layer utilities { + .display-bold24 { + @apply text-2xl font-bold; + } + + .display-bold20 { + @apply text-xl font-bold; + } + + .display-bold16 { + @apply text-base font-bold; + } + + .display-bold14 { + @apply text-sm font-bold; + } + + .display-bold12 { + @apply text-xs font-bold; + } + + .display-medium20 { + @apply text-xl; + } + + .display-medium16 { + @apply text-base; + } + + .display-medium14 { + @apply text-sm; + } + + .display-medium12 { + @apply text-xs; + } +} diff --git a/packages/frontend/src/mocks/priceData.json b/packages/frontend/src/mocks/priceData.json new file mode 100644 index 00000000..61a3d187 --- /dev/null +++ b/packages/frontend/src/mocks/priceData.json @@ -0,0 +1,1047 @@ +{ + "data": [ + { + "time": "2018-10-19", + "open": 180.34, + "high": 180.99, + "low": 178.57, + "close": 179.85 + }, + { + "time": "2018-10-22", + "open": 180.82, + "high": 181.4, + "low": 177.56, + "close": 178.75 + }, + { + "time": "2018-10-23", + "open": 175.77, + "high": 179.49, + "low": 175.44, + "close": 178.53 + }, + { + "time": "2018-10-24", + "open": 178.58, + "high": 182.37, + "low": 176.31, + "close": 176.97 + }, + { + "time": "2018-10-25", + "open": 177.52, + "high": 180.5, + "low": 176.83, + "close": 179.07 + }, + { + "time": "2018-10-26", + "open": 176.88, + "high": 177.34, + "low": 170.91, + "close": 172.23 + }, + { + "time": "2018-10-29", + "open": 173.74, + "high": 175.99, + "low": 170.95, + "close": 173.2 + }, + { + "time": "2018-10-30", + "open": 173.16, + "high": 176.43, + "low": 172.64, + "close": 176.24 + }, + { + "time": "2018-10-31", + "open": 177.98, + "high": 178.85, + "low": 175.59, + "close": 175.88 + }, + { + "time": "2018-11-01", + "open": 176.84, + "high": 180.86, + "low": 175.9, + "close": 180.46 + }, + { + "time": "2018-11-02", + "open": 182.47, + "high": 183.01, + "low": 177.39, + "close": 179.93 + }, + { + "time": "2018-11-05", + "open": 181.02, + "high": 182.41, + "low": 179.3, + "close": 182.19 + }, + { + "time": "2018-11-06", + "open": 181.93, + "high": 182.65, + "low": 180.05, + "close": 182.01 + }, + { + "time": "2018-11-07", + "open": 183.79, + "high": 187.68, + "low": 182.06, + "close": 187.23 + }, + { + "time": "2018-11-08", + "open": 187.13, + "high": 188.69, + "low": 185.72, + "close": 188.0 + }, + { + "time": "2018-11-09", + "open": 188.32, + "high": 188.48, + "low": 184.96, + "close": 185.99 + }, + { + "time": "2018-11-12", + "open": 185.23, + "high": 186.95, + "low": 179.02, + "close": 179.43 + }, + { + "time": "2018-11-13", + "open": 177.3, + "high": 181.62, + "low": 172.85, + "close": 179.0 + }, + { + "time": "2018-11-14", + "open": 182.61, + "high": 182.9, + "low": 179.15, + "close": 179.9 + }, + { + "time": "2018-11-15", + "open": 179.01, + "high": 179.67, + "low": 173.61, + "close": 177.36 + }, + { + "time": "2018-11-16", + "open": 173.99, + "high": 177.6, + "low": 173.51, + "close": 177.02 + }, + { + "time": "2018-11-19", + "open": 176.71, + "high": 178.88, + "low": 172.3, + "close": 173.59 + }, + { + "time": "2018-11-20", + "open": 169.25, + "high": 172.0, + "low": 167.0, + "close": 169.05 + }, + { + "time": "2018-11-21", + "open": 170.0, + "high": 170.93, + "low": 169.15, + "close": 169.3 + }, + { + "time": "2018-11-23", + "open": 169.39, + "high": 170.33, + "low": 168.47, + "close": 168.85 + }, + { + "time": "2018-11-26", + "open": 170.2, + "high": 172.39, + "low": 168.87, + "close": 169.82 + }, + { + "time": "2018-11-27", + "open": 169.11, + "high": 173.38, + "low": 168.82, + "close": 173.22 + }, + { + "time": "2018-11-28", + "open": 172.91, + "high": 177.65, + "low": 170.62, + "close": 177.43 + }, + { + "time": "2018-11-29", + "open": 176.8, + "high": 177.27, + "low": 174.92, + "close": 175.66 + }, + { + "time": "2018-11-30", + "open": 175.75, + "high": 180.37, + "low": 175.11, + "close": 180.32 + }, + { + "time": "2018-12-03", + "open": 183.29, + "high": 183.5, + "low": 179.35, + "close": 181.74 + }, + { + "time": "2018-12-04", + "open": 181.06, + "high": 182.23, + "low": 174.55, + "close": 175.3 + }, + { + "time": "2018-12-06", + "open": 173.5, + "high": 176.04, + "low": 170.46, + "close": 175.96 + }, + { + "time": "2018-12-07", + "open": 175.35, + "high": 178.36, + "low": 172.24, + "close": 172.79 + }, + { + "time": "2018-12-10", + "open": 173.39, + "high": 173.99, + "low": 167.73, + "close": 171.69 + }, + { + "time": "2018-12-11", + "open": 174.3, + "high": 175.6, + "low": 171.24, + "close": 172.21 + }, + { + "time": "2018-12-12", + "open": 173.75, + "high": 176.87, + "low": 172.81, + "close": 174.21 + }, + { + "time": "2018-12-13", + "open": 174.31, + "high": 174.91, + "low": 172.07, + "close": 173.87 + }, + { + "time": "2018-12-14", + "open": 172.98, + "high": 175.14, + "low": 171.95, + "close": 172.29 + }, + { + "time": "2018-12-17", + "open": 171.51, + "high": 171.99, + "low": 166.93, + "close": 167.97 + }, + { + "time": "2018-12-18", + "open": 168.9, + "high": 171.95, + "low": 168.5, + "close": 170.04 + }, + { + "time": "2018-12-19", + "open": 170.92, + "high": 174.95, + "low": 166.77, + "close": 167.56 + }, + { + "time": "2018-12-20", + "open": 166.28, + "high": 167.31, + "low": 162.23, + "close": 164.16 + }, + { + "time": "2018-12-21", + "open": 162.81, + "high": 167.96, + "low": 160.17, + "close": 160.48 + }, + { + "time": "2018-12-24", + "open": 160.16, + "high": 161.4, + "low": 158.09, + "close": 158.14 + }, + { + "time": "2018-12-26", + "open": 159.46, + "high": 168.28, + "low": 159.44, + "close": 168.28 + }, + { + "time": "2018-12-27", + "open": 166.44, + "high": 170.46, + "low": 163.36, + "close": 170.32 + }, + { + "time": "2018-12-28", + "open": 171.22, + "high": 173.12, + "low": 168.6, + "close": 170.22 + }, + { + "time": "2018-12-31", + "open": 171.47, + "high": 173.24, + "low": 170.65, + "close": 171.82 + }, + { + "time": "2019-01-02", + "open": 169.71, + "high": 173.18, + "low": 169.05, + "close": 172.41 + }, + { + "time": "2019-01-03", + "open": 171.84, + "high": 171.84, + "low": 168.21, + "close": 168.61 + }, + { + "time": "2019-01-04", + "open": 170.18, + "high": 174.74, + "low": 169.52, + "close": 173.62 + }, + { + "time": "2019-01-07", + "open": 173.83, + "high": 178.18, + "low": 173.83, + "close": 177.04 + }, + { + "time": "2019-01-08", + "open": 178.57, + "high": 179.59, + "low": 175.61, + "close": 177.89 + }, + { + "time": "2019-01-09", + "open": 177.87, + "high": 181.27, + "low": 177.1, + "close": 179.73 + }, + { + "time": "2019-01-10", + "open": 178.03, + "high": 179.24, + "low": 176.34, + "close": 179.06 + }, + { + "time": "2019-01-11", + "open": 177.93, + "high": 180.26, + "low": 177.12, + "close": 179.41 + }, + { + "time": "2019-01-14", + "open": 177.59, + "high": 179.23, + "low": 176.9, + "close": 178.81 + }, + { + "time": "2019-01-15", + "open": 176.08, + "high": 177.82, + "low": 175.2, + "close": 176.47 + }, + { + "time": "2019-01-16", + "open": 177.09, + "high": 177.93, + "low": 175.86, + "close": 177.04 + }, + { + "time": "2019-01-17", + "open": 174.01, + "high": 175.46, + "low": 172.0, + "close": 174.87 + }, + { + "time": "2019-01-18", + "open": 176.98, + "high": 180.04, + "low": 176.18, + "close": 179.58 + }, + { + "time": "2019-01-22", + "open": 177.49, + "high": 178.6, + "low": 175.36, + "close": 177.11 + }, + { + "time": "2019-01-23", + "open": 176.59, + "high": 178.06, + "low": 174.53, + "close": 176.89 + }, + { + "time": "2019-01-24", + "open": 177.0, + "high": 177.53, + "low": 175.3, + "close": 177.29 + }, + { + "time": "2019-01-25", + "open": 179.78, + "high": 180.87, + "low": 178.61, + "close": 180.4 + }, + { + "time": "2019-01-28", + "open": 178.97, + "high": 179.99, + "low": 177.41, + "close": 179.83 + }, + { + "time": "2019-01-29", + "open": 178.96, + "high": 180.15, + "low": 178.09, + "close": 179.69 + }, + { + "time": "2019-01-30", + "open": 180.47, + "high": 184.2, + "low": 179.78, + "close": 182.18 + }, + { + "time": "2019-01-31", + "open": 181.5, + "high": 184.67, + "low": 181.06, + "close": 183.53 + }, + { + "time": "2019-02-01", + "open": 184.03, + "high": 185.15, + "low": 182.83, + "close": 184.37 + }, + { + "time": "2019-02-04", + "open": 184.3, + "high": 186.43, + "low": 183.84, + "close": 186.43 + }, + { + "time": "2019-02-05", + "open": 186.89, + "high": 186.99, + "low": 184.69, + "close": 186.39 + }, + { + "time": "2019-02-06", + "open": 186.69, + "high": 186.69, + "low": 184.06, + "close": 184.72 + }, + { + "time": "2019-02-07", + "open": 183.74, + "high": 184.92, + "low": 182.45, + "close": 184.07 + }, + { + "time": "2019-02-08", + "open": 183.05, + "high": 184.58, + "low": 182.72, + "close": 184.54 + }, + { + "time": "2019-02-11", + "open": 185.0, + "high": 185.42, + "low": 182.75, + "close": 182.92 + }, + { + "time": "2019-02-12", + "open": 183.84, + "high": 186.4, + "low": 183.52, + "close": 185.52 + }, + { + "time": "2019-02-13", + "open": 186.3, + "high": 188.68, + "low": 185.92, + "close": 188.41 + }, + { + "time": "2019-02-14", + "open": 187.5, + "high": 188.93, + "low": 186.0, + "close": 187.71 + }, + { + "time": "2019-02-15", + "open": 189.87, + "high": 192.62, + "low": 189.05, + "close": 192.39 + }, + { + "time": "2019-02-19", + "open": 191.71, + "high": 193.19, + "low": 191.28, + "close": 192.33 + }, + { + "time": "2019-02-20", + "open": 192.39, + "high": 192.4, + "low": 191.11, + "close": 191.85 + }, + { + "time": "2019-02-21", + "open": 191.85, + "high": 192.37, + "low": 190.61, + "close": 191.82 + }, + { + "time": "2019-02-22", + "open": 191.69, + "high": 192.54, + "low": 191.62, + "close": 192.39 + }, + { + "time": "2019-02-25", + "open": 192.75, + "high": 193.42, + "low": 189.96, + "close": 189.98 + }, + { + "time": "2019-02-26", + "open": 185.59, + "high": 188.47, + "low": 182.8, + "close": 188.3 + }, + { + "time": "2019-02-27", + "open": 187.9, + "high": 188.5, + "low": 183.21, + "close": 183.67 + }, + { + "time": "2019-02-28", + "open": 183.6, + "high": 185.19, + "low": 183.11, + "close": 185.14 + }, + { + "time": "2019-03-01", + "open": 185.82, + "high": 186.56, + "low": 182.86, + "close": 185.17 + }, + { + "time": "2019-03-04", + "open": 186.2, + "high": 186.24, + "low": 182.1, + "close": 183.81 + }, + { + "time": "2019-03-05", + "open": 184.24, + "high": 185.12, + "low": 183.25, + "close": 184.0 + }, + { + "time": "2019-03-06", + "open": 184.53, + "high": 184.97, + "low": 183.84, + "close": 184.45 + }, + { + "time": "2019-03-07", + "open": 184.39, + "high": 184.62, + "low": 181.58, + "close": 182.51 + }, + { + "time": "2019-03-08", + "open": 181.49, + "high": 181.91, + "low": 179.52, + "close": 181.23 + }, + { + "time": "2019-03-11", + "open": 182.0, + "high": 183.2, + "low": 181.2, + "close": 182.44 + }, + { + "time": "2019-03-12", + "open": 183.43, + "high": 184.27, + "low": 182.33, + "close": 184.0 + }, + { + "time": "2019-03-13", + "open": 183.24, + "high": 183.78, + "low": 181.08, + "close": 181.14 + }, + { + "time": "2019-03-14", + "open": 181.28, + "high": 181.74, + "low": 180.5, + "close": 181.61 + }, + { + "time": "2019-03-15", + "open": 182.3, + "high": 182.49, + "low": 179.57, + "close": 182.23 + }, + { + "time": "2019-03-18", + "open": 182.53, + "high": 183.48, + "low": 182.33, + "close": 183.42 + }, + { + "time": "2019-03-19", + "open": 184.19, + "high": 185.82, + "low": 183.48, + "close": 184.13 + }, + { + "time": "2019-03-20", + "open": 184.3, + "high": 187.12, + "low": 183.43, + "close": 186.1 + }, + { + "time": "2019-03-21", + "open": 185.5, + "high": 190.0, + "low": 185.5, + "close": 189.97 + }, + { + "time": "2019-03-22", + "open": 189.31, + "high": 192.05, + "low": 188.67, + "close": 188.75 + }, + { + "time": "2019-03-25", + "open": 188.75, + "high": 191.71, + "low": 188.51, + "close": 189.68 + }, + { + "time": "2019-03-26", + "open": 190.69, + "high": 192.19, + "low": 188.74, + "close": 189.34 + }, + { + "time": "2019-03-27", + "open": 189.65, + "high": 191.61, + "low": 188.39, + "close": 189.25 + }, + { + "time": "2019-03-28", + "open": 189.91, + "high": 191.4, + "low": 189.16, + "close": 190.06 + }, + { + "time": "2019-03-29", + "open": 190.85, + "high": 192.04, + "low": 190.14, + "close": 191.89 + }, + { + "time": "2019-04-01", + "open": 192.99, + "high": 195.9, + "low": 192.85, + "close": 195.64 + }, + { + "time": "2019-04-02", + "open": 195.5, + "high": 195.5, + "low": 194.01, + "close": 194.31 + }, + { + "time": "2019-04-03", + "open": 194.98, + "high": 198.78, + "low": 194.11, + "close": 198.61 + }, + { + "time": "2019-04-04", + "open": 199.0, + "high": 200.49, + "low": 198.02, + "close": 200.45 + }, + { + "time": "2019-04-05", + "open": 200.86, + "high": 203.13, + "low": 200.61, + "close": 202.06 + }, + { + "time": "2019-04-08", + "open": 201.37, + "high": 203.79, + "low": 201.24, + "close": 203.55 + }, + { + "time": "2019-04-09", + "open": 202.26, + "high": 202.71, + "low": 200.46, + "close": 200.9 + }, + { + "time": "2019-04-10", + "open": 201.26, + "high": 201.6, + "low": 198.02, + "close": 199.43 + }, + { + "time": "2019-04-11", + "open": 199.9, + "high": 201.5, + "low": 199.03, + "close": 201.48 + }, + { + "time": "2019-04-12", + "open": 202.13, + "high": 204.26, + "low": 202.13, + "close": 203.85 + }, + { + "time": "2019-04-15", + "open": 204.16, + "high": 205.14, + "low": 203.4, + "close": 204.86 + }, + { + "time": "2019-04-16", + "open": 205.25, + "high": 205.99, + "low": 204.29, + "close": 204.47 + }, + { + "time": "2019-04-17", + "open": 205.34, + "high": 206.84, + "low": 205.32, + "close": 206.55 + }, + { + "time": "2019-04-18", + "open": 206.02, + "high": 207.78, + "low": 205.1, + "close": 205.66 + }, + { + "time": "2019-04-22", + "open": 204.11, + "high": 206.25, + "low": 204.0, + "close": 204.78 + }, + { + "time": "2019-04-23", + "open": 205.14, + "high": 207.33, + "low": 203.43, + "close": 206.05 + }, + { + "time": "2019-04-24", + "open": 206.16, + "high": 208.29, + "low": 205.54, + "close": 206.72 + }, + { + "time": "2019-04-25", + "open": 206.01, + "high": 207.72, + "low": 205.06, + "close": 206.5 + }, + { + "time": "2019-04-26", + "open": 205.88, + "high": 206.14, + "low": 203.34, + "close": 203.61 + }, + { + "time": "2019-04-29", + "open": 203.31, + "high": 203.8, + "low": 200.34, + "close": 202.16 + }, + { + "time": "2019-04-30", + "open": 201.55, + "high": 203.75, + "low": 200.79, + "close": 203.7 + }, + { + "time": "2019-05-01", + "open": 203.2, + "high": 203.52, + "low": 198.66, + "close": 198.8 + }, + { + "time": "2019-05-02", + "open": 199.3, + "high": 201.06, + "low": 198.8, + "close": 201.01 + }, + { + "time": "2019-05-03", + "open": 202.0, + "high": 202.31, + "low": 200.32, + "close": 200.56 + }, + { + "time": "2019-05-06", + "open": 198.74, + "high": 199.93, + "low": 198.31, + "close": 199.63 + }, + { + "time": "2019-05-07", + "open": 196.75, + "high": 197.65, + "low": 192.96, + "close": 194.77 + }, + { + "time": "2019-05-08", + "open": 194.49, + "high": 196.61, + "low": 193.68, + "close": 195.17 + }, + { + "time": "2019-05-09", + "open": 193.31, + "high": 195.08, + "low": 191.59, + "close": 194.58 + }, + { + "time": "2019-05-10", + "open": 193.21, + "high": 195.49, + "low": 190.01, + "close": 194.58 + }, + { + "time": "2019-05-13", + "open": 191.0, + "high": 191.66, + "low": 189.14, + "close": 190.34 + }, + { + "time": "2019-05-14", + "open": 190.5, + "high": 192.76, + "low": 190.01, + "close": 191.62 + }, + { + "time": "2019-05-15", + "open": 190.81, + "high": 192.81, + "low": 190.27, + "close": 191.76 + }, + { + "time": "2019-05-16", + "open": 192.47, + "high": 194.96, + "low": 192.2, + "close": 192.38 + }, + { + "time": "2019-05-17", + "open": 190.86, + "high": 194.5, + "low": 190.75, + "close": 192.58 + }, + { + "time": "2019-05-20", + "open": 191.13, + "high": 192.86, + "low": 190.61, + "close": 190.95 + }, + { + "time": "2019-05-21", + "open": 187.13, + "high": 192.52, + "low": 186.34, + "close": 191.45 + }, + { + "time": "2019-05-22", + "open": 190.49, + "high": 192.22, + "low": 188.05, + "close": 188.91 + }, + { + "time": "2019-05-23", + "open": 188.45, + "high": 192.54, + "low": 186.27, + "close": 192.0 + }, + { + "time": "2019-05-24", + "open": 192.54, + "high": 193.86, + "low": 190.41, + "close": 193.59 + } + ] +} diff --git a/packages/frontend/src/mocks/volumeData.json b/packages/frontend/src/mocks/volumeData.json new file mode 100644 index 00000000..34df5f05 --- /dev/null +++ b/packages/frontend/src/mocks/volumeData.json @@ -0,0 +1,154 @@ +{ + "data": [ + { "time": "2018-10-19", "value": 19103293.0 }, + { "time": "2018-10-22", "value": 21737523.0 }, + { "time": "2018-10-23", "value": 29328713.0 }, + { "time": "2018-10-24", "value": 37435638.0 }, + { "time": "2018-10-25", "value": 25269995.0 }, + { "time": "2018-10-26", "value": 24973311.0 }, + { "time": "2018-10-29", "value": 22103692.0 }, + { "time": "2018-10-30", "value": 25231199.0 }, + { "time": "2018-10-31", "value": 24214427.0 }, + { "time": "2018-11-01", "value": 22533201.0 }, + { "time": "2018-11-02", "value": 14734412.0 }, + { "time": "2018-11-05", "value": 12733842.0 }, + { "time": "2018-11-06", "value": 12371207.0 }, + { "time": "2018-11-07", "value": 14891287.0 }, + { "time": "2018-11-08", "value": 12482392.0 }, + { "time": "2018-11-09", "value": 17365762.0 }, + { "time": "2018-11-12", "value": 13236769.0 }, + { "time": "2018-11-13", "value": 13047907.0 }, + { "time": "2018-11-14", "value": 18288710.0 }, + { "time": "2018-11-15", "value": 17147123.0 }, + { "time": "2018-11-16", "value": 19470986.0 }, + { "time": "2018-11-19", "value": 18405731.0 }, + { "time": "2018-11-20", "value": 22028957.0 }, + { "time": "2018-11-21", "value": 18482233.0 }, + { "time": "2018-11-23", "value": 7009050.0 }, + { "time": "2018-11-26", "value": 12308876.0 }, + { "time": "2018-11-27", "value": 14118867.0 }, + { "time": "2018-11-28", "value": 18662989.0 }, + { "time": "2018-11-29", "value": 14763658.0 }, + { "time": "2018-11-30", "value": 31142818.0 }, + { "time": "2018-12-03", "value": 27795428.0 }, + { "time": "2018-12-04", "value": 21727411.0 }, + { "time": "2018-12-06", "value": 26880429.0 }, + { "time": "2018-12-07", "value": 16948126.0 }, + { "time": "2018-12-10", "value": 16603356.0 }, + { "time": "2018-12-11", "value": 14991438.0 }, + { "time": "2018-12-12", "value": 18892182.0 }, + { "time": "2018-12-13", "value": 15454706.0 }, + { "time": "2018-12-14", "value": 13960870.0 }, + { "time": "2018-12-17", "value": 18902523.0 }, + { "time": "2018-12-18", "value": 18895777.0 }, + { "time": "2018-12-19", "value": 20968473.0 }, + { "time": "2018-12-20", "value": 26897008.0 }, + { "time": "2018-12-21", "value": 55413082.0 }, + { "time": "2018-12-24", "value": 15077207.0 }, + { "time": "2018-12-26", "value": 17970539.0 }, + { "time": "2018-12-27", "value": 17530977.0 }, + { "time": "2018-12-28", "value": 14771641.0 }, + { "time": "2018-12-31", "value": 15331758.0 }, + { "time": "2019-01-02", "value": 13969691.0 }, + { "time": "2019-01-03", "value": 19245411.0 }, + { "time": "2019-01-04", "value": 17035848.0 }, + { "time": "2019-01-07", "value": 16348982.0 }, + { "time": "2019-01-08", "value": 21425008.0 }, + { "time": "2019-01-09", "value": 18136000.0 }, + { "time": "2019-01-10", "value": 14259910.0 }, + { "time": "2019-01-11", "value": 15801548.0 }, + { "time": "2019-01-14", "value": 11342293.0 }, + { "time": "2019-01-15", "value": 10074386.0 }, + { "time": "2019-01-16", "value": 13411691.0 }, + { "time": "2019-01-17", "value": 15223854.0 }, + { "time": "2019-01-18", "value": 16802516.0 }, + { "time": "2019-01-22", "value": 18284771.0 }, + { "time": "2019-01-23", "value": 15109007.0 }, + { "time": "2019-01-24", "value": 12494109.0 }, + { "time": "2019-01-25", "value": 17806822.0 }, + { "time": "2019-01-28", "value": 25955718.0 }, + { "time": "2019-01-29", "value": 33789235.0 }, + { "time": "2019-01-30", "value": 27260036.0 }, + { "time": "2019-01-31", "value": 28585447.0 }, + { "time": "2019-02-01", "value": 13778392.0 }, + { "time": "2019-02-04", "value": 15818901.0 }, + { "time": "2019-02-05", "value": 14124794.0 }, + { "time": "2019-02-06", "value": 11391442.0 }, + { "time": "2019-02-07", "value": 12436168.0 }, + { "time": "2019-02-08", "value": 12011657.0 }, + { "time": "2019-02-11", "value": 9802798.0 }, + { "time": "2019-02-12", "value": 11227550.0 }, + { "time": "2019-02-13", "value": 11884803.0 }, + { "time": "2019-02-14", "value": 11190094.0 }, + { "time": "2019-02-15", "value": 15719416.0 }, + { "time": "2019-02-19", "value": 12272877.0 }, + { "time": "2019-02-20", "value": 11379006.0 }, + { "time": "2019-02-21", "value": 14680547.0 }, + { "time": "2019-02-22", "value": 12534431.0 }, + { "time": "2019-02-25", "value": 15051182.0 }, + { "time": "2019-02-26", "value": 12005571.0 }, + { "time": "2019-02-27", "value": 8962776.0 }, + { "time": "2019-02-28", "value": 15742971.0 }, + { "time": "2019-03-01", "value": 10942737.0 }, + { "time": "2019-03-04", "value": 13674737.0 }, + { "time": "2019-03-05", "value": 15749545.0 }, + { "time": "2019-03-06", "value": 13935530.0 }, + { "time": "2019-03-07", "value": 12644171.0 }, + { "time": "2019-03-08", "value": 10646710.0 }, + { "time": "2019-03-11", "value": 13627431.0 }, + { "time": "2019-03-12", "value": 12812980.0 }, + { "time": "2019-03-13", "value": 14168350.0 }, + { "time": "2019-03-14", "value": 12148349.0 }, + { "time": "2019-03-15", "value": 23715337.0 }, + { "time": "2019-03-18", "value": 12168133.0 }, + { "time": "2019-03-19", "value": 13462686.0 }, + { "time": "2019-03-20", "value": 11903104.0 }, + { "time": "2019-03-21", "value": 10920129.0 }, + { "time": "2019-03-22", "value": 25125385.0 }, + { "time": "2019-03-25", "value": 15463411.0 }, + { "time": "2019-03-26", "value": 12316901.0 }, + { "time": "2019-03-27", "value": 13290298.0 }, + { "time": "2019-03-28", "value": 20547060.0 }, + { "time": "2019-03-29", "value": 17283871.0 }, + { "time": "2019-04-01", "value": 16331140.0 }, + { "time": "2019-04-02", "value": 11408146.0 }, + { "time": "2019-04-03", "value": 15491724.0 }, + { "time": "2019-04-04", "value": 8776028.0 }, + { "time": "2019-04-05", "value": 11497780.0 }, + { "time": "2019-04-08", "value": 11680538.0 }, + { "time": "2019-04-09", "value": 10414416.0 }, + { "time": "2019-04-10", "value": 8782061.0 }, + { "time": "2019-04-11", "value": 9219930.0 }, + { "time": "2019-04-12", "value": 10847504.0 }, + { "time": "2019-04-15", "value": 7741472.0 }, + { "time": "2019-04-16", "value": 10239261.0 }, + { "time": "2019-04-17", "value": 15498037.0 }, + { "time": "2019-04-18", "value": 13189013.0 }, + { "time": "2019-04-22", "value": 11950365.0 }, + { "time": "2019-04-23", "value": 23488682.0 }, + { "time": "2019-04-24", "value": 13227084.0 }, + { "time": "2019-04-25", "value": 17425466.0 }, + { "time": "2019-04-26", "value": 16329727.0 }, + { "time": "2019-04-29", "value": 13984965.0 }, + { "time": "2019-04-30", "value": 15469002.0 }, + { "time": "2019-05-01", "value": 11627436.0 }, + { "time": "2019-05-02", "value": 14435436.0 }, + { "time": "2019-05-03", "value": 9388228.0 }, + { "time": "2019-05-06", "value": 10066145.0 }, + { "time": "2019-05-07", "value": 12963827.0 }, + { "time": "2019-05-08", "value": 12086743.0 }, + { "time": "2019-05-09", "value": 14835326.0 }, + { "time": "2019-05-10", "value": 10707335.0 }, + { "time": "2019-05-13", "value": 13759350.0 }, + { "time": "2019-05-14", "value": 12776175.0 }, + { "time": "2019-05-15", "value": 10806379.0 }, + { "time": "2019-05-16", "value": 11695064.0 }, + { "time": "2019-05-17", "value": 14436662.0 }, + { "time": "2019-05-20", "value": 20910590.0 }, + { "time": "2019-05-21", "value": 14016315.0 }, + { "time": "2019-05-22", "value": 11487448.0 }, + { "time": "2019-05-23", "value": 11707083.0 }, + { "time": "2019-05-24", "value": 8755506.0 }, + { "time": "2019-05-28", "value": 3097125.0 } + ] +} diff --git a/packages/frontend/src/pages/home/Home.tsx b/packages/frontend/src/pages/home/Home.tsx new file mode 100644 index 00000000..d31605bc --- /dev/null +++ b/packages/frontend/src/pages/home/Home.tsx @@ -0,0 +1,3 @@ +export const Home = () => { + return
    ; +}; diff --git a/packages/frontend/src/pages/home/index.ts b/packages/frontend/src/pages/home/index.ts new file mode 100644 index 00000000..6fd0b5ba --- /dev/null +++ b/packages/frontend/src/pages/home/index.ts @@ -0,0 +1 @@ +export * from './Home'; diff --git a/packages/frontend/src/pages/my-page/MyPage.tsx b/packages/frontend/src/pages/my-page/MyPage.tsx new file mode 100644 index 00000000..b56bab0f --- /dev/null +++ b/packages/frontend/src/pages/my-page/MyPage.tsx @@ -0,0 +1,3 @@ +export const MyPage = () => { + return
    마이페이지
    ; +}; diff --git a/packages/frontend/src/pages/my-page/index.ts b/packages/frontend/src/pages/my-page/index.ts new file mode 100644 index 00000000..7780682b --- /dev/null +++ b/packages/frontend/src/pages/my-page/index.ts @@ -0,0 +1 @@ +export * from './MyPage'; diff --git a/packages/frontend/src/pages/stock-detail/AddAlarmForm.tsx b/packages/frontend/src/pages/stock-detail/AddAlarmForm.tsx new file mode 100644 index 00000000..95715984 --- /dev/null +++ b/packages/frontend/src/pages/stock-detail/AddAlarmForm.tsx @@ -0,0 +1,7 @@ +export const AddAlarmForm = () => { + return ( +
    +

    알림 추가

    +
    + ); +}; diff --git a/packages/frontend/src/pages/stock-detail/ChatPanel.tsx b/packages/frontend/src/pages/stock-detail/ChatPanel.tsx new file mode 100644 index 00000000..b4d808df --- /dev/null +++ b/packages/frontend/src/pages/stock-detail/ChatPanel.tsx @@ -0,0 +1,11 @@ +import { TextArea } from './components'; + +export const ChatPanel = () => { + return ( +
    +

    채팅

    + + +
    + ); +}; diff --git a/packages/frontend/src/pages/stock-detail/components/Title.tsx b/packages/frontend/src/pages/stock-detail/components/Title.tsx new file mode 100644 index 00000000..2aab6a93 --- /dev/null +++ b/packages/frontend/src/pages/stock-detail/components/Title.tsx @@ -0,0 +1,11 @@ +import { type ReactNode } from 'react'; + +interface TitleProps { + children: ReactNode; +} + +export const Title = ({ children }: TitleProps) => { + return ( +

    {children}

    + ); +}; diff --git a/packages/frontend/src/pages/stock-detail/components/index.ts b/packages/frontend/src/pages/stock-detail/components/index.ts new file mode 100644 index 00000000..dd780814 --- /dev/null +++ b/packages/frontend/src/pages/stock-detail/components/index.ts @@ -0,0 +1,4 @@ +export * from './TextArea'; +export * from './MetricItem'; +export * from './MetricSection'; +export * from './Title'; diff --git a/packages/frontend/src/pages/stock-detail/hooks/useChart.ts b/packages/frontend/src/pages/stock-detail/hooks/useChart.ts new file mode 100644 index 00000000..eecff959 --- /dev/null +++ b/packages/frontend/src/pages/stock-detail/hooks/useChart.ts @@ -0,0 +1,53 @@ +import type { ChartTheme } from '@/styles/theme'; +import { createChart, type IChartApi } from 'lightweight-charts'; +import { useEffect, useRef, RefObject } from 'react'; +import priceData from '@/mocks/priceData.json'; +import volumeData from '@/mocks/volumeData.json'; +import { + createCandlestickOptions, + createChartOptions, + createVolumeOptions, +} from '@/utils/createChartOptions'; +import { getHistogramColorData } from '@/utils/getHistogramColorData'; + +interface UseChartProps { + containerRef: RefObject; + theme: ChartTheme; +} + +export const useChart = ({ containerRef, theme }: UseChartProps) => { + const chart = useRef(); + + useEffect(() => { + if (!containerRef.current) return; + + chart.current = createChart(containerRef.current, { + width: containerRef.current.clientWidth, + height: containerRef.current.clientHeight, + ...createChartOptions(theme), + }); + + const volumeSeries = chart.current.addHistogramSeries( + createVolumeOptions(), + ); + volumeSeries.priceScale().applyOptions({ + scaleMargins: { + top: 0.93, + bottom: 0, + }, + }); + const histogramData = getHistogramColorData(volumeData.data); + volumeSeries.setData(histogramData); + + const candleSeries = chart.current.addCandlestickSeries( + createCandlestickOptions(theme), + ); + candleSeries.setData(priceData.data); + + return () => { + chart.current?.remove(); + }; + }, [containerRef, theme]); + + return chart; +}; diff --git a/packages/frontend/src/pages/stock-detail/hooks/useChartResize.ts b/packages/frontend/src/pages/stock-detail/hooks/useChartResize.ts new file mode 100644 index 00000000..263c77e7 --- /dev/null +++ b/packages/frontend/src/pages/stock-detail/hooks/useChartResize.ts @@ -0,0 +1,31 @@ +import { IChartApi } from 'lightweight-charts'; +import { MutableRefObject, useEffect, useRef, type RefObject } from 'react'; + +interface UseChartResize { + containerRef: RefObject; + chart: MutableRefObject; +} + +export const useChartResize = ({ containerRef, chart }: UseChartResize) => { + const resizeObserver = useRef(); + + useEffect(() => { + if (!containerRef.current || !chart.current) return; + + resizeObserver.current = new ResizeObserver((entries) => { + const { width, height } = entries[0].contentRect; + + chart.current?.applyOptions({ width, height }); + + requestAnimationFrame(() => { + chart.current?.timeScale().fitContent(); + }); + }); + + resizeObserver.current.observe(containerRef.current); + + return () => { + resizeObserver.current?.disconnect(); + }; + }, [chart, containerRef]); +}; diff --git a/packages/frontend/src/pages/stock-detail/index.ts b/packages/frontend/src/pages/stock-detail/index.ts new file mode 100644 index 00000000..8887d490 --- /dev/null +++ b/packages/frontend/src/pages/stock-detail/index.ts @@ -0,0 +1,5 @@ +export * from './StockDetail'; +export * from './AddAlarmForm'; +export * from './ChatPanel'; +export * from './NotificationPanel'; +export * from './StockMetricsPanel'; diff --git a/packages/frontend/src/routes/index.tsx b/packages/frontend/src/routes/index.tsx new file mode 100644 index 00000000..2a08323b --- /dev/null +++ b/packages/frontend/src/routes/index.tsx @@ -0,0 +1,26 @@ +import { createBrowserRouter } from 'react-router-dom'; +import { Layout } from '@/components/layouts'; +import { Home } from '@/pages/home'; +import { MyPage } from '@/pages/my-page'; +import { StockDetail } from '@/pages/stock-detail'; + +export const router = createBrowserRouter([ + { + element: , + children: [ + { + path: '/', + element: , + }, + { + // TODO: 주식 메인페이지 만들어지면 path 바꿀것 + path: '/stocks', + element: , + }, + { + path: '/my-page', + element: , + }, + ], + }, +]); diff --git a/packages/frontend/src/styles/theme/darkTheme.ts b/packages/frontend/src/styles/theme/darkTheme.ts new file mode 100644 index 00000000..e6e492cf --- /dev/null +++ b/packages/frontend/src/styles/theme/darkTheme.ts @@ -0,0 +1,20 @@ +import resolveConfig from 'tailwindcss/resolveConfig'; +import { ChartTheme } from '.'; +import tailwindConfig from '@/../tailwind.config'; + +const colorConfig = resolveConfig(tailwindConfig).theme.colors; +console.log(colorConfig.red); +export const darkTheme: ChartTheme = { + background: '#1a1a1a', + textColor: '#ffffffe6', + gridLines: '#334158', + borderColor: '#485c7b', + candlestick: { + upColor: colorConfig.red.toString(), + downColor: colorConfig.blue.toString(), + borderUpColor: colorConfig.red.toString(), + borderDownColor: colorConfig.blue.toString(), + wickUpColor: '#838ca1', + wickDownColor: '#838ca1', + }, +}; diff --git a/packages/frontend/src/styles/theme/index.ts b/packages/frontend/src/styles/theme/index.ts new file mode 100644 index 00000000..338dd105 --- /dev/null +++ b/packages/frontend/src/styles/theme/index.ts @@ -0,0 +1,3 @@ +export * from './darkTheme'; +export * from './lightTheme'; +export * from './types'; diff --git a/packages/frontend/src/styles/theme/lightTheme.ts b/packages/frontend/src/styles/theme/lightTheme.ts new file mode 100644 index 00000000..c1f2698d --- /dev/null +++ b/packages/frontend/src/styles/theme/lightTheme.ts @@ -0,0 +1,20 @@ +import resolveConfig from 'tailwindcss/resolveConfig'; +import { ChartTheme } from '.'; +import tailwindConfig from '@/../tailwind.config'; + +const colorConfig = resolveConfig(tailwindConfig).theme.colors; + +export const lightTheme: ChartTheme = { + background: colorConfig.white, + textColor: '#000000e6', + gridLines: '#e0e3eb', + borderColor: '#d6dcde', + candlestick: { + upColor: colorConfig.red.toString(), + downColor: colorConfig.blue.toString(), + borderUpColor: colorConfig.red.toString(), + borderDownColor: colorConfig.blue.toString(), + wickUpColor: '#737375', + wickDownColor: '#737375', + }, +}; diff --git a/packages/frontend/src/styles/theme/types.ts b/packages/frontend/src/styles/theme/types.ts new file mode 100644 index 00000000..4a9ea7a1 --- /dev/null +++ b/packages/frontend/src/styles/theme/types.ts @@ -0,0 +1,16 @@ +import type { DeepPartial, ChartOptions } from 'lightweight-charts'; + +export interface ChartTheme extends DeepPartial { + background: string; + textColor: string; + gridLines: string; + borderColor: string; + candlestick: { + upColor: string; + downColor: string; + borderUpColor: string; + borderDownColor: string; + wickUpColor: string; + wickDownColor: string; + }; +} diff --git a/packages/frontend/src/utils/cn.ts b/packages/frontend/src/utils/cn.ts new file mode 100644 index 00000000..ffe21d21 --- /dev/null +++ b/packages/frontend/src/utils/cn.ts @@ -0,0 +1,6 @@ +import { ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export const cn = (...inputs: ClassValue[]) => { + return twMerge(clsx(inputs)); +}; diff --git a/packages/frontend/src/utils/createChartOptions.ts b/packages/frontend/src/utils/createChartOptions.ts new file mode 100644 index 00000000..b6618aa8 --- /dev/null +++ b/packages/frontend/src/utils/createChartOptions.ts @@ -0,0 +1,47 @@ +import type { ChartTheme } from '@/styles/theme'; +import { + type DeepPartial, + type HistogramStyleOptions, + type SeriesOptionsCommon, + CrosshairMode, + ColorType, +} from 'lightweight-charts'; + +export const createChartOptions = (theme: ChartTheme) => { + const { background, textColor, gridLines, borderColor } = theme; + + return { + layout: { + background: { type: ColorType.Solid, color: background }, + textColor: textColor, + }, + grid: { + vertLines: { + color: gridLines, + }, + horzLines: { + color: gridLines, + }, + }, + crosshair: { + mode: CrosshairMode.Normal, + }, + timeScale: { + borderColor: borderColor, + }, + }; +}; + +export const createVolumeOptions = (): DeepPartial< + HistogramStyleOptions & SeriesOptionsCommon +> => ({ + priceLineWidth: 2, + priceFormat: { + type: 'volume', + }, + priceScaleId: '', +}); + +export const createCandlestickOptions = (theme: ChartTheme) => { + return { ...theme.candlestick }; +}; diff --git a/packages/frontend/src/utils/getHistogramColorData.ts b/packages/frontend/src/utils/getHistogramColorData.ts new file mode 100644 index 00000000..86524a45 --- /dev/null +++ b/packages/frontend/src/utils/getHistogramColorData.ts @@ -0,0 +1,21 @@ +import resolveConfig from 'tailwindcss/resolveConfig'; +import tailwindConfig from '@/../tailwind.config'; + +// TODO: api 나오면 객체/위치 수정 +interface VolumeData { + time: string; + value: number; +} + +const colorConfig = resolveConfig(tailwindConfig).theme.colors; + +export const getHistogramColorData = (data: VolumeData[]) => { + return data.map((item, index) => { + const color = + index === 0 || item.value >= data[index - 1].value + ? colorConfig.red + : colorConfig.blue; + + return { time: item.time, value: item.value, color }; + }); +}; diff --git a/packages/frontend/src/vite-env.d.ts b/packages/frontend/src/vite-env.d.ts index 11f02fe2..7bdee965 100644 --- a/packages/frontend/src/vite-env.d.ts +++ b/packages/frontend/src/vite-env.d.ts @@ -1 +1,2 @@ /// +/// diff --git a/packages/frontend/svg.d.ts b/packages/frontend/svg.d.ts new file mode 100644 index 00000000..ea669257 --- /dev/null +++ b/packages/frontend/svg.d.ts @@ -0,0 +1,4 @@ +declare module '*.svg' { + const content: React.FC>; + export default content; +} diff --git a/packages/frontend/tailwind.config.js b/packages/frontend/tailwind.config.js deleted file mode 100644 index d21f1cda..00000000 --- a/packages/frontend/tailwind.config.js +++ /dev/null @@ -1,8 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], - theme: { - extend: {}, - }, - plugins: [], -}; diff --git a/packages/frontend/tailwind.config.ts b/packages/frontend/tailwind.config.ts new file mode 100644 index 00000000..10590b9f --- /dev/null +++ b/packages/frontend/tailwind.config.ts @@ -0,0 +1,24 @@ +import type { Config } from 'tailwindcss' + +const config: Config = { + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], + theme: { + extend: {}, + colors: { + 'light-gray': '#d9d9d9', + gray: '#8c8c8c', + 'dark-gray': '#4f4f4f', + black: '#000000', + white: '#ffffff', + 'light-yellow': '#ffdcac', + 'light-orange': '#ffcfac', + orange: '#ffa868', + red: '#ff4d4d', + green: '#7eeb7e', + blue: '#1a75ff', + }, + }, + plugins: [], +} + +export default config \ No newline at end of file diff --git a/packages/frontend/tsconfig.app.json b/packages/frontend/tsconfig.app.json index b4b522c0..24c6800d 100644 --- a/packages/frontend/tsconfig.app.json +++ b/packages/frontend/tsconfig.app.json @@ -25,5 +25,5 @@ "composite": true }, - "include": ["src"] + "include": ["src", "src/**/*.json", "tailwind.config.ts"] } diff --git a/packages/frontend/tsconfig.node.json b/packages/frontend/tsconfig.node.json index abcd7f0d..522b48f8 100644 --- a/packages/frontend/tsconfig.node.json +++ b/packages/frontend/tsconfig.node.json @@ -5,6 +5,7 @@ "lib": ["ES2023"], "module": "ESNext", "skipLibCheck": true, + "types": ["vite-plugin-svgr/client"], /* Bundler mode */ "moduleResolution": "Bundler", @@ -20,5 +21,5 @@ "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true }, - "include": ["vite.config.ts"] + "include": ["vite.config.ts", "svg.d.ts"] } diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index 0e1b4b44..9fe89f8d 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -1,10 +1,11 @@ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; import path from 'path'; +import react from '@vitejs/plugin-react'; +import { defineConfig } from 'vite'; +import svgr from 'vite-plugin-svgr'; // https://vite.dev/config/ export default defineConfig({ - plugins: [react()], + plugins: [react(), svgr()], resolve: { alias: { '@': path.resolve(__dirname, './src'), diff --git a/test.js b/test.js new file mode 100644 index 00000000..ec521fac --- /dev/null +++ b/test.js @@ -0,0 +1,5 @@ +const getTodayDate = () => { + const today = new Date(); + return today.toISOString().split('T')[0].replace(/-/g, ''); +}; +console.log(getTodayDate()); diff --git a/yarn.lock b/yarn.lock index 557adde2..10d4e991 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adobe/css-tools@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.0.tgz#728c484f4e10df03d5a3acd0d8adcbbebff8ad63" + integrity sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ== + "@alloc/quick-lru@^5.2.0": version "5.2.0" resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" @@ -73,7 +78,7 @@ ora "5.4.1" rxjs "7.8.1" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0": version "7.26.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== @@ -87,7 +92,7 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.2.tgz#278b6b13664557de95b8f35b90d96785850bb56e" integrity sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg== -"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.25.2": +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.18.9", "@babel/core@^7.21.3", "@babel/core@^7.23.9", "@babel/core@^7.25.2": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40" integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== @@ -315,6 +320,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.25.9" +"@babel/runtime@^7.12.5", "@babel/runtime@^7.17.8": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" + integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.25.9", "@babel/template@^7.3.3": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" @@ -324,7 +336,7 @@ "@babel/parser" "^7.25.9" "@babel/types" "^7.25.9" -"@babel/traverse@^7.25.9": +"@babel/traverse@^7.18.9", "@babel/traverse@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84" integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw== @@ -337,7 +349,7 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.3.3": +"@babel/types@^7.0.0", "@babel/types@^7.18.9", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.3.3": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.0.tgz#deabd08d6b753bc8e0f198f8709fb575e31774ff" integrity sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA== @@ -350,6 +362,17 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@chromatic-com/storybook@3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@chromatic-com/storybook/-/storybook-3.2.2.tgz#08754443de55618f802f88450c35266fd6d25db5" + integrity sha512-xmXt/GW0hAPbzNTrxYuVo43Adrtjue4DeVrsoIIEeJdGaPNNeNf+DHMlJKOBdlHmCnFUoe9R/0mLM9zUp5bKWw== + dependencies: + chromatic "^11.15.0" + filesize "^10.0.12" + jsonfile "^6.1.0" + react-confetti "^6.1.0" + strip-ansi "^7.1.0" + "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" @@ -536,116 +559,236 @@ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== +"@esbuild/aix-ppc64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz#b57697945b50e99007b4c2521507dc613d4a648c" + integrity sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw== + "@esbuild/android-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== +"@esbuild/android-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz#1add7e0af67acefd556e407f8497e81fddad79c0" + integrity sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w== + "@esbuild/android-arm@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== +"@esbuild/android-arm@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.24.0.tgz#ab7263045fa8e090833a8e3c393b60d59a789810" + integrity sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew== + "@esbuild/android-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== +"@esbuild/android-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.24.0.tgz#e8f8b196cfdfdd5aeaebbdb0110983460440e705" + integrity sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ== + "@esbuild/darwin-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== +"@esbuild/darwin-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz#2d0d9414f2acbffd2d86e98253914fca603a53dd" + integrity sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw== + "@esbuild/darwin-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== +"@esbuild/darwin-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz#33087aab31a1eb64c89daf3d2cf8ce1775656107" + integrity sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA== + "@esbuild/freebsd-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== +"@esbuild/freebsd-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz#bb76e5ea9e97fa3c753472f19421075d3a33e8a7" + integrity sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA== + "@esbuild/freebsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== +"@esbuild/freebsd-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz#e0e2ce9249fdf6ee29e5dc3d420c7007fa579b93" + integrity sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ== + "@esbuild/linux-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== +"@esbuild/linux-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz#d1b2aa58085f73ecf45533c07c82d81235388e75" + integrity sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g== + "@esbuild/linux-arm@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== +"@esbuild/linux-arm@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz#8e4915df8ea3e12b690a057e77a47b1d5935ef6d" + integrity sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw== + "@esbuild/linux-ia32@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== +"@esbuild/linux-ia32@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz#8200b1110666c39ab316572324b7af63d82013fb" + integrity sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA== + "@esbuild/linux-loong64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== +"@esbuild/linux-loong64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz#6ff0c99cf647504df321d0640f0d32e557da745c" + integrity sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g== + "@esbuild/linux-mips64el@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== +"@esbuild/linux-mips64el@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz#3f720ccd4d59bfeb4c2ce276a46b77ad380fa1f3" + integrity sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA== + "@esbuild/linux-ppc64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== +"@esbuild/linux-ppc64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz#9d6b188b15c25afd2e213474bf5f31e42e3aa09e" + integrity sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ== + "@esbuild/linux-riscv64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== +"@esbuild/linux-riscv64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz#f989fdc9752dfda286c9cd87c46248e4dfecbc25" + integrity sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw== + "@esbuild/linux-s390x@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== +"@esbuild/linux-s390x@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz#29ebf87e4132ea659c1489fce63cd8509d1c7319" + integrity sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g== + "@esbuild/linux-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== +"@esbuild/linux-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz#4af48c5c0479569b1f359ffbce22d15f261c0cef" + integrity sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA== + "@esbuild/netbsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== +"@esbuild/netbsd-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz#1ae73d23cc044a0ebd4f198334416fb26c31366c" + integrity sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg== + +"@esbuild/openbsd-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz#5d904a4f5158c89859fd902c427f96d6a9e632e2" + integrity sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg== + "@esbuild/openbsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== +"@esbuild/openbsd-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz#4c8aa88c49187c601bae2971e71c6dc5e0ad1cdf" + integrity sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q== + "@esbuild/sunos-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== +"@esbuild/sunos-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz#8ddc35a0ea38575fa44eda30a5ee01ae2fa54dd4" + integrity sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA== + "@esbuild/win32-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== +"@esbuild/win32-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz#6e79c8543f282c4539db684a207ae0e174a9007b" + integrity sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA== + "@esbuild/win32-ia32@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== +"@esbuild/win32-ia32@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz#057af345da256b7192d18b676a02e95d0fa39103" + integrity sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw== + "@esbuild/win32-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== +"@esbuild/win32-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz#168ab1c7e1c318b922637fad8f339d48b01e1244" + integrity sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.1" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" @@ -986,6 +1129,16 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" +"@joshwooding/vite-plugin-react-docgen-typescript@0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.3.0.tgz#67599fca260c2eafdaf234a944f9d471e6d53b08" + integrity sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA== + dependencies: + glob "^7.2.0" + glob-promise "^4.2.0" + magic-string "^0.27.0" + react-docgen-typescript "^2.2.2" + "@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" @@ -1013,7 +1166,7 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15", "@jridgewell/sourcemap-codec@^1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== @@ -1051,6 +1204,13 @@ resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz#f29a55df17cb6e87cfbabce33ff6a14a9f85076d" integrity sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA== +"@mdx-js/react@^3.0.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-3.1.0.tgz#c4522e335b3897b9a845db1dbdd2f966ae8fb0ed" + integrity sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ== + dependencies: + "@types/mdx" "^2.0.0" + "@nestjs/cli@^10.0.0": version "10.4.5" resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-10.4.5.tgz#d6563b87e8ca1d0f256c19a7847dbcc96c76a88e" @@ -1135,6 +1295,14 @@ socket.io "4.8.0" tslib "2.7.0" +"@nestjs/schedule@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@nestjs/schedule/-/schedule-4.1.1.tgz#a730cff250ad5db78fe6a1bfc7f12a30856e48df" + integrity sha512-VxAnCiU4HP0wWw8IdWAVfsGC/FGjyToNjjUtXDEQL6oj+w/N5QDd2VT9k6d7Jbr8PlZuBZNdWtDKSkH5bZ+RXQ== + dependencies: + cron "3.1.7" + uuid "10.0.0" + "@nestjs/schematics@^10.0.0", "@nestjs/schematics@^10.0.1": version "10.2.3" resolved "https://registry.yarnpkg.com/@nestjs/schematics/-/schematics-10.2.3.tgz#6053f43c5065b9e825cd08c4db1bf6bcbc9a6a62" @@ -1221,6 +1389,20 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== +"@remix-run/router@1.21.0": + version "1.21.0" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.21.0.tgz#c65ae4262bdcfe415dbd4f64ec87676e4a56e2b5" + integrity sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA== + +"@rollup/pluginutils@^5.0.2", "@rollup/pluginutils@^5.1.3": + version "5.1.3" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.3.tgz#3001bf1a03f3ad24457591f2c259c8e514e0dbdf" + integrity sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^4.0.2" + "@rollup/rollup-android-arm-eabi@4.24.4": version "4.24.4" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.4.tgz#c460b54c50d42f27f8254c435a4f3b3e01910bc8" @@ -1350,6 +1532,333 @@ resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.5.tgz#3abc203c79b8c3e90fd6c156a0c62d5403520e12" integrity sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw== +"@storybook/addon-actions@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-8.4.3.tgz#1645b5bd5e11cab64debf4e113238a4b84212f64" + integrity sha512-3lPiMszzxi7YWouIiWSLELCQNFLY2ABmD7O1u2+i/0ZXZZeHqIrhdNoVCj9j0qMisAe9neYzDWLfyKX5yv226g== + dependencies: + "@storybook/global" "^5.0.0" + "@types/uuid" "^9.0.1" + dequal "^2.0.2" + polished "^4.2.2" + uuid "^9.0.0" + +"@storybook/addon-backgrounds@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-backgrounds/-/addon-backgrounds-8.4.3.tgz#3ab3dbf4314d1fe8b66e77bb9468d642413a6734" + integrity sha512-m3kTxtn+GgO1dj+qVUYV8LnYEVbeITUk+iXJlCBoYQptmWOmOry0KBSk3m/eWlWPeI42X6btwrLtXzMziC2RGA== + dependencies: + "@storybook/global" "^5.0.0" + memoizerific "^1.11.3" + ts-dedent "^2.0.0" + +"@storybook/addon-controls@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-controls/-/addon-controls-8.4.3.tgz#fd72beb60ba0c6de5db17038a05fe93e84263fd6" + integrity sha512-KPX1IxI60C0iLNYlkGVuRT+YKbSdbdy//pc2eDHWktxY0TnDymc3VWaSxNvIOpZK8N7ut1/UP/qb+sH/ckW7SA== + dependencies: + "@storybook/global" "^5.0.0" + dequal "^2.0.2" + ts-dedent "^2.0.0" + +"@storybook/addon-docs@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-8.4.3.tgz#6c2ffdb3a03cb015edf590e9a5beac8d381bdebb" + integrity sha512-3xSYtbg+pjZiQIzJJOKlSXgxxRvRSdQYMQbAZoJVizGpb2y5OpEKiAoP1wuOaYTD8t2wlBgpi/aEx7qHAWaDbA== + dependencies: + "@mdx-js/react" "^3.0.0" + "@storybook/blocks" "8.4.3" + "@storybook/csf-plugin" "8.4.3" + "@storybook/react-dom-shim" "8.4.3" + react "^16.8.0 || ^17.0.0 || ^18.0.0" + react-dom "^16.8.0 || ^17.0.0 || ^18.0.0" + ts-dedent "^2.0.0" + +"@storybook/addon-essentials@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-essentials/-/addon-essentials-8.4.3.tgz#1d5b283ef72492dc15a1985f4e98508a72a99f6a" + integrity sha512-5SOC8FUJHVhicbLlaD9D+BKa556Zc0XnsXgkFWgeXhNSXRcM1ZrhUFWxVYGMAyXBZ3lmeYHNo/mYxDBnD2fWPQ== + dependencies: + "@storybook/addon-actions" "8.4.3" + "@storybook/addon-backgrounds" "8.4.3" + "@storybook/addon-controls" "8.4.3" + "@storybook/addon-docs" "8.4.3" + "@storybook/addon-highlight" "8.4.3" + "@storybook/addon-measure" "8.4.3" + "@storybook/addon-outline" "8.4.3" + "@storybook/addon-toolbars" "8.4.3" + "@storybook/addon-viewport" "8.4.3" + ts-dedent "^2.0.0" + +"@storybook/addon-highlight@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-highlight/-/addon-highlight-8.4.3.tgz#8f5a74ee9aff68b9ded18506673da3c99259611f" + integrity sha512-MfBvokTJkbynHBceA2SgvFvS7Tpdv6FxzSZbeVtJHyYBqXrobj8llpo4n2IqAo/f3otcapN64wK82Jl4u8dYVg== + dependencies: + "@storybook/global" "^5.0.0" + +"@storybook/addon-interactions@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-interactions/-/addon-interactions-8.4.3.tgz#7e1dc73f81e53891e2e497b419692fb3a847cf09" + integrity sha512-PLc5qM5/CtVcSSVmoyS+dgJNvLN3Z99PwcbDb7y0a2/tSd+LGQ6pEB02OtHWyJepkzKulMV7k9SwpywD2XsToA== + dependencies: + "@storybook/global" "^5.0.0" + "@storybook/instrumenter" "8.4.3" + "@storybook/test" "8.4.3" + polished "^4.2.2" + ts-dedent "^2.2.0" + +"@storybook/addon-measure@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-measure/-/addon-measure-8.4.3.tgz#14e9024c77c00db4386fec3728f5afa3a826a8a2" + integrity sha512-R9m71P6LDNr7cUtDgWWPBRB/GQfv8hdDjWbD/HfqPkGi49RtBXf/zzFr7OrzgwaT9A73VEM74FGOhCZyHz5Qtg== + dependencies: + "@storybook/global" "^5.0.0" + tiny-invariant "^1.3.1" + +"@storybook/addon-onboarding@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-onboarding/-/addon-onboarding-8.4.3.tgz#e87b01cd4798e7fe12d329e8e0f3ea91ba7b6177" + integrity sha512-GR384uns/cb0nhjEab+woOrWDiZYJeq5RLEfHoLePvSm75cmZ785U9jxirUh8uX+/RxRok7b/TjGmd5EMxYhfg== + dependencies: + react-confetti "^6.1.0" + +"@storybook/addon-outline@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-outline/-/addon-outline-8.4.3.tgz#77c20fdab16327761c74a195e3c73f3e15dda319" + integrity sha512-9dMmh6uQrlJUlKvH+rxEvvo8BCYznRa/YxLoGtgNzh5EbbSR03IVqgfZPpE4ewZidsfCL3Jf3cPjwSuWs3dxLA== + dependencies: + "@storybook/global" "^5.0.0" + ts-dedent "^2.0.0" + +"@storybook/addon-toolbars@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-toolbars/-/addon-toolbars-8.4.3.tgz#13617fe0b6ab8d6c11338ac8a98a9cf96f0a1dce" + integrity sha512-lW7p7VPeUDIqS0RAXY4yRQ4LCQWGzGdw64moU20NpeVfedfDc4EeCisLD54sU/xA6kMnxoFNYsdHfpkHvJA/Cg== + +"@storybook/addon-viewport@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-viewport/-/addon-viewport-8.4.3.tgz#2231e6ee739be100f1922855219606cae404e4bb" + integrity sha512-KUstpUx++5cWXMXlz9jBhM6qDW9rwtKMvTyJV24TmhYIDmynset2ILRknIqLbVdBixop40+I67O3SF/ydU4E0w== + dependencies: + memoizerific "^1.11.3" + +"@storybook/blocks@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/blocks/-/blocks-8.4.3.tgz#03017dd47349b7014f5bc15d3451a95c4b4ddcc8" + integrity sha512-PPC+RXievuHKYlL+oO4ygllT59YzpESklNfeHUkeyuSo0nr04UwSrbfdsQlYJo3nRP0wNKyj/NkYDvzMJ5RlTg== + dependencies: + "@storybook/csf" "^0.1.11" + "@storybook/icons" "^1.2.12" + ts-dedent "^2.0.0" + +"@storybook/builder-vite@8.4.3", "@storybook/builder-vite@^8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/builder-vite/-/builder-vite-8.4.3.tgz#f0df25908272851113fcee3b234b3931b8eed6af" + integrity sha512-kLM2vPKOo/yAavYmQgt0qO8kU/vDYuHRq3/AH9g4AvU155u9NeY5u5p8V4KtEHIDxWNmIOD2C09nDkk7DA22sw== + dependencies: + "@storybook/csf-plugin" "8.4.3" + browser-assert "^1.2.1" + ts-dedent "^2.0.0" + +"@storybook/components@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/components/-/components-8.4.3.tgz#830f91317da80ffe6b9ab7321a90b3afe2602585" + integrity sha512-5+krpYrKC0aLUlkfhKLR78Yrai0S9AP7SR3jXMpyuWIny0fIKn+Ak2IQ721A6RGW+zP02GR6/wLHI+A7CDpcAg== + +"@storybook/core@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/core/-/core-8.4.3.tgz#218b68087c955d6ee6eaf1d454855e87da45087a" + integrity sha512-Ly4sR2gU2Xxu+O0qR4RJpq+Bs45Kv0JPlzdkoTDKQD8B2ozRAdvQLgBHjnBbUYw9jUPzC96uusqTJIBxIdBi7w== + dependencies: + "@storybook/csf" "^0.1.11" + better-opn "^3.0.2" + browser-assert "^1.2.1" + esbuild "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0" + esbuild-register "^3.5.0" + jsdoc-type-pratt-parser "^4.0.0" + process "^0.11.10" + recast "^0.23.5" + semver "^7.6.2" + util "^0.12.5" + ws "^8.2.3" + +"@storybook/csf-plugin@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/csf-plugin/-/csf-plugin-8.4.3.tgz#90355a4cb8958de82b459b7c1489424b8fefc9b5" + integrity sha512-lS3qJ1qBZk7ddu3O+1hmmp+eDsQ/pOTKuTCJY7Zaoyze97LnLtYRs3FbfPhievVWiIoPdnXtK+mcssR9N9AHMw== + dependencies: + unplugin "^1.3.1" + +"@storybook/csf@^0.1.11": + version "0.1.11" + resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.1.11.tgz#ad685a4fe564a47a6b73571c2e7c07b526f4f71b" + integrity sha512-dHYFQH3mA+EtnCkHXzicbLgsvzYjcDJ1JWsogbItZogkPHgSJM/Wr71uMkcvw8v9mmCyP4NpXJuu6bPoVsOnzg== + dependencies: + type-fest "^2.19.0" + +"@storybook/global@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@storybook/global/-/global-5.0.0.tgz#b793d34b94f572c1d7d9e0f44fac4e0dbc9572ed" + integrity sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ== + +"@storybook/icons@^1.2.12": + version "1.2.12" + resolved "https://registry.yarnpkg.com/@storybook/icons/-/icons-1.2.12.tgz#3e4c939113b67df7ab17b78f805dbb57f4acf0db" + integrity sha512-UxgyK5W3/UV4VrI3dl6ajGfHM4aOqMAkFLWe2KibeQudLf6NJpDrDMSHwZj+3iKC4jFU7dkKbbtH2h/al4sW3Q== + +"@storybook/instrumenter@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/instrumenter/-/instrumenter-8.4.3.tgz#1cf2200334efda87d5e876fcdef5241310a1ee28" + integrity sha512-jEMi3CFlyeMQv6V/WWPnL10Qgqn5j03pXXnfLylGcrvLnl1pa1A6sDWqeB6XR2L1HuW96XelkMecCvp5pYXAdQ== + dependencies: + "@storybook/global" "^5.0.0" + "@vitest/utils" "^2.1.1" + +"@storybook/manager-api@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/manager-api/-/manager-api-8.4.3.tgz#a2a3e2b2f8e6654bff6f732808c6a8e3d9c5c3d6" + integrity sha512-b09FHQLHrc3VGdodgV+EkA6V8VhpgadygDn9aVIXUULHXMQCfzzsSK9kiunFGVjH5r4BtdanucBXoBRFAi9D/g== + +"@storybook/preview-api@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-8.4.3.tgz#c48c524f4eee79d0ed2458d88a8d6ee2f6518530" + integrity sha512-SQPiGJ5iNk/RMZTfTQZe27MaZz16XfIgb1GTDWuaSrDBWVcelHRCZdh8Ps+9X5Mre6GeZ9wMQ56l+hQf/DO9Ug== + +"@storybook/react-dom-shim@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/react-dom-shim/-/react-dom-shim-8.4.3.tgz#8515c782df8d59e3381266bff5fddaf4b903190e" + integrity sha512-0zFfPJsDzqEMXk6CEHOIPRR8BcST/X4UbZDZmQBVrzOlmJWdyx1nFK7BT9bbJvb6N9v2Qy6yHL3b2wzZqkDezA== + +"@storybook/react-vite@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/react-vite/-/react-vite-8.4.3.tgz#de306c55114fa2edbdbffeb35b42a6cfd09edc62" + integrity sha512-5M6sZLmD0PogJnhuWNgXySJux/NbRinz7fznj+05to/t8uIgqx6UDu5tZO0LWnSw7K/NsHnvLLwhhzttM3X8zQ== + dependencies: + "@joshwooding/vite-plugin-react-docgen-typescript" "0.3.0" + "@rollup/pluginutils" "^5.0.2" + "@storybook/builder-vite" "8.4.3" + "@storybook/react" "8.4.3" + find-up "^5.0.0" + magic-string "^0.30.0" + react-docgen "^7.0.0" + resolve "^1.22.8" + tsconfig-paths "^4.2.0" + +"@storybook/react@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/react/-/react-8.4.3.tgz#29a77605344a12c99ea2bdfb7f4de04eac88e961" + integrity sha512-Dz7Kt81lGjS+b4LLOKyLK5Ifp9ZzfD0pwOM2r5QYuBcD5b1I4I6gpRoTfQI/dI6bk5WevVqeOZ2iigZAnaXNGw== + dependencies: + "@storybook/components" "8.4.3" + "@storybook/global" "^5.0.0" + "@storybook/manager-api" "8.4.3" + "@storybook/preview-api" "8.4.3" + "@storybook/react-dom-shim" "8.4.3" + "@storybook/theming" "8.4.3" + +"@storybook/test@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/test/-/test-8.4.3.tgz#c6a737d30f120448c79ec54da0f172b762306d3a" + integrity sha512-R4KMIZE4S7GyFE4AFD9FESv2Ws406lsg9GFrBaiJGrzOlRKe5yJ7w1MWOu76UclqRNlQHzaEOnOE6lEHVISsDQ== + dependencies: + "@storybook/csf" "^0.1.11" + "@storybook/global" "^5.0.0" + "@storybook/instrumenter" "8.4.3" + "@testing-library/dom" "10.4.0" + "@testing-library/jest-dom" "6.5.0" + "@testing-library/user-event" "14.5.2" + "@vitest/expect" "2.0.5" + "@vitest/spy" "2.0.5" + +"@storybook/theming@8.4.3": + version "8.4.3" + resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-8.4.3.tgz#c264898c7668457a729c238cc463d7600f2a5f03" + integrity sha512-ORQY2/C488ur5NkQYes6x+fO5rcyRMyh4uX3DlkNhCsA2CJ/Ik3WVGjprrDuLn+9S4+mtXfVUNfvN7xszlT1oA== + +"@svgr/babel-plugin-add-jsx-attribute@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz#4001f5d5dd87fa13303e36ee106e3ff3a7eb8b22" + integrity sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g== + +"@svgr/babel-plugin-remove-jsx-attribute@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz#69177f7937233caca3a1afb051906698f2f59186" + integrity sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA== + +"@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz#c2c48104cfd7dcd557f373b70a56e9e3bdae1d44" + integrity sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA== + +"@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz#8fbb6b2e91fa26ac5d4aa25c6b6e4f20f9c0ae27" + integrity sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ== + +"@svgr/babel-plugin-svg-dynamic-title@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz#1d5ba1d281363fc0f2f29a60d6d936f9bbc657b0" + integrity sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og== + +"@svgr/babel-plugin-svg-em-dimensions@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz#35e08df300ea8b1d41cb8f62309c241b0369e501" + integrity sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g== + +"@svgr/babel-plugin-transform-react-native-svg@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz#90a8b63998b688b284f255c6a5248abd5b28d754" + integrity sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q== + +"@svgr/babel-plugin-transform-svg-component@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz#013b4bfca88779711f0ed2739f3f7efcefcf4f7e" + integrity sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw== + +"@svgr/babel-preset@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-8.1.0.tgz#0e87119aecdf1c424840b9d4565b7137cabf9ece" + integrity sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug== + dependencies: + "@svgr/babel-plugin-add-jsx-attribute" "8.0.0" + "@svgr/babel-plugin-remove-jsx-attribute" "8.0.0" + "@svgr/babel-plugin-remove-jsx-empty-expression" "8.0.0" + "@svgr/babel-plugin-replace-jsx-attribute-value" "8.0.0" + "@svgr/babel-plugin-svg-dynamic-title" "8.0.0" + "@svgr/babel-plugin-svg-em-dimensions" "8.0.0" + "@svgr/babel-plugin-transform-react-native-svg" "8.1.0" + "@svgr/babel-plugin-transform-svg-component" "8.0.0" + +"@svgr/core@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/core/-/core-8.1.0.tgz#41146f9b40b1a10beaf5cc4f361a16a3c1885e88" + integrity sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA== + dependencies: + "@babel/core" "^7.21.3" + "@svgr/babel-preset" "8.1.0" + camelcase "^6.2.0" + cosmiconfig "^8.1.3" + snake-case "^3.0.4" + +"@svgr/hast-util-to-babel-ast@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz#6952fd9ce0f470e1aded293b792a2705faf4ffd4" + integrity sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q== + dependencies: + "@babel/types" "^7.21.3" + entities "^4.4.0" + +"@svgr/plugin-jsx@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz#96969f04a24b58b174ee4cd974c60475acbd6928" + integrity sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA== + dependencies: + "@babel/core" "^7.21.3" + "@svgr/babel-preset" "8.1.0" + "@svgr/hast-util-to-babel-ast" "8.0.0" + svg-parser "^2.0.4" + "@tanstack/query-core@5.59.17": version "5.59.17" resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.59.17.tgz#bda3bb678be48e2f6ee692abd1cfc2db3d455e4b" @@ -1362,6 +1871,38 @@ dependencies: "@tanstack/query-core" "5.59.17" +"@testing-library/dom@10.4.0": + version "10.4.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.4.0.tgz#82a9d9462f11d240ecadbf406607c6ceeeff43a8" + integrity sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^5.0.1" + aria-query "5.3.0" + chalk "^4.1.0" + dom-accessibility-api "^0.5.9" + lz-string "^1.5.0" + pretty-format "^27.0.2" + +"@testing-library/jest-dom@6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.5.0.tgz#50484da3f80fb222a853479f618a9ce5c47bfe54" + integrity sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA== + dependencies: + "@adobe/css-tools" "^4.4.0" + aria-query "^5.0.0" + chalk "^3.0.0" + css.escape "^1.5.1" + dom-accessibility-api "^0.6.3" + lodash "^4.17.21" + redent "^3.0.0" + +"@testing-library/user-event@14.5.2": + version "14.5.2" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.2.tgz#db7257d727c891905947bd1c1a99da20e03c2ebd" + integrity sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ== + "@tsconfig/node10@^1.0.7": version "1.0.11" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" @@ -1382,7 +1923,12 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@types/babel__core@^7.1.14", "@types/babel__core@^7.20.5": +"@types/aria-query@^5.0.1": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" + integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw== + +"@types/babel__core@^7.1.14", "@types/babel__core@^7.18.0", "@types/babel__core@^7.20.5": version "7.20.5" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== @@ -1408,7 +1954,7 @@ "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6", "@types/babel__traverse@^7.18.0": version "7.20.6" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== @@ -1455,6 +2001,12 @@ "@types/node" "*" "@types/estree@1.0.6", "@types/estree@^1.0.5", "@types/estree@^1.0.6": +"@types/doctrine@^0.0.9": + version "0.0.9" + resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.9.tgz#d86a5f452a15e3e3113b99e39616a9baa0f9863f" + integrity sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA== + +"@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.5", "@types/estree@^1.0.6": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== @@ -1486,6 +2038,14 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/glob@^7.1.3": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + "@types/graceful-fs@^4.1.3": version "4.1.9" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" @@ -1535,6 +2095,16 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/luxon@~3.4.0": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.4.2.tgz#e4fc7214a420173cea47739c33cdf10874694db7" + integrity sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA== + +"@types/mdx@^2.0.0": + version "2.0.13" + resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.13.tgz#68f6877043d377092890ff5b298152b0a21671bd" + integrity sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw== + "@types/methods@^1.1.4": version "1.1.4" resolved "https://registry.yarnpkg.com/@types/methods/-/methods-1.1.4.tgz#d3b7ac30ac47c91054ea951ce9eed07b1051e547" @@ -1545,6 +2115,11 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== +"@types/minimatch@*": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + "@types/node@*", "@types/node@^22.8.7": version "22.8.7" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.8.7.tgz#04ab7a073d95b4a6ee899f235d43f3c320a976f4" @@ -1628,6 +2203,11 @@ "@types/prop-types" "*" csstype "^3.0.2" +"@types/resolve@^1.20.2": + version "1.20.6" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.6.tgz#e6e60dad29c2c8c206c026e6dd8d6d1bdda850b8" + integrity sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ== + "@types/send@*": version "0.17.4" resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" @@ -1685,6 +2265,11 @@ resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.12.2.tgz#760329e756e18a4aab82fc502b51ebdfebbe49f5" integrity sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA== +"@types/uuid@^9.0.1": + version "9.0.8" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" + integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== + "@types/yargs-parser@*": version "21.0.3" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" @@ -1731,6 +2316,14 @@ "@typescript-eslint/types" "8.12.2" "@typescript-eslint/visitor-keys" "8.12.2" +"@typescript-eslint/scope-manager@8.14.0": + version "8.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.14.0.tgz#01f37c147a735cd78f0ff355e033b9457da1f373" + integrity sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw== + dependencies: + "@typescript-eslint/types" "8.14.0" + "@typescript-eslint/visitor-keys" "8.14.0" + "@typescript-eslint/type-utils@8.12.2": version "8.12.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz#132b0c52d45f6814e6f2e32416c7951ed480b016" @@ -1746,6 +2339,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.12.2.tgz#8d70098c0e90442495b53d0296acdca6d0f3f73c" integrity sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA== +"@typescript-eslint/types@8.14.0": + version "8.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.14.0.tgz#0d33d8d0b08479c424e7d654855fddf2c71e4021" + integrity sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g== + "@typescript-eslint/typescript-estree@8.12.2": version "8.12.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz#206df9b1cbff212aaa9401985ef99f04daa84da5" @@ -1760,6 +2358,20 @@ semver "^7.6.0" ts-api-utils "^1.3.0" +"@typescript-eslint/typescript-estree@8.14.0": + version "8.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.14.0.tgz#a7a3a5a53a6c09313e12fb4531d4ff582ee3c312" + integrity sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ== + dependencies: + "@typescript-eslint/types" "8.14.0" + "@typescript-eslint/visitor-keys" "8.14.0" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + "@typescript-eslint/utils@8.12.2": version "8.12.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.12.2.tgz#726cc9f49f5866605bd15bbc1768ffc15637930e" @@ -1770,6 +2382,16 @@ "@typescript-eslint/types" "8.12.2" "@typescript-eslint/typescript-estree" "8.12.2" +"@typescript-eslint/utils@^8.8.1": + version "8.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.14.0.tgz#ac2506875e03aba24e602364e43b2dfa45529dbd" + integrity sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.14.0" + "@typescript-eslint/types" "8.14.0" + "@typescript-eslint/typescript-estree" "8.14.0" + "@typescript-eslint/visitor-keys@8.12.2": version "8.12.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz#94d7410f78eb6d134b9fcabaf1eeedb910ba8c38" @@ -1778,6 +2400,14 @@ "@typescript-eslint/types" "8.12.2" eslint-visitor-keys "^3.4.3" +"@typescript-eslint/visitor-keys@8.14.0": + version "8.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.14.0.tgz#2418d5a54669af9658986ade4e6cfb7767d815ad" + integrity sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ== + dependencies: + "@typescript-eslint/types" "8.14.0" + eslint-visitor-keys "^3.4.3" + "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" @@ -1794,6 +2424,56 @@ "@types/babel__core" "^7.20.5" react-refresh "^0.14.2" +"@vitest/expect@2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-2.0.5.tgz#f3745a6a2c18acbea4d39f5935e913f40d26fa86" + integrity sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA== + dependencies: + "@vitest/spy" "2.0.5" + "@vitest/utils" "2.0.5" + chai "^5.1.1" + tinyrainbow "^1.2.0" + +"@vitest/pretty-format@2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-2.0.5.tgz#91d2e6d3a7235c742e1a6cc50e7786e2f2979b1e" + integrity sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ== + dependencies: + tinyrainbow "^1.2.0" + +"@vitest/pretty-format@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-2.1.5.tgz#bc79b8826d4a63dc04f2a75d2944694039fa50aa" + integrity sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw== + dependencies: + tinyrainbow "^1.2.0" + +"@vitest/spy@2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-2.0.5.tgz#590fc07df84a78b8e9dd976ec2090920084a2b9f" + integrity sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA== + dependencies: + tinyspy "^3.0.0" + +"@vitest/utils@2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.0.5.tgz#6f8307a4b6bc6ceb9270007f73c67c915944e926" + integrity sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ== + dependencies: + "@vitest/pretty-format" "2.0.5" + estree-walker "^3.0.3" + loupe "^3.1.1" + tinyrainbow "^1.2.0" + +"@vitest/utils@^2.1.1": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.1.5.tgz#0e19ce677c870830a1573d33ee86b0d6109e9546" + integrity sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg== + dependencies: + "@vitest/pretty-format" "2.1.5" + loupe "^3.1.2" + tinyrainbow "^1.2.0" + "@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": version "1.12.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" @@ -2111,6 +2791,18 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +aria-query@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" + integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== + dependencies: + dequal "^2.0.3" + +aria-query@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" + integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== + array-buffer-byte-length@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" @@ -2197,6 +2889,18 @@ asap@^2.0.0: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== + +ast-types@^0.16.1: + version "0.16.1" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.16.1.tgz#7a9da1617c9081bc121faafe91711b4c8bb81da2" + integrity sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg== + dependencies: + tslib "^2.0.1" + async@^3.2.3: version "3.2.6" resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" @@ -2318,6 +3022,13 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +better-opn@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/better-opn/-/better-opn-3.0.2.tgz#f96f35deaaf8f34144a4102651babcf00d1d8817" + integrity sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ== + dependencies: + open "^8.0.4" + base64id@2.0.0, base64id@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" @@ -2387,6 +3098,11 @@ braces@^3.0.3, braces@~3.0.2: dependencies: fill-range "^7.1.1" +browser-assert@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/browser-assert/-/browser-assert-1.2.1.tgz#9aaa5a2a8c74685c2ae05bfe46efd606f068c200" + integrity sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ== + browserslist@^4.21.10, browserslist@^4.23.3, browserslist@^4.24.0: version "4.24.2" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580" @@ -2485,6 +3201,17 @@ caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001669: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz#27c2e2c637e007cfa864a16f7dfe7cde66b38b5f" integrity sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog== +chai@^5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.1.2.tgz#3afbc340b994ae3610ca519a6c70ace77ad4378d" + integrity sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw== + dependencies: + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" + chalk@4.1.2, chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -2502,6 +3229,14 @@ chalk@^2.4.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" @@ -2517,6 +3252,11 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +check-error@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" + integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== + chokidar@3.6.0, chokidar@^3.5.3: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" @@ -2532,6 +3272,11 @@ chokidar@3.6.0, chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chromatic@^11.15.0: + version "11.18.1" + resolved "https://registry.yarnpkg.com/chromatic/-/chromatic-11.18.1.tgz#c8f7b330dbd9be3b45a84abcb924f5217dc6c326" + integrity sha512-hkNT9vA6K9+PnE/khhZYBnRCOm8NonaQDs7RZ8YHFo7/lh1b/x/uFMkTjWjaj/mkM6QOR/evu5VcZMtcaauSlw== + chrome-trace-event@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" @@ -2561,6 +3306,13 @@ class-validator@^0.14.1: libphonenumber-js "^1.10.53" validator "^13.9.0" +class-variance-authority@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/class-variance-authority/-/class-variance-authority-0.7.0.tgz#1c3134d634d80271b1837452b06d821915954522" + integrity sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A== + dependencies: + clsx "2.0.0" + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -2639,6 +3391,16 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== +clsx@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.0.0.tgz#12658f3fd98fafe62075595a5c30e43d18f3d00b" + integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q== + +clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -2869,7 +3631,7 @@ cosmiconfig-typescript-loader@^5.0.0: dependencies: jiti "^1.21.6" -cosmiconfig@^8.2.0: +cosmiconfig@^8.1.3, cosmiconfig@^8.2.0: version "8.3.6" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== @@ -2907,6 +3669,14 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cron@3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/cron/-/cron-3.1.7.tgz#3423d618ba625e78458fff8cb67001672d49ba0d" + integrity sha512-tlBg7ARsAMQLzgwqVxy8AZl/qlTc5nibqYwtNGoCrd+cV+ugI+tvZC1oT/8dFH8W455YrywGykx/KMmAqOr7Jw== + dependencies: + "@types/luxon" "~3.4.0" + luxon "~3.4.0" + cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -2916,6 +3686,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +css.escape@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -3029,6 +3804,11 @@ dedent@^1.0.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== + deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" @@ -3055,6 +3835,11 @@ define-data-property@^1.0.1, define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.2.0, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" @@ -3079,6 +3864,11 @@ depd@2.0.0, depd@~2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +dequal@^2.0.2, dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" @@ -3141,6 +3931,24 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-accessibility-api@^0.5.9: + version "0.5.16" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" + integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg== + +dom-accessibility-api@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz#993e925cc1d73f2c662e7d75dd5a5445259a8fd8" + integrity sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w== + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + dot-prop@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -3251,6 +4059,11 @@ enhanced-resolve@^5.0.0, enhanced-resolve@^5.17.1, enhanced-resolve@^5.7.0: graceful-fs "^4.2.4" tapable "^2.2.0" +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + env-paths@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" @@ -3364,6 +4177,43 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +esbuild-register@^3.5.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/esbuild-register/-/esbuild-register-3.6.0.tgz#cf270cfa677baebbc0010ac024b823cbf723a36d" + integrity sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg== + dependencies: + debug "^4.3.4" + +"esbuild@^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.24.0.tgz#f2d470596885fcb2e91c21eb3da3b3c89c0b55e7" + integrity sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ== + optionalDependencies: + "@esbuild/aix-ppc64" "0.24.0" + "@esbuild/android-arm" "0.24.0" + "@esbuild/android-arm64" "0.24.0" + "@esbuild/android-x64" "0.24.0" + "@esbuild/darwin-arm64" "0.24.0" + "@esbuild/darwin-x64" "0.24.0" + "@esbuild/freebsd-arm64" "0.24.0" + "@esbuild/freebsd-x64" "0.24.0" + "@esbuild/linux-arm" "0.24.0" + "@esbuild/linux-arm64" "0.24.0" + "@esbuild/linux-ia32" "0.24.0" + "@esbuild/linux-loong64" "0.24.0" + "@esbuild/linux-mips64el" "0.24.0" + "@esbuild/linux-ppc64" "0.24.0" + "@esbuild/linux-riscv64" "0.24.0" + "@esbuild/linux-s390x" "0.24.0" + "@esbuild/linux-x64" "0.24.0" + "@esbuild/netbsd-x64" "0.24.0" + "@esbuild/openbsd-arm64" "0.24.0" + "@esbuild/openbsd-x64" "0.24.0" + "@esbuild/sunos-x64" "0.24.0" + "@esbuild/win32-arm64" "0.24.0" + "@esbuild/win32-ia32" "0.24.0" + "@esbuild/win32-x64" "0.24.0" + esbuild@^0.21.3: version "0.21.5" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" @@ -3482,6 +4332,15 @@ eslint-plugin-react-refresh@^0.4.14: resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.14.tgz#e3c611ead69bbf7436d01295c853d4abb8c59f68" integrity sha512-aXvzCTK7ZBv1e7fahFuR3Z/fyQQSIQ711yPgYRj+Oj64tyTgO4iQIDmYXDBqvSWQ/FA4OSCsXOStlF+noU0/NA== +eslint-plugin-storybook@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-storybook/-/eslint-plugin-storybook-0.11.0.tgz#97adc63512816a6f8b86040d1364af43d3336099" + integrity sha512-MvPJgF+ORwgK04a1CY5itO4pwdAOFIRqczlNEHL62+4Ocvj1d61GWRqIdeX1BNCKno6fdPC6TksUHCZMGsq26g== + dependencies: + "@storybook/csf" "^0.1.11" + "@typescript-eslint/utils" "^8.8.1" + ts-dedent "^2.2.0" + eslint-scope@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -3619,7 +4478,7 @@ espree@^9.6.0, espree@^9.6.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" -esprima@^4.0.0, esprima@^4.0.1: +esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -3648,6 +4507,18 @@ estraverse@^5.1.0, estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -3761,6 +4632,11 @@ external-editor@^3.0.3, external-editor@^3.1.0: iconv-lite "^0.4.24" tmp "^0.0.33" +fancy-canvas@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fancy-canvas/-/fancy-canvas-2.1.0.tgz#44b40e40419ad8ef8304df365e4276767e918552" + integrity sha512-nifxXJ95JNLFR2NgRV4/MxVP45G9909wJTEKz5fg/TZS20JJZA6hfgRVh/bC9bwl2zBtBNcYPjiBE4njQHVBwQ== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -3863,6 +4739,11 @@ filelist@^1.0.4: dependencies: minimatch "^5.0.1" +filesize@^10.0.12: + version "10.1.6" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-10.1.6.tgz#31194da825ac58689c0bce3948f33ce83aabd361" + integrity sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w== + fill-range@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" @@ -4169,6 +5050,13 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" +glob-promise@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/glob-promise/-/glob-promise-4.2.2.tgz#15f44bcba0e14219cd93af36da6bb905ff007877" + integrity sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw== + dependencies: + "@types/glob" "^7.1.3" + glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" @@ -4186,7 +5074,7 @@ glob@10.4.2: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@7.2.3, glob@^7.1.3, glob@^7.1.4: +glob@7.2.3, glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -4428,6 +5316,11 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -4547,6 +5440,14 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-array-buffer@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" @@ -4613,6 +5514,11 @@ is-date-object@^1.0.1: dependencies: has-tostringtag "^1.0.0" +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -4633,6 +5539,13 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== +is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -4718,7 +5631,7 @@ is-text-path@^2.0.0: dependencies: text-extensions "^2.0.0" -is-typed-array@^1.1.13: +is-typed-array@^1.1.13, is-typed-array@^1.1.3: version "1.1.13" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== @@ -4747,6 +5660,13 @@ is-windows@^1.0.1: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" @@ -5231,6 +6151,18 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsdoc-type-pratt-parser@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz#ff6b4a3f339c34a6c188cbf50a16087858d22113" + integrity sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg== + jsesc@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" @@ -5283,7 +6215,7 @@ jsonc-parser@3.3.1: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.3.1.tgz#f2a524b4f7fd11e3d791e559977ad60b98b798b4" integrity sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ== -jsonfile@^6.0.1: +jsonfile@^6.0.1, jsonfile@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== @@ -5332,6 +6264,13 @@ libphonenumber-js@^1.10.53: resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.14.tgz#d753524fd30e6433834a1464baf7efed4a06b593" integrity sha512-sexvAfwcW1Lqws4zFp8heAtAEXbEDnvkYCEGzvOoMgZR7JhXo/IkE9MkkGACgBed5fWqh3ShBGnJBdDnU9N8EQ== +lightweight-charts@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lightweight-charts/-/lightweight-charts-4.2.1.tgz#a2d97048c026644507faae679e00bf3088c9c247" + integrity sha512-nE2zCZ5Gp7KZbVHUJi6QhQLkYRvYyxsQTnSLEXIFmc8iHOFBT4rk/Dbyecq+CLW59FNuoCPNOYjZnS63/uHDrA== + dependencies: + fancy-canvas "2.1.0" + lilconfig@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" @@ -5470,6 +6409,18 @@ loose-envify@^1.1.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +loupe@^3.1.0, loupe@^3.1.1, loupe@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.2.tgz#c86e0696804a02218f2206124c45d8b15291a240" + integrity sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg== + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + lru-cache@^10.2.0: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" @@ -5492,6 +6443,16 @@ lru.min@^1.0.0: resolved "https://registry.yarnpkg.com/lru.min/-/lru.min-1.1.1.tgz#146e01e3a183fa7ba51049175de04667d5701f0e" integrity sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q== +luxon@~3.4.0: + version "3.4.4" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.4.4.tgz#cf20dc27dc532ba41a169c43fdcc0063601577af" + integrity sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA== + +lz-string@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" + integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== + magic-string@0.30.8: version "0.30.8" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.8.tgz#14e8624246d2bedba70d5462aa99ac9681844613" @@ -5499,6 +6460,20 @@ magic-string@0.30.8: dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" +magic-string@^0.27.0: + version "0.27.0" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3" + integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.13" + +magic-string@^0.30.0: + version "0.30.12" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.12.tgz#9eb11c9d072b9bcb4940a5b2c2e1a217e4ee1a60" + integrity sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + make-dir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" @@ -5518,6 +6493,11 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +map-or-similar@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/map-or-similar/-/map-or-similar-1.5.0.tgz#6de2653174adfb5d9edc33c69d3e92a1b76faf08" + integrity sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -5530,6 +6510,13 @@ memfs@^3.4.1: dependencies: fs-monkey "^1.0.4" +memoizerific@^1.11.3: + version "1.11.3" + resolved "https://registry.yarnpkg.com/memoizerific/-/memoizerific-1.11.3.tgz#7c87a4646444c32d75438570905f2dbd1b1a805a" + integrity sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog== + dependencies: + map-or-similar "^1.5.0" + meow@^12.0.1: version "12.1.1" resolved "https://registry.yarnpkg.com/meow/-/meow-12.1.1.tgz#e558dddbab12477b69b2e9a2728c327f191bace6" @@ -5600,6 +6587,11 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +min-indent@^1.0.0, min-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -5742,6 +6734,14 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + nest-winston@^1.9.7: version "1.9.7" resolved "https://registry.yarnpkg.com/nest-winston/-/nest-winston-1.9.7.tgz#1ef6eb2459ce595655de37d5beb900d2e75b61d3" @@ -5898,6 +6898,15 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +open@^8.0.4: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -6111,6 +7120,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pathval@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" + integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== + pause@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" @@ -6131,6 +7145,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -6153,6 +7172,13 @@ pluralize@8.0.0: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== +polished@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/polished/-/polished-4.3.1.tgz#5a00ae32715609f83d89f6f31d0f0261c6170548" + integrity sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA== + dependencies: + "@babel/runtime" "^7.17.8" + possible-typed-array-names@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" @@ -6223,11 +7249,25 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" +prettier-plugin-tailwindcss@^0.6.8: + version "0.6.8" + resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.8.tgz#8a178e1679e3f941cc9de396f109c6cffea676d8" + integrity sha512-dGu3kdm7SXPkiW4nzeWKCl3uoImdd5CTZEJGxyypEPL37Wj0HT2pLqjrvSei1nTeuQfO4PUfjeW5cTUNRLZ4sA== + prettier@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== +pretty-format@^27.0.2: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" @@ -6242,6 +7282,11 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -6312,7 +7357,35 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -react-dom@^18.3.1: +react-confetti@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/react-confetti/-/react-confetti-6.1.0.tgz#03dc4340d955acd10b174dbf301f374a06e29ce6" + integrity sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw== + dependencies: + tween-functions "^1.2.0" + +react-docgen-typescript@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz#4611055e569edc071204aadb20e1c93e1ab1659c" + integrity sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg== + +react-docgen@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-7.1.0.tgz#4b41e557dab939a5157be09ee532fd09c07d99fc" + integrity sha512-APPU8HB2uZnpl6Vt/+0AFoVYgSRtfiP6FLrZgPPTDmqSb2R4qZRbgd0A3VzIFxDt5e+Fozjx79WjLWnF69DK8g== + dependencies: + "@babel/core" "^7.18.9" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + "@types/babel__core" "^7.18.0" + "@types/babel__traverse" "^7.18.0" + "@types/doctrine" "^0.0.9" + "@types/resolve" "^1.20.2" + doctrine "^3.0.0" + resolve "^1.22.1" + strip-indent "^4.0.0" + +"react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", react-dom@^18.3.1: version "18.3.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== @@ -6320,6 +7393,11 @@ react-dom@^18.3.1: loose-envify "^1.1.0" scheduler "^0.23.2" +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + react-is@^18.0.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" @@ -6330,7 +7408,22 @@ react-refresh@^0.14.2: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== -react@^18.3.1: +react-router-dom@^6.28.0: + version "6.28.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.28.0.tgz#f73ebb3490e59ac9f299377062ad1d10a9f579e6" + integrity sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg== + dependencies: + "@remix-run/router" "1.21.0" + react-router "6.28.0" + +react-router@6.28.0: + version "6.28.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.28.0.tgz#29247c86d7ba901d7e5a13aa79a96723c3e59d0d" + integrity sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg== + dependencies: + "@remix-run/router" "1.21.0" + +"react@^16.8.0 || ^17.0.0 || ^18.0.0", react@^18.3.1: version "18.3.1" resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== @@ -6373,11 +7466,36 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +recast@^0.23.5: + version "0.23.9" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.9.tgz#587c5d3a77c2cfcb0c18ccce6da4361528c2587b" + integrity sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q== + dependencies: + ast-types "^0.16.1" + esprima "~4.0.0" + source-map "~0.6.1" + tiny-invariant "^1.3.3" + tslib "^2.0.1" + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + +reflect-metadata@^0.2.0: reflect-metadata@^0.2.0, reflect-metadata@^0.2.1: version "0.2.2" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + regexp.prototype.flags@^1.5.2: version "1.5.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42" @@ -6433,7 +7551,7 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.1.7, resolve@^1.20.0, resolve@^1.22.2, resolve@^1.22.4: +resolve@^1.1.7, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22.2, resolve@^1.22.4, resolve@^1.22.8: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -6595,7 +7713,7 @@ semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.4, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3: +semver@^7.3.4, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2, semver@^7.6.3: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== @@ -6725,6 +7843,14 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + socket.io-adapter@~2.5.2: version "2.5.5" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz#c7a1f9c703d7756844751b6ff9abfc1780664082" @@ -6793,7 +7919,7 @@ source-map@0.7.4, source-map@^0.7.4: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== -source-map@^0.6.0, source-map@^0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -6830,6 +7956,13 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +storybook@8.4.3: + version "8.4.3" + resolved "https://registry.yarnpkg.com/storybook/-/storybook-8.4.3.tgz#2e281f54aa54f082aee7ed9c00c7b6504f247791" + integrity sha512-n+6ME+APinsx0zjNTmx3SntJ4iCgoTK7TsxUC8+op/rUAA8hNbD+/NT7Qx/F5peHNchVeVFGtebPDAHU9g1M/Q== + dependencies: + "@storybook/core" "8.4.3" + streamsearch@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" @@ -6948,7 +8081,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.0.1: +strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== @@ -6970,6 +8103,20 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-4.0.0.tgz#b41379433dd06f5eae805e21d631e07ee670d853" + integrity sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA== + dependencies: + min-indent "^1.0.1" + strip-json-comments@3.1.1, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -7037,6 +8184,11 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +svg-parser@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" + integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== + swagger-ui-dist@5.18.2: version "5.18.2" resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz#62013074374d272c04ed3030704b88db5aa8c0b7" @@ -7057,6 +8209,11 @@ synckit@^0.9.1: "@pkgr/core" "^0.1.0" tslib "^2.6.2" +tailwind-merge@^2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-2.5.4.tgz#4bf574e81fa061adeceba099ae4df56edcee78d1" + integrity sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q== + tailwindcss@^3.4.14: version "3.4.14" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.14.tgz#6dd23a7f54ec197b19159e91e3bb1e55e7aa73ac" @@ -7162,11 +8319,26 @@ thenify-all@^1.0.0: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +tiny-invariant@^1.3.1, tiny-invariant@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" + integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== + tinyexec@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.1.tgz#0ab0daf93b43e2c211212396bdb836b468c97c98" integrity sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ== +tinyrainbow@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-1.2.0.tgz#5c57d2fc0fb3d1afd78465c33ca885d04f02abb5" + integrity sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ== + +tinyspy@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" + integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -7211,6 +8383,11 @@ ts-api-utils@^1.3.0: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.0.tgz#709c6f2076e511a81557f3d07a0cbd566ae8195c" integrity sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ== +ts-dedent@^2.0.0, ts-dedent@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" + integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== + ts-interface-checker@^0.1.9: version "0.1.13" resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" @@ -7299,11 +8476,16 @@ tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0, tslib@^2.5.0, tslib@^2.6.2: +tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.5.0, tslib@^2.6.2: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== +tween-functions@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tween-functions/-/tween-functions-1.2.0.tgz#1ae3a50e7c60bb3def774eac707acbca73bbc3ff" + integrity sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -7326,6 +8508,11 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== +type-fest@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + type-is@^1.6.4, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -7472,6 +8659,14 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== +unplugin@^1.3.1: + version "1.15.0" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.15.0.tgz#cd1e92e537ab14a03354d6f83f29d536fac2e5a9" + integrity sha512-jTPIs63W+DUEDW207ztbaoO7cQ4p5aVaB823LSlxpsFEU3Mykwxf3ZGC/wzxFJeZlASZYgVrWeo7LgOrqJZ8RA== + dependencies: + acorn "^8.14.0" + webpack-virtual-modules "^0.6.2" + unzipper@^0.12.3: version "0.12.3" resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.12.3.tgz#31958f5eed7368ed8f57deae547e5a673e984f87" @@ -7511,10 +8706,32 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== utils-merge@1.0.1, utils-merge@1.x.x, utils-merge@^1.0.1: +util@^0.12.5: + version "0.12.5" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + +utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uuid@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +uuid@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + uuid@9.0.1, uuid@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" @@ -7544,6 +8761,15 @@ vary@^1, vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +vite-plugin-svgr@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/vite-plugin-svgr/-/vite-plugin-svgr-4.3.0.tgz#742f16f11375996306c696ec323e4d23f6005075" + integrity sha512-Jy9qLB2/PyWklpYy0xk0UU3TlU0t2UMpJXZvf+hWII1lAmRHrOUKi11Uw8N3rxoNk7atZNYO3pR3vI1f7oi+6w== + dependencies: + "@rollup/pluginutils" "^5.1.3" + "@svgr/core" "^8.1.0" + "@svgr/plugin-jsx" "^8.1.0" + vite@^5.4.10: version "5.4.10" resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.10.tgz#d358a7bd8beda6cf0f3b7a450a8c7693a4f80c18" @@ -7592,6 +8818,11 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== +webpack-virtual-modules@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8" + integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ== + webpack@5.94.0: version "5.94.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f" @@ -7640,7 +8871,7 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.14, which-typed-array@^1.1.15: +which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2: version "1.1.15" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== @@ -7755,6 +8986,11 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" +ws@^8.2.3: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + ws@~8.17.1: version "8.17.1" resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"