From 426d344a5831c75d9de1809bb6dcfa44be74e8d0 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 18 Aug 2025 11:39:16 +0900 Subject: [PATCH 01/91] =?UTF-8?q?#15=20feat:=20svg=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/svg/binIcon.svg | 5 +++++ src/assets/svg/AddIcon.tsx | 3 +-- src/assets/svg/BinIcon.tsx | 23 +++++++++++++++++++++++ src/assets/svg/index.ts | 1 + 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 public/svg/binIcon.svg create mode 100644 src/assets/svg/BinIcon.tsx diff --git a/public/svg/binIcon.svg b/public/svg/binIcon.svg new file mode 100644 index 0000000..f5af42c --- /dev/null +++ b/public/svg/binIcon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/svg/AddIcon.tsx b/src/assets/svg/AddIcon.tsx index 71637e0..4c23a74 100644 --- a/src/assets/svg/AddIcon.tsx +++ b/src/assets/svg/AddIcon.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import type {SVGProps} from 'react'; const SvgAddIcon = (props: SVGProps) => ( ) => ( viewBox='0 0 14 15' {...props}> ) => ( + + + + + +); +export default SvgBinIcon; diff --git a/src/assets/svg/index.ts b/src/assets/svg/index.ts index 910de97..9717a54 100644 --- a/src/assets/svg/index.ts +++ b/src/assets/svg/index.ts @@ -2,6 +2,7 @@ export {default as AddIcon} from './AddIcon'; export {default as ArrowdownIcon} from './ArrowdownIcon'; export {default as ArrowleftIcon} from './ArrowleftIcon'; export {default as ArrowrightIcon} from './ArrowrightIcon'; +export {default as BinIcon} from './BinIcon'; export {default as ChatIcon} from './ChatIcon'; export {default as DeleteIcon} from './DeleteIcon'; export {default as DragAndDropIcon} from './DragAndDropIcon'; From e9bcab8f774eb6b90fcd0995957762db7af8024e Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 18 Aug 2025 11:52:22 +0900 Subject: [PATCH 02/91] =?UTF-8?q?#15=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=9D=BC?= =?UTF-8?q?=EC=9A=B0=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/App.tsx b/src/App.tsx index a7039c3..8bf70f4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,6 +5,7 @@ import UserIdInputPage from './pages/common/UserIdInputPage'; import Dashboard from './pages/common/Dashboard'; import AssignmentsPage from './pages/admin/AssignmentsPage'; import AssignmentSelectPage from './pages/admin/AssignmentSelectPage'; +import UnitPage from './pages/admin/UnitPage'; function App() { return ( @@ -28,6 +29,7 @@ function App() { } /> } /> } /> + } /> From 8f072b90f5dc173a09d45b58fc6c05b88af09093 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 18 Aug 2025 11:52:53 +0900 Subject: [PATCH 03/91] =?UTF-8?q?#15=20style:=20input-field=20=EB=B0=8F=20?= =?UTF-8?q?label=20=EA=B3=B5=ED=86=B5=20=EC=8A=A4=ED=83=80=EC=9D=BC=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/index.css b/src/index.css index f2a112e..fd98688 100644 --- a/src/index.css +++ b/src/index.css @@ -74,3 +74,13 @@ .text-btn { @apply text-base font-medium; } + +.input-field { + @apply bg-white w-[295px] px-[14.6px] py-[10.5px] rounded-[9px] border-[0.9px] border-purple-stroke focus:outline-1 focus:outline-primary; +} + +@layer base { + label { + @apply flex flex-col gap-[12.5px]; + } +} From 2f157d6f921de22e7aae2b7ea48905335df325de Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 18 Aug 2025 11:55:29 +0900 Subject: [PATCH 04/91] =?UTF-8?q?#15=20feat:=20=EB=B2=84=ED=8A=BC=20second?= =?UTF-8?q?aryPurple=20variant=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Button.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/common/Button.tsx b/src/components/common/Button.tsx index 3c36220..fc14e33 100644 --- a/src/components/common/Button.tsx +++ b/src/components/common/Button.tsx @@ -13,6 +13,7 @@ const buttonTheme: ButtonTheme = { primaryPurple: 'primary-btn bg-primary text-white', primaryWhite: 'primary-btn bg-white text-primary border', secondaryPurpleStroke: 'secondary-btn bg-purple-stroke text-secondary-black', + secondaryPurple: 'secondary-btn bg-primary text-white', }; const Button = ({theme, text, icon}: ButtonProps) => { From 20da864dc7f5284ab7765469371ba0a40a573029 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 18 Aug 2025 11:57:56 +0900 Subject: [PATCH 05/91] =?UTF-8?q?#15=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/admin/UnitPage.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/pages/admin/UnitPage.tsx diff --git a/src/pages/admin/UnitPage.tsx b/src/pages/admin/UnitPage.tsx new file mode 100644 index 0000000..05bf03f --- /dev/null +++ b/src/pages/admin/UnitPage.tsx @@ -0,0 +1,11 @@ +import UnitLayout from '../../components/admin/units/UnitLayout'; + +const UnitPage = () => { + return ( +
+ +
+ ); +}; + +export default UnitPage; From 3db20b2ece4a0fc7e317e96f1a505a75de480b27 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 18 Aug 2025 11:59:07 +0900 Subject: [PATCH 06/91] =?UTF-8?q?#15=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20=EB=B0=8F=20?= =?UTF-8?q?UI=20=EA=B5=AC=EC=84=B1=20=EC=9A=94=EC=86=8C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/admin/units/UnitEditor.tsx | 18 +++++ src/components/admin/units/UnitForm.tsx | 71 ++++++++++++++++++++ src/components/admin/units/UnitLayout.tsx | 21 ++++++ src/components/admin/units/UnitList.tsx | 26 +++++++ src/components/admin/units/UnitListItem.tsx | 26 +++++++ src/components/admin/units/dummy/allUnits.ts | 25 +++++++ src/components/admin/units/dummy/types.ts | 31 +++++++++ src/components/admin/units/dummy/unit.ts | 22 ++++++ 8 files changed, 240 insertions(+) create mode 100644 src/components/admin/units/UnitEditor.tsx create mode 100644 src/components/admin/units/UnitForm.tsx create mode 100644 src/components/admin/units/UnitLayout.tsx create mode 100644 src/components/admin/units/UnitList.tsx create mode 100644 src/components/admin/units/UnitListItem.tsx create mode 100644 src/components/admin/units/dummy/allUnits.ts create mode 100644 src/components/admin/units/dummy/types.ts create mode 100644 src/components/admin/units/dummy/unit.ts diff --git a/src/components/admin/units/UnitEditor.tsx b/src/components/admin/units/UnitEditor.tsx new file mode 100644 index 0000000..9279d70 --- /dev/null +++ b/src/components/admin/units/UnitEditor.tsx @@ -0,0 +1,18 @@ +import {BinIcon} from '../../../assets/svg'; +import IconButton from '../../common/IconButton'; +import UnitForm from './UnitForm'; +import {unit} from './dummy/unit'; + +const UnitEditor = () => { + const unitInfo = unit.response; + return ( +
+
+

1. 단원

+
+ +
+ ); +}; + +export default UnitEditor; diff --git a/src/components/admin/units/UnitForm.tsx b/src/components/admin/units/UnitForm.tsx new file mode 100644 index 0000000..1ada676 --- /dev/null +++ b/src/components/admin/units/UnitForm.tsx @@ -0,0 +1,71 @@ +import {AddIcon} from '../../../assets/svg'; +import Button from '../../common/Button'; +import AssignmentCard from '../assignments/AssignmentCard'; +import type {UnitInfo} from './dummy/types'; + +interface UnitFormProps extends UnitInfo {} + +const UnitForm = ({ + title, + releaseDate, + dueDate, + assignments, +}: UnitFormProps) => { + return ( +
+
+ +
+ + +
+
+
+

문제 등록

+
+ {assignments.map((a) => ( + + ))} +
+
+
+
+
+ ); +}; + +export default UnitForm; diff --git a/src/components/admin/units/UnitLayout.tsx b/src/components/admin/units/UnitLayout.tsx new file mode 100644 index 0000000..8b0a21a --- /dev/null +++ b/src/components/admin/units/UnitLayout.tsx @@ -0,0 +1,21 @@ +import Button from '../../common/Button'; +import UnitEditor from './UnitEditor'; +import UnitList from './UnitList'; +const UnitLayout = () => { + return ( +
+ +
+ +
+
+
+
+ ); +}; + +export default UnitLayout; diff --git a/src/components/admin/units/UnitList.tsx b/src/components/admin/units/UnitList.tsx new file mode 100644 index 0000000..3d13995 --- /dev/null +++ b/src/components/admin/units/UnitList.tsx @@ -0,0 +1,26 @@ +import Button from '../../common/Button'; +import {AddIcon} from '../../../assets/svg'; +import {allUnits} from './dummy/allUnits'; +import UnitListItem from './UnitListItem'; +import {useState} from 'react'; + +const UnitList = () => { + const unitList = allUnits.response.units; + return ( +
+

단원 보기

+ {unitList.map((unit, index) => ( + + ))} +
+
+
+ ); +}; + +export default UnitList; diff --git a/src/components/admin/units/UnitListItem.tsx b/src/components/admin/units/UnitListItem.tsx new file mode 100644 index 0000000..b831cee --- /dev/null +++ b/src/components/admin/units/UnitListItem.tsx @@ -0,0 +1,26 @@ +import type {Unit} from './dummy/types'; +import {ArrowrightIcon} from '../../../assets/svg'; +import {useState} from 'react'; + +interface UnitListItemProps extends Unit { + index: number; +} + +const UnitListItem = ({index, title, assignmentCount}: UnitListItemProps) => { + return ( +
+ + {assignmentCount} 문제 + +
+

{title}

+ +
+
+ ); +}; + +export default UnitListItem; diff --git a/src/components/admin/units/dummy/allUnits.ts b/src/components/admin/units/dummy/allUnits.ts new file mode 100644 index 0000000..6137320 --- /dev/null +++ b/src/components/admin/units/dummy/allUnits.ts @@ -0,0 +1,25 @@ +import type {UnitListResponse} from './types'; + +export const allUnits: UnitListResponse = { + success: true, + response: { + count: 3, + units: [ + { + id: 1, + title: '변수와 수식 (수정)', + assignmentCount: 0, + }, + { + id: 2, + title: '날씨 데이터 확인하기', + assignmentCount: 0, + }, + { + id: 3, + title: '날씨 데이터 확인하기', + assignmentCount: 0, + }, + ], + }, +}; diff --git a/src/components/admin/units/dummy/types.ts b/src/components/admin/units/dummy/types.ts new file mode 100644 index 0000000..7a21ad1 --- /dev/null +++ b/src/components/admin/units/dummy/types.ts @@ -0,0 +1,31 @@ +import type {Assignment} from '../../assignments/dummy/types'; + +interface UnitInfo { + id: number; + title: string; + releaseDate: string; + dueDate: string; + assignmentCount: number; + assignments: Assignment[]; +} + +interface UnitResponse { + success: boolean; + response: UnitInfo; +} + +interface Unit { + id: number; + title: string; + assignmentCount: number; +} + +interface UnitListResponse { + success: boolean; + response: { + count: number; + units: Unit[]; + }; +} + +export type {UnitResponse, UnitListResponse, Unit, UnitInfo}; diff --git a/src/components/admin/units/dummy/unit.ts b/src/components/admin/units/dummy/unit.ts new file mode 100644 index 0000000..9e4d1ed --- /dev/null +++ b/src/components/admin/units/dummy/unit.ts @@ -0,0 +1,22 @@ +import type {UnitResponse} from './types'; + +export const unit: UnitResponse = { + success: true, + response: { + id: 1, + title: '날씨 데이터 확인하기', + releaseDate: '2025-07-27', + dueDate: '2025-07-27', + assignmentCount: 2, + assignments: [ + { + id: 1, + title: '날씨 데이터를 활용한 앱 만들기', + }, + { + id: 2, + title: '날씨 데이터를 활용한 앱 만들기', + }, + ], + }, +}; From 585765b5d60c6755c7e6c15b2a877efe34973227 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 18 Aug 2025 12:05:04 +0900 Subject: [PATCH 07/91] =?UTF-8?q?#15=20refactor:=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=97=90=20color=20props?= =?UTF-8?q?=20=EC=A0=84=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/admin/assignments/AssignmentPageLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/admin/assignments/AssignmentPageLayout.tsx b/src/components/admin/assignments/AssignmentPageLayout.tsx index e72355a..5a81a91 100644 --- a/src/components/admin/assignments/AssignmentPageLayout.tsx +++ b/src/components/admin/assignments/AssignmentPageLayout.tsx @@ -35,7 +35,7 @@ const AssignmentPageLayout = ({ ); From 420c7b3b7a801639c1b8f450e6012ce2b9c34b5d Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 9 Feb 2026 20:58:58 +0900 Subject: [PATCH 15/91] =?UTF-8?q?#15=20fix:=20Assignment=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=EC=9D=98=20submittedStatus?= =?UTF-8?q?=20optional=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/models/assignment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/assignment.ts b/src/models/assignment.ts index d1257cf..aa7c59b 100644 --- a/src/models/assignment.ts +++ b/src/models/assignment.ts @@ -6,5 +6,5 @@ import type {SubmissionStatus} from './course'; export interface Assignment { id: number; title: string; - submittedStatus: SubmissionStatus; + submittedStatus?: SubmissionStatus; } From 6ae32b4039fa15a5badb02e19fb812ca9aa742c7 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 9 Feb 2026 21:00:07 +0900 Subject: [PATCH 16/91] =?UTF-8?q?#15=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C-=EC=83=9D=EC=84=B1=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EB=8D=94=EB=AF=B8=20=EC=9D=91=EB=8B=B5=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EB=B0=8F=20=ED=83=80=EC=9E=85=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/models/course.ts | 9 +++++ src/pages/create-unit/mocks/response.ts | 54 +++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/pages/create-unit/mocks/response.ts diff --git a/src/models/course.ts b/src/models/course.ts index ed8cb9d..0e72e0b 100644 --- a/src/models/course.ts +++ b/src/models/course.ts @@ -95,3 +95,12 @@ export type CourseOptionsResponse = ApiResponse<{ count: number; courses: DashboardCourse[]; }>; + +// 단원 조회-생성 페이지 응답 타입 정의 - 단일 단원 +export type SingleUnitResponse = ApiResponse; + +// 단원 조회-생성 페이지 응답 타입 정의 - 전체 단원 목록 +export type AllUnitsResponse = ApiResponse<{ + count: number; + units: Pick[]; +}>; diff --git a/src/pages/create-unit/mocks/response.ts b/src/pages/create-unit/mocks/response.ts new file mode 100644 index 0000000..153afca --- /dev/null +++ b/src/pages/create-unit/mocks/response.ts @@ -0,0 +1,54 @@ +import type {AllUnitsResponse, SingleUnitResponse} from '@/models/course'; + +export const singleUnitResponse: SingleUnitResponse = { + success: true, + response: { + id: 1, + title: '날씨 데이터 확인하기', + releaseDate: '2025-07-27', + dueDate: '2025-07-27', + assignmentCount: 4, + assignments: [ + { + id: 1, + title: '날씨 데이터를 활용한 앱 만들기', + }, + { + id: 2, + title: '날씨 데이터를 활용한 앱 만들기', + }, + { + id: 3, + title: '날씨 데이터를 활용한 앱 만들기', + }, + { + id: 4, + title: '날씨 데이터를 활용한 앱 만들기', + }, + ], + }, +}; + +export const allUnitsResponse: AllUnitsResponse = { + success: true, + response: { + count: 3, + units: [ + { + id: 1, + title: '변수와 수식 (수정)', + assignmentCount: 2, + }, + { + id: 2, + title: '날씨 데이터 확인하기', + assignmentCount: 1, + }, + { + id: 3, + title: '날씨 데이터 확인하기', + assignmentCount: 3, + }, + ], + }, +}; From e0390b5fc450276557b6d0dfabab0e9e77daf31d Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 9 Feb 2026 21:01:40 +0900 Subject: [PATCH 17/91] =?UTF-8?q?#15=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=9D=BC=EC=9A=B0=ED=8A=B8=EB=A5=BC=20adm?= =?UTF-8?q?in=20=ED=95=98=EC=9C=84=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EB=B0=8F=20CreateUnitPage=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index d49e941..2d14d74 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,13 +4,13 @@ import LandingPage from './pages/common/LandingPage'; import UserIdInputPage from './pages/common/UserIdInputPage'; import Dashboard from './pages/dashboard/Dashboard'; import AssignmentSelectPage from './pages/select-assignment/AssignmentSelectPage'; -import UnitPage from './pages/admin/UnitPage'; import CourseOverviewPage from './pages/course-overview/CourseOverviewPage'; import AssignmentCreatePage from './pages/admin/assignments/AssignmentCreatePage'; import CourseCreatePage from './pages/admin/courses/CourseCreatePage'; import StudentManagementPage from './pages/admin/student/StudentManagementPage'; import {useEffect} from 'react'; import {useUserStore} from '@/entities/auth/model/useUserStore'; +import CreateUnitPage from './pages/create-unit/CreateUnitPage'; const AppRoutes = () => { const {pathname} = useLocation(); @@ -47,8 +47,8 @@ const AppRoutes = () => { } /> } /> } /> + } /> - } /> ); From dd0b2d20466ee8392bda61a28930f4b4ddb73c80 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 9 Feb 2026 21:02:11 +0900 Subject: [PATCH 18/91] =?UTF-8?q?#15=20feat:=20binIcon=20public=20->=20src?= =?UTF-8?q?/assets=20=ED=95=98=EC=9C=84=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/svg/binIcon.svg | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/assets/svg/binIcon.svg diff --git a/src/assets/svg/binIcon.svg b/src/assets/svg/binIcon.svg new file mode 100644 index 0000000..f5af42c --- /dev/null +++ b/src/assets/svg/binIcon.svg @@ -0,0 +1,5 @@ + + + + + From 3bd6f5b2e61b4edb725ec4edbc37270715807598 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 9 Feb 2026 21:03:23 +0900 Subject: [PATCH 19/91] =?UTF-8?q?#15=20feat:=20CreatUnitPage=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/CreateUnitPage.tsx | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/pages/create-unit/CreateUnitPage.tsx diff --git a/src/pages/create-unit/CreateUnitPage.tsx b/src/pages/create-unit/CreateUnitPage.tsx new file mode 100644 index 0000000..8e13760 --- /dev/null +++ b/src/pages/create-unit/CreateUnitPage.tsx @@ -0,0 +1,25 @@ +import SurfaceCard from '@/components/common/SurfaceCard'; +import UnitFormEditor from './ui/UnitFormEditor'; +import UnitList from './ui/UnitList'; +import {allUnitsResponse, singleUnitResponse} from './mocks/response'; + +const CreateUnitPage = () => { + const unitList = allUnitsResponse.response.units; + const currentUnit = singleUnitResponse.response; + + return ( +
+ {/* 단원 리스트 섹션 */} + + + + + {/* 단원 폼 섹션 */} + + + +
+ ); +}; + +export default CreateUnitPage; From d3d758ceaec486dc60c40481ae209d937f0dd8b6 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 9 Feb 2026 21:04:13 +0900 Subject: [PATCH 20/91] =?UTF-8?q?#15=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=ED=8E=B8=EC=A7=91=20=EC=84=B9=EC=85=98=20(UnitFormEditor)=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/ui/UnitFormEditor.tsx | 99 +++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/pages/create-unit/ui/UnitFormEditor.tsx diff --git a/src/pages/create-unit/ui/UnitFormEditor.tsx b/src/pages/create-unit/ui/UnitFormEditor.tsx new file mode 100644 index 0000000..f9b3f79 --- /dev/null +++ b/src/pages/create-unit/ui/UnitFormEditor.tsx @@ -0,0 +1,99 @@ +import {useForm, type FieldValues} from 'react-hook-form'; +import Button from '@/components/common/Button'; +import BinIcon from '@/assets/svg/binIcon.svg?react'; +import LabeledInput from '@/components/admin/form/LabeledInput'; +import type {Unit} from '@/models/course'; + +const UnitFormEditor = ({unit}: {unit: Unit}) => { + const { + register, + handleSubmit, + // formState: {errors, isSubmitting}, + reset, + } = useForm(); + + const onSubmit = async (data: FieldValues) => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + reset(); + }; + + return ( +
+ {/* 단원 편집 폼 */} +
+ {/* 폼 헤더 */} +
+ {/* TODO: 단원 Index 추가하기 */} +

1. 단원

+ +
+ + {/* 폼 본문 */} +
+ {/* 단원 제목 섹션 */} +
+ +
+ + {/* 날짜 섹션 (공개일, 마감일) */} +
+ + +
+ +
+ + {/* 문제 등록 섹션 */} +
+

문제 등록

+ + { + /* 문제 리스트 */ + // TODO: 문제 리스트 컴포넌트 추가 + } +
+
+
+ + { + /* 문제 등록 */ + // TODO: 문제 등록 컴포넌트로 교체 필요 + } + + {/* 제출 버튼 */} +
+ + +
+
+ ); +}; + +export default UnitFormEditor; From e25f7f7d6754cf253825a33089a672681dba9432 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 9 Feb 2026 21:04:36 +0900 Subject: [PATCH 21/91] =?UTF-8?q?#15=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20(UnitList)=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/ui/UnitList.tsx | 51 +++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/pages/create-unit/ui/UnitList.tsx diff --git a/src/pages/create-unit/ui/UnitList.tsx b/src/pages/create-unit/ui/UnitList.tsx new file mode 100644 index 0000000..b1f9366 --- /dev/null +++ b/src/pages/create-unit/ui/UnitList.tsx @@ -0,0 +1,51 @@ +import Button from '@/components/common/Button'; +import AddIcon from '@/assets/svg/addIcon.svg?react'; +import Badge from '@/components/common/Badge'; +import ArrowrightIcon from '@/assets/svg/arrowrightIcon.svg?react'; +import type {AllUnitsResponse} from '@/models/course'; + +interface UnitListProps { + unitList: AllUnitsResponse['response']['units']; +} + +const UnitList = ({unitList}: UnitListProps) => { + return ( +
+ {/* 단원 리스트 헤더 */} +

단원 보기

+ + {/* 단원 목록 */} +
    + {/* 단원 아이템 */} + {unitList.map(({id, title, assignmentCount}) => ( +
  • + {/* 단원 인덱스 배지 */} +
    + + {assignmentCount} + +
    + + {/* 단원 제목 및 화살표 아이콘 */} +
    +

    {title}

    + +
    +
  • + ))} +
+ + {/* 단원 추가 버튼 */} +
+ +
+
+ ); +}; + +export default UnitList; From b6cc590807ce1cff783077f4f2592bb1bfca63a0 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 9 Feb 2026 21:05:47 +0900 Subject: [PATCH 22/91] =?UTF-8?q?#15=20chorer:=20=EA=B8=B0=EC=A1=B4=20?= =?UTF-8?q?=EB=8B=A8=EC=9B=90=20=EA=B4=80=EB=A0=A8=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EB=B0=8F=20=EB=8D=94=EB=AF=B8=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/svg/binIcon.svg | 5 -- src/assets/svg/BinIcon.tsx | 23 ------- src/components/admin/units/UnitEditor.tsx | 18 ----- src/components/admin/units/UnitForm.tsx | 71 -------------------- src/components/admin/units/UnitLayout.tsx | 21 ------ src/components/admin/units/UnitList.tsx | 26 ------- src/components/admin/units/UnitListItem.tsx | 26 ------- src/components/admin/units/dummy/allUnits.ts | 25 ------- src/components/admin/units/dummy/types.ts | 31 --------- src/components/admin/units/dummy/unit.ts | 34 ---------- src/pages/admin/UnitPage.tsx | 11 --- 11 files changed, 291 deletions(-) delete mode 100644 public/svg/binIcon.svg delete mode 100644 src/assets/svg/BinIcon.tsx delete mode 100644 src/components/admin/units/UnitEditor.tsx delete mode 100644 src/components/admin/units/UnitForm.tsx delete mode 100644 src/components/admin/units/UnitLayout.tsx delete mode 100644 src/components/admin/units/UnitList.tsx delete mode 100644 src/components/admin/units/UnitListItem.tsx delete mode 100644 src/components/admin/units/dummy/allUnits.ts delete mode 100644 src/components/admin/units/dummy/types.ts delete mode 100644 src/components/admin/units/dummy/unit.ts delete mode 100644 src/pages/admin/UnitPage.tsx diff --git a/public/svg/binIcon.svg b/public/svg/binIcon.svg deleted file mode 100644 index f5af42c..0000000 --- a/public/svg/binIcon.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/assets/svg/BinIcon.tsx b/src/assets/svg/BinIcon.tsx deleted file mode 100644 index 375bd97..0000000 --- a/src/assets/svg/BinIcon.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import * as React from 'react'; -import type {SVGProps} from 'react'; -const SvgBinIcon = (props: SVGProps) => ( - - - - - -); -export default SvgBinIcon; diff --git a/src/components/admin/units/UnitEditor.tsx b/src/components/admin/units/UnitEditor.tsx deleted file mode 100644 index 2fffd20..0000000 --- a/src/components/admin/units/UnitEditor.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import {BinIcon} from '../../../assets/svg'; -import IconButton from '../../common/IconButton'; -import UnitForm from './UnitForm'; -import {unit} from './dummy/unit'; - -const UnitEditor = () => { - const unitInfo = unit.response; - return ( -
-
-

1. 단원

-
- -
- ); -}; - -export default UnitEditor; diff --git a/src/components/admin/units/UnitForm.tsx b/src/components/admin/units/UnitForm.tsx deleted file mode 100644 index 86f28cc..0000000 --- a/src/components/admin/units/UnitForm.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import {AddIcon} from '../../../assets/svg'; -import Button from '../../common/Button'; -import AssignmentCard from '../assignments/AssignmentCard'; -import type {UnitInfo} from './dummy/types'; - -interface UnitFormProps extends UnitInfo {} - -const UnitForm = ({ - title, - releaseDate, - dueDate, - assignments, -}: UnitFormProps) => { - return ( -
-
- -
- - -
-
-
-

문제 등록

-
- {assignments.map((a) => ( - - ))} -
-
-
-
-
- ); -}; - -export default UnitForm; diff --git a/src/components/admin/units/UnitLayout.tsx b/src/components/admin/units/UnitLayout.tsx deleted file mode 100644 index 6f37630..0000000 --- a/src/components/admin/units/UnitLayout.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import Button from '../../common/Button'; -import UnitEditor from './UnitEditor'; -import UnitList from './UnitList'; -const UnitLayout = () => { - return ( -
- -
- -
-
-
-
- ); -}; - -export default UnitLayout; diff --git a/src/components/admin/units/UnitList.tsx b/src/components/admin/units/UnitList.tsx deleted file mode 100644 index 3d13995..0000000 --- a/src/components/admin/units/UnitList.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import Button from '../../common/Button'; -import {AddIcon} from '../../../assets/svg'; -import {allUnits} from './dummy/allUnits'; -import UnitListItem from './UnitListItem'; -import {useState} from 'react'; - -const UnitList = () => { - const unitList = allUnits.response.units; - return ( -
-

단원 보기

- {unitList.map((unit, index) => ( - - ))} -
-
-
- ); -}; - -export default UnitList; diff --git a/src/components/admin/units/UnitListItem.tsx b/src/components/admin/units/UnitListItem.tsx deleted file mode 100644 index b831cee..0000000 --- a/src/components/admin/units/UnitListItem.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import type {Unit} from './dummy/types'; -import {ArrowrightIcon} from '../../../assets/svg'; -import {useState} from 'react'; - -interface UnitListItemProps extends Unit { - index: number; -} - -const UnitListItem = ({index, title, assignmentCount}: UnitListItemProps) => { - return ( -
- - {assignmentCount} 문제 - -
-

{title}

- -
-
- ); -}; - -export default UnitListItem; diff --git a/src/components/admin/units/dummy/allUnits.ts b/src/components/admin/units/dummy/allUnits.ts deleted file mode 100644 index 6137320..0000000 --- a/src/components/admin/units/dummy/allUnits.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type {UnitListResponse} from './types'; - -export const allUnits: UnitListResponse = { - success: true, - response: { - count: 3, - units: [ - { - id: 1, - title: '변수와 수식 (수정)', - assignmentCount: 0, - }, - { - id: 2, - title: '날씨 데이터 확인하기', - assignmentCount: 0, - }, - { - id: 3, - title: '날씨 데이터 확인하기', - assignmentCount: 0, - }, - ], - }, -}; diff --git a/src/components/admin/units/dummy/types.ts b/src/components/admin/units/dummy/types.ts deleted file mode 100644 index 7a21ad1..0000000 --- a/src/components/admin/units/dummy/types.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type {Assignment} from '../../assignments/dummy/types'; - -interface UnitInfo { - id: number; - title: string; - releaseDate: string; - dueDate: string; - assignmentCount: number; - assignments: Assignment[]; -} - -interface UnitResponse { - success: boolean; - response: UnitInfo; -} - -interface Unit { - id: number; - title: string; - assignmentCount: number; -} - -interface UnitListResponse { - success: boolean; - response: { - count: number; - units: Unit[]; - }; -} - -export type {UnitResponse, UnitListResponse, Unit, UnitInfo}; diff --git a/src/components/admin/units/dummy/unit.ts b/src/components/admin/units/dummy/unit.ts deleted file mode 100644 index 4e976e3..0000000 --- a/src/components/admin/units/dummy/unit.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type {UnitResponse} from './types'; - -export const unit: UnitResponse = { - success: true, - response: { - id: 1, - title: '날씨 데이터 확인하기', - releaseDate: '2025-07-27', - dueDate: '2025-07-27', - assignmentCount: 5, - assignments: [ - { - id: 1, - title: '날씨 데이터를 활용한 앱 만들기', - }, - { - id: 2, - title: '날씨 데이터를 활용한 앱 만들기', - }, - { - id: 3, - title: '날씨 데이터를 활용한 앱 만들기', - }, - { - id: 4, - title: '날씨 데이터를 활용한 앱 만들기', - }, - { - id: 5, - title: '날씨 데이터를 활용한 앱 만들기', - }, - ], - }, -}; diff --git a/src/pages/admin/UnitPage.tsx b/src/pages/admin/UnitPage.tsx deleted file mode 100644 index 05bf03f..0000000 --- a/src/pages/admin/UnitPage.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import UnitLayout from '../../components/admin/units/UnitLayout'; - -const UnitPage = () => { - return ( -
- -
- ); -}; - -export default UnitPage; From a01b2a781eb40c7dbd2d13692d8e84f7125bac8b Mon Sep 17 00:00:00 2001 From: suminb99 Date: Tue, 10 Feb 2026 00:40:55 +0900 Subject: [PATCH 23/91] =?UTF-8?q?#15=20feat:=20SelectableItem=20className?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=98=A4=EB=B2=84=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=94=A9=20=EA=B0=80=EB=8A=A5=ED=95=98=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/SelectableItem.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/common/SelectableItem.tsx b/src/components/common/SelectableItem.tsx index 7822024..eeba682 100644 --- a/src/components/common/SelectableItem.tsx +++ b/src/components/common/SelectableItem.tsx @@ -20,6 +20,7 @@ interface SelectableItemProps extends SelectableItemVariants { leftIcon?: React.ReactNode; title: string; rightIcon?: React.ReactNode; + className?: string; } const SelectableItem = ({ @@ -27,9 +28,10 @@ const SelectableItem = ({ leftIcon, title, rightIcon, + className, }: SelectableItemProps) => { return ( -
+
{leftIcon}

{title}

{rightIcon}
From 64a9ec4f84b49487bf715637da3041109f47a552 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Tue, 10 Feb 2026 00:41:26 +0900 Subject: [PATCH 24/91] =?UTF-8?q?#15=20chore:=20dnd-kit=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +++ pnpm-lock.yaml | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/package.json b/package.json index 48b83af..0e56433 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,9 @@ "preinstall": "npx only-allow pnpm" }, "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@tailwindcss/vite": "^4.1.11", "axios": "^1.13.4", "react": "^19.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 478e9c1..2d20ed2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,15 @@ importers: .: dependencies: + '@dnd-kit/core': + specifier: ^6.3.1 + version: 6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@dnd-kit/sortable': + specifier: ^10.0.0 + version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) + '@dnd-kit/utilities': + specifier: ^3.2.2 + version: 3.2.2(react@19.1.0) '@tailwindcss/vite': specifier: ^4.1.11 version: 4.1.11(vite@7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1)) @@ -284,6 +293,28 @@ packages: resolution: {integrity: sha512-Y6+WUMsTFWE5jb20IFP4YGa5IrGY/+a/FbOSjDF/wz9gepU2hwCYSXRHP/vPwBvwcY3SVMASt4yXxbXNXigmZQ==} engines: {node: '>=18'} + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.3.1': + resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/sortable@10.0.0': + resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==} + peerDependencies: + '@dnd-kit/core': ^6.3.0 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + '@esbuild/aix-ppc64@0.25.5': resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} engines: {node: '>=18'} @@ -2544,6 +2575,31 @@ snapshots: gonzales-pe: 4.3.0 node-source-walk: 7.0.1 + '@dnd-kit/accessibility@3.1.1(react@19.1.0)': + dependencies: + react: 19.1.0 + tslib: 2.8.1 + + '@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@dnd-kit/accessibility': 3.1.1(react@19.1.0) + '@dnd-kit/utilities': 3.2.2(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + tslib: 2.8.1 + + '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)': + dependencies: + '@dnd-kit/core': 6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@dnd-kit/utilities': 3.2.2(react@19.1.0) + react: 19.1.0 + tslib: 2.8.1 + + '@dnd-kit/utilities@3.2.2(react@19.1.0)': + dependencies: + react: 19.1.0 + tslib: 2.8.1 + '@esbuild/aix-ppc64@0.25.5': optional: true From 0e17edfa9309ab5603eb0f13206d7acf15f58db5 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Tue, 10 Feb 2026 00:41:53 +0900 Subject: [PATCH 25/91] =?UTF-8?q?#15=20style:=20shadow=20custom=20variant?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.css b/src/index.css index 00c9930..fabeecd 100644 --- a/src/index.css +++ b/src/index.css @@ -55,6 +55,7 @@ --color-badge-red: #ff6f6f; --font-coolvetica: 'Coolvetica', sans-serif; + --shadow-box: 2px 4px 10px 0 rgba(0, 0, 0, 0.05); --shadow-card: 0px 0px 14px 0px rgba(223, 219, 240, 0.4); --shadow-modal: 4px 4px 7px 0px rgba(0, 0, 0, 0.1); --shadow-dropdown: 2px 4px 7px 0px rgba(0, 0, 0, 0.1); From 4e810144d86c1e9443e7124b416958b158db61ed Mon Sep 17 00:00:00 2001 From: suminb99 Date: Tue, 10 Feb 2026 00:42:46 +0900 Subject: [PATCH 26/91] =?UTF-8?q?#15=20feat:=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EA=B3=BC=EC=A0=9C=20=EB=B0=B0?= =?UTF-8?q?=EC=97=B4=20=EC=95=84=EC=9D=B4=ED=85=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/mocks/response.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/pages/create-unit/mocks/response.ts b/src/pages/create-unit/mocks/response.ts index 153afca..a2f1b57 100644 --- a/src/pages/create-unit/mocks/response.ts +++ b/src/pages/create-unit/mocks/response.ts @@ -7,23 +7,27 @@ export const singleUnitResponse: SingleUnitResponse = { title: '날씨 데이터 확인하기', releaseDate: '2025-07-27', dueDate: '2025-07-27', - assignmentCount: 4, + assignmentCount: 5, assignments: [ { id: 1, - title: '날씨 데이터를 활용한 앱 만들기', + title: '날씨 데이터를 활용한 앱 만들기 1', }, { id: 2, - title: '날씨 데이터를 활용한 앱 만들기', + title: '날씨 데이터를 활용한 앱 만들기 2', }, { id: 3, - title: '날씨 데이터를 활용한 앱 만들기', + title: '날씨 데이터를 활용한 앱 만들기 3', }, { id: 4, - title: '날씨 데이터를 활용한 앱 만들기', + title: '날씨 데이터를 활용한 앱 만들기 4', + }, + { + id: 5, + title: '날씨 데이터를 활용한 앱 만들기 4', }, ], }, From 57f9029087c2a8b10fc070c6f264760d5b9d88a7 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Tue, 10 Feb 2026 00:44:01 +0900 Subject: [PATCH 27/91] =?UTF-8?q?#15=20feat:=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EC=84=B9=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/ui/UnitFormEditor.tsx | 23 +++++++-------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/pages/create-unit/ui/UnitFormEditor.tsx b/src/pages/create-unit/ui/UnitFormEditor.tsx index f9b3f79..448eba0 100644 --- a/src/pages/create-unit/ui/UnitFormEditor.tsx +++ b/src/pages/create-unit/ui/UnitFormEditor.tsx @@ -3,6 +3,7 @@ import Button from '@/components/common/Button'; import BinIcon from '@/assets/svg/binIcon.svg?react'; import LabeledInput from '@/components/admin/form/LabeledInput'; import type {Unit} from '@/models/course'; +import {SortableAssignmentList} from './SortableAssignmentList'; const UnitFormEditor = ({unit}: {unit: Unit}) => { const { @@ -18,11 +19,11 @@ const UnitFormEditor = ({unit}: {unit: Unit}) => { }; return ( -
+
{/* 단원 편집 폼 */}
+ className='bg-background h-[670px] flex flex-col flex-1 rounded-[30px] overflow-y-auto'> {/* 폼 헤더 */}
{/* TODO: 단원 Index 추가하기 */} @@ -36,7 +37,7 @@ const UnitFormEditor = ({unit}: {unit: Unit}) => {
{/* 폼 본문 */} -
+
{/* 단원 제목 섹션 */}
{ />
-
+
{/* 문제 등록 섹션 */}
-

문제 등록

- - { - /* 문제 리스트 */ - // TODO: 문제 리스트 컴포넌트 추가 - } +
- { - /* 문제 등록 */ - // TODO: 문제 등록 컴포넌트로 교체 필요 - } - {/* 제출 버튼 */} -
+
From c0e321edffa34c9a1dd4ff3ac1b1f8a7d5553c4f Mon Sep 17 00:00:00 2001 From: suminb99 Date: Tue, 10 Feb 2026 00:45:20 +0900 Subject: [PATCH 28/91] =?UTF-8?q?#15=20feat:=20=EB=93=9C=EB=9E=98=EA=B7=B8?= =?UTF-8?q?=20=EB=B0=8F=20=EC=A0=95=EB=A0=AC=20=EA=B0=80=EB=8A=A5=ED=95=9C?= =?UTF-8?q?=20=EB=AC=B8=EC=A0=9C=20=EC=95=84=EC=9D=B4=ED=85=9C=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../create-unit/ui/SortableAssignmentList.tsx | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 src/pages/create-unit/ui/SortableAssignmentList.tsx diff --git a/src/pages/create-unit/ui/SortableAssignmentList.tsx b/src/pages/create-unit/ui/SortableAssignmentList.tsx new file mode 100644 index 0000000..c0c826e --- /dev/null +++ b/src/pages/create-unit/ui/SortableAssignmentList.tsx @@ -0,0 +1,115 @@ +import SelectableItem from '@/components/common/SelectableItem'; +import type {Assignment} from '@/models/assignment'; +import {useState} from 'react'; +import DragAndDropIcon from '@/assets/svg/dragAndDropIcon.svg?react'; +import DeleteIcon from '@/assets/svg/deleteIcon.svg?react'; +import { + closestCorners, + DndContext, + KeyboardSensor, + PointerSensor, + useSensor, + useSensors, +} from '@dnd-kit/core'; +import { + SortableContext, + verticalListSortingStrategy, + useSortable, + arrayMove, + sortableKeyboardCoordinates, +} from '@dnd-kit/sortable'; +import {CSS} from '@dnd-kit/utilities'; +import Button from '@/components/common/Button'; +import AddIcon from '@/assets/svg/addIcon.svg?react'; + +export const SortableAssignmentList = ({ + assignmentList, +}: { + assignmentList: Assignment[]; +}) => { + const [assignments, setAssignments] = useState(assignmentList); + + // 과제 인덱스 찾기 + const getAssignmentIndex = (id: number) => { + return assignments.findIndex((assignment) => assignment.id === id); + }; + + const handleDragEnd = (event: any) => { + // active: 드래그 중인 아이템, over: 드래그가 끝난 위치의 아이템 + const {active, over} = event; + + if (active.id === over.id) return; // 위치가 바뀌지 않은 경우 + + // 위치가 바뀐 경우 - 배열에서 아이템의 위치를 업데이트 + setAssignments((assignments) => { + const originalIndex = getAssignmentIndex(active.id); + const newIndex = getAssignmentIndex(over.id); + + return arrayMove(assignments, originalIndex, newIndex); + }); + }; + + const sensors = useSensors( + // 마우스 및 터치 센서 설정 + useSensor(PointerSensor, { + activationConstraint: {distance: 8}, + }), + + // 키보드 센서 설정 + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }) + ); + + return ( +
+ {/* 섹션 제목 - 문제 등록 */} +

문제 등록

+ + {/* draggable & sortable 문제 목록 영역 */} + + +
    + {assignments.map(({id, title}) => ( + + ))} +
+
+
+ + {/* 문제 연결 버튼 */} +
+ +
+
+ ); +}; + +const DraggableAssignmentItem = ({id, title}: Assignment) => { + const {attributes, listeners, setNodeRef, transform, transition, isDragging} = + useSortable({id}); + + const style = { + transform: CSS.Transform.toString(transform), + transition, + }; + + return ( +
  • + } + rightIcon={} + className={`cursor grab touch-none bg-white shadow-box active:cursor-grabbing ${isDragging ? 'z-10 opacity-50' : ''}`} + /> +
  • + ); +}; From 758499314db46bbf00f77bebaf6300621c8a9b73 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Wed, 11 Feb 2026 19:27:49 +0900 Subject: [PATCH 29/91] =?UTF-8?q?#15=20refactor:=20addIcon=20=EC=83=89?= =?UTF-8?q?=EC=83=81=20currentColor=20=EC=A0=81=EC=9A=A9=20=EB=B0=8F=20But?= =?UTF-8?q?ton=20none=20=EC=82=AC=EC=9D=B4=EC=A6=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/svg/addIcon.svg | 4 ++-- src/components/common/Button.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/assets/svg/addIcon.svg b/src/assets/svg/addIcon.svg index c9edbbd..2f57002 100644 --- a/src/assets/svg/addIcon.svg +++ b/src/assets/svg/addIcon.svg @@ -1,4 +1,4 @@ - - + + diff --git a/src/components/common/Button.tsx b/src/components/common/Button.tsx index 6ca2015..759ebde 100644 --- a/src/components/common/Button.tsx +++ b/src/components/common/Button.tsx @@ -17,7 +17,7 @@ const button = tv({ default: 'w-24 h-10 px-3 py-1.5', compact: 'w-fit px-3 py-1.5 leading-5', wide: 'w-40 py-[15px]', - none: 'w-fit p-0', + none: 'p-0', icon: 'w-16 h-16 p-0 rounded-full', // 아이콘 버튼 rounded 속성 적용 }, content: { From 94cb995289e3b1bfbc513d119f95968e79253a2a Mon Sep 17 00:00:00 2001 From: suminb99 Date: Wed, 11 Feb 2026 19:28:04 +0900 Subject: [PATCH 30/91] =?UTF-8?q?#15=20style:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=ED=8E=B8=EC=A7=91=20=ED=8F=BC=20=EB=A0=88=EC=9D=B4=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EB=B0=8F=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/CreateUnitPage.tsx | 2 +- src/pages/create-unit/ui/SortableAssignmentList.tsx | 1 + src/pages/create-unit/ui/UnitFormEditor.tsx | 10 ++++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/pages/create-unit/CreateUnitPage.tsx b/src/pages/create-unit/CreateUnitPage.tsx index 8e13760..3b9d80e 100644 --- a/src/pages/create-unit/CreateUnitPage.tsx +++ b/src/pages/create-unit/CreateUnitPage.tsx @@ -9,7 +9,7 @@ const CreateUnitPage = () => { return (
    - {/* 단원 리스트 섹션 */} + {/* 단원 목차 섹션 */} diff --git a/src/pages/create-unit/ui/SortableAssignmentList.tsx b/src/pages/create-unit/ui/SortableAssignmentList.tsx index c0c826e..ec26a97 100644 --- a/src/pages/create-unit/ui/SortableAssignmentList.tsx +++ b/src/pages/create-unit/ui/SortableAssignmentList.tsx @@ -93,6 +93,7 @@ export const SortableAssignmentList = ({ ); }; +// 드래그 가능한 과제 아이템 컴포넌트 const DraggableAssignmentItem = ({id, title}: Assignment) => { const {attributes, listeners, setNodeRef, transform, transition, isDragging} = useSortable({id}); diff --git a/src/pages/create-unit/ui/UnitFormEditor.tsx b/src/pages/create-unit/ui/UnitFormEditor.tsx index 448eba0..a5011cb 100644 --- a/src/pages/create-unit/ui/UnitFormEditor.tsx +++ b/src/pages/create-unit/ui/UnitFormEditor.tsx @@ -19,11 +19,11 @@ const UnitFormEditor = ({unit}: {unit: Unit}) => { }; return ( -
    +
    {/* 단원 편집 폼 */}
    + className='bg-background h-[670px] flex flex-col overflow-x-hidden custom-scrollbar rounded-[30px]'> {/* 폼 헤더 */}
    {/* TODO: 단원 Index 추가하기 */} @@ -31,13 +31,14 @@ const UnitFormEditor = ({unit}: {unit: Unit}) => {
    {/* 폼 본문 */} -
    +
    {/* 단원 제목 섹션 */}
    { }; export default UnitFormEditor; +devicePixelRatio; From 2f1ea99ffbaa36054317facb4858f0a8a1e299fb Mon Sep 17 00:00:00 2001 From: suminb99 Date: Wed, 11 Feb 2026 19:47:30 +0900 Subject: [PATCH 31/91] =?UTF-8?q?#44=20feat:=20=EA=B0=95=EC=9D=98=EB=B3=84?= =?UTF-8?q?=20=EC=A0=84=EC=B2=B4=20=EB=8B=A8=EC=9B=90=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitApi.ts | 10 ++++++++++ src/entities/unit/index.ts | 1 + 2 files changed, 11 insertions(+) create mode 100644 src/entities/unit/api/unitApi.ts create mode 100644 src/entities/unit/index.ts diff --git a/src/entities/unit/api/unitApi.ts b/src/entities/unit/api/unitApi.ts new file mode 100644 index 0000000..be0b394 --- /dev/null +++ b/src/entities/unit/api/unitApi.ts @@ -0,0 +1,10 @@ +import type {AllUnitsResponse} from '@/models/course'; +import {privateAxios} from '@/shared/api/axiosInstance'; + +// 강의별 전체 단원 조회 +export const getAllUnitsByCourseId = async ( + courseId: number +): Promise => { + const response = await privateAxios.get(`/courses/${courseId}/units`); + return response.data; +}; diff --git a/src/entities/unit/index.ts b/src/entities/unit/index.ts new file mode 100644 index 0000000..9af3bd5 --- /dev/null +++ b/src/entities/unit/index.ts @@ -0,0 +1 @@ +export {getAllUnitsByCourseId} from './api/unitApi'; From 5b292f5ed0a9f5435b836cdb3852f47afd4f884a Mon Sep 17 00:00:00 2001 From: suminb99 Date: Wed, 11 Feb 2026 19:50:37 +0900 Subject: [PATCH 32/91] =?UTF-8?q?#44=20feat:=20=ED=8A=B9=EC=A0=95=20?= =?UTF-8?q?=EB=8B=A8=EC=9B=90=20=EC=A1=B0=ED=9A=8C=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitApi.ts | 8 +++++++- src/entities/unit/index.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/entities/unit/api/unitApi.ts b/src/entities/unit/api/unitApi.ts index be0b394..9c64741 100644 --- a/src/entities/unit/api/unitApi.ts +++ b/src/entities/unit/api/unitApi.ts @@ -1,4 +1,4 @@ -import type {AllUnitsResponse} from '@/models/course'; +import type {AllUnitsResponse, Unit} from '@/models/course'; import {privateAxios} from '@/shared/api/axiosInstance'; // 강의별 전체 단원 조회 @@ -8,3 +8,9 @@ export const getAllUnitsByCourseId = async ( const response = await privateAxios.get(`/courses/${courseId}/units`); return response.data; }; + +// 단일 단원 조회 +export const getUnitById = async (unitId: number): Promise => { + const response = await privateAxios.get(`/units/${unitId}`); + return response.data; +}; diff --git a/src/entities/unit/index.ts b/src/entities/unit/index.ts index 9af3bd5..02e845c 100644 --- a/src/entities/unit/index.ts +++ b/src/entities/unit/index.ts @@ -1 +1 @@ -export {getAllUnitsByCourseId} from './api/unitApi'; +export {getAllUnitsByCourseId, getUnitById} from './api/unitApi'; From 5700500f9e788399bc9e9e3ff143ac220d441fbc Mon Sep 17 00:00:00 2001 From: suminb99 Date: Wed, 11 Feb 2026 19:58:38 +0900 Subject: [PATCH 33/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitApi.ts | 9 +++++++++ src/entities/unit/index.ts | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/entities/unit/api/unitApi.ts b/src/entities/unit/api/unitApi.ts index 9c64741..a81c3a5 100644 --- a/src/entities/unit/api/unitApi.ts +++ b/src/entities/unit/api/unitApi.ts @@ -1,3 +1,4 @@ +import type {ApiResponse} from '@/models/common'; import type {AllUnitsResponse, Unit} from '@/models/course'; import {privateAxios} from '@/shared/api/axiosInstance'; @@ -14,3 +15,11 @@ export const getUnitById = async (unitId: number): Promise => { const response = await privateAxios.get(`/units/${unitId}`); return response.data; }; + +// 단원 삭제 +export const deleteUnitById = async ( + unitId: number +): Promise> => { + const response = await privateAxios.delete(`/units/${unitId}`); + return response.data; +}; diff --git a/src/entities/unit/index.ts b/src/entities/unit/index.ts index 02e845c..dd51a55 100644 --- a/src/entities/unit/index.ts +++ b/src/entities/unit/index.ts @@ -1 +1,5 @@ -export {getAllUnitsByCourseId, getUnitById} from './api/unitApi'; +export { + getAllUnitsByCourseId, + getUnitById, + deleteUnitById, +} from './api/unitApi'; From 1b5573c8f17d1be50dac8340e95f40c6bf53337a Mon Sep 17 00:00:00 2001 From: suminb99 Date: Wed, 11 Feb 2026 20:13:47 +0900 Subject: [PATCH 34/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B4=80=EB=A0=A8=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EC=98=B5=EC=85=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitQueryOptions.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/entities/unit/api/unitQueryOptions.ts diff --git a/src/entities/unit/api/unitQueryOptions.ts b/src/entities/unit/api/unitQueryOptions.ts new file mode 100644 index 0000000..22080a6 --- /dev/null +++ b/src/entities/unit/api/unitQueryOptions.ts @@ -0,0 +1,18 @@ +import {queryOptions} from '@tanstack/react-query'; +import {getAllUnitsByCourseId, getUnitById} from './unitApi'; + +// 강의별 전체 단원 조회 쿼리 옵션 +export function allUnitsQueryOptions(courseId: number) { + return queryOptions({ + queryKey: ['units', courseId], + queryFn: () => getAllUnitsByCourseId(courseId), + }); +} + +// 단일 단원 조회 쿼리 옵션 +export function unitQueryOptions(unitId: number) { + return queryOptions({ + queryKey: ['unit', unitId], + queryFn: () => getUnitById(unitId), + }); +} From a1d8cf2e4e4679f267e04ec90c6af494f147c040 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Wed, 11 Feb 2026 22:28:09 +0900 Subject: [PATCH 35/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=ED=8F=BC=EC=97=90=20zod=20=EC=8A=A4=ED=82=A4=EB=A7=88=20?= =?UTF-8?q?=EA=B8=B0=EB=B0=98=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 + pnpm-lock.yaml | 2245 ++++++++----------- src/pages/create-unit/model/types.ts | 17 + src/pages/create-unit/ui/UnitFormEditor.tsx | 35 +- 4 files changed, 1028 insertions(+), 1271 deletions(-) create mode 100644 src/pages/create-unit/model/types.ts diff --git a/package.json b/package.json index 5ffb5c7..520d6f5 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", + "@hookform/resolvers": "^5.2.2", "@tailwindcss/vite": "^4.1.11", "@tanstack/react-query": "^5.90.20", "axios": "^1.13.4", @@ -25,6 +26,7 @@ "tailwind-merge": "^3.4.0", "tailwind-variants": "^3.2.2", "tailwindcss": "^4.1.11", + "zod": "^4.3.6", "zustand": "^5.0.10" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dee8723..b73f2ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,92 +10,98 @@ importers: dependencies: '@dnd-kit/core': specifier: ^6.3.1 - version: 6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@dnd-kit/sortable': specifier: ^10.0.0 - version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) + version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) '@dnd-kit/utilities': specifier: ^3.2.2 - version: 3.2.2(react@19.1.0) + version: 3.2.2(react@19.2.4) + '@hookform/resolvers': + specifier: ^5.2.2 + version: 5.2.2(react-hook-form@7.71.1(react@19.2.4)) '@tailwindcss/vite': specifier: ^4.1.11 - version: 4.1.11(vite@7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1)) + version: 4.1.18(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)) '@tanstack/react-query': specifier: ^5.90.20 - version: 5.90.20(react@19.1.0) + version: 5.90.21(react@19.2.4) axios: specifier: ^1.13.4 - version: 1.13.4 + version: 1.13.5 react: specifier: ^19.1.0 - version: 19.1.0 + version: 19.2.4 react-dom: specifier: ^19.1.0 - version: 19.1.0(react@19.1.0) + version: 19.2.4(react@19.2.4) react-hook-form: specifier: ^7.71.1 - version: 7.71.1(react@19.1.0) + version: 7.71.1(react@19.2.4) react-router-dom: specifier: ^7.6.3 - version: 7.6.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tailwind-merge: specifier: ^3.4.0 version: 3.4.0 tailwind-variants: specifier: ^3.2.2 - version: 3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.11) + version: 3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.18) tailwindcss: specifier: ^4.1.11 - version: 4.1.11 + version: 4.1.18 + zod: + specifier: ^4.3.6 + version: 4.3.6 zustand: specifier: ^5.0.10 - version: 5.0.10(@types/react@19.1.8)(immer@10.2.0)(react@19.1.0) + version: 5.0.11(@types/react@19.2.14)(immer@10.2.0)(react@19.2.4) devDependencies: '@commitlint/cli': specifier: ^20.3.0 - version: 20.3.0(@types/node@24.2.1)(typescript@5.8.3) + version: 20.4.1(@types/node@24.10.13)(typescript@5.8.3) '@commitlint/config-conventional': specifier: ^20.3.0 - version: 20.3.0 + version: 20.4.1 '@eslint/js': specifier: ^9.29.0 - version: 9.30.1 + version: 9.39.2 '@feature-sliced/steiger-plugin': specifier: ^0.5.7 version: 0.5.7(typescript@5.8.3) '@tanstack/eslint-plugin-query': specifier: ^5.91.4 - version: 5.91.4(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) + version: 5.91.4(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) '@types/node': specifier: ^24.2.1 - version: 24.2.1 + version: 24.10.13 '@types/react': specifier: ^19.1.8 - version: 19.1.8 + version: 19.2.14 '@types/react-dom': specifier: ^19.1.6 - version: 19.1.6(@types/react@19.1.8) + version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^4.5.2 - version: 4.6.0(vite@7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1)) + version: 4.7.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)) eslint: specifier: ^9.29.0 - version: 9.30.1(jiti@2.6.1) + version: 9.39.2(jiti@2.6.1) eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.30.1(jiti@2.6.1)) + version: 5.2.0(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react-refresh: specifier: ^0.4.20 - version: 0.4.20(eslint@9.30.1(jiti@2.6.1)) + version: 0.4.26(eslint@9.39.2(jiti@2.6.1)) globals: specifier: ^16.2.0 - version: 16.3.0 + version: 16.5.0 prettier: specifier: ^3.6.2 - version: 3.6.2 + version: 3.8.1 prettier-plugin-tailwindcss: specifier: ^0.6.14 - version: 0.6.14(prettier@3.6.2) + version: 0.6.14(prettier@3.8.1) steiger: specifier: ^0.5.11 version: 0.5.11(typescript@5.8.3) @@ -107,69 +113,61 @@ importers: version: 5.8.3 typescript-eslint: specifier: ^8.34.1 - version: 8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) + version: 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) vite: specifier: ^7.0.0 - version: 7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1) + version: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2) vite-plugin-svgr: specifier: ^4.3.0 - version: 4.3.0(rollup@4.44.2)(typescript@5.8.3)(vite@7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1)) + version: 4.5.0(rollup@4.57.1)(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1)) + version: 5.1.4(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)) packages: - '@ampproject/remapping@2.3.0': - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} - - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.0': - resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.0': - resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.0': - resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.27.3': - resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} @@ -178,17 +176,12 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.27.6': - resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.0': - resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/parser@7.28.6': - resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} hasBin: true @@ -204,20 +197,16 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.28.0': - resolution: {integrity: sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.0': - resolution: {integrity: sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.6': - resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} '@clack/core@0.4.1': @@ -226,73 +215,73 @@ packages: '@clack/prompts@0.9.1': resolution: {integrity: sha512-JIpyaboYZeWYlyP0H+OoPPxd6nqueG/CmN6ixBiNFsIDHREevjIf0n0Ohh5gr5C8pEDknzgvz+pIJ8dMhzWIeg==} - '@commitlint/cli@20.3.0': - resolution: {integrity: sha512-HXO8YVfqdBK+MnlX2zqNrv6waGYPs6Ysjm5W2Y0GMagWXwiIKx7C8dcIX9ca+QdHq4WA0lcMnZLQ0pzQh1piZg==} + '@commitlint/cli@20.4.1': + resolution: {integrity: sha512-uuFKKpc7OtQM+6SRqT+a4kV818o1pS+uvv/gsRhyX7g4x495jg+Q7P0+O9VNGyLXBYP0syksS7gMRDJKcekr6A==} engines: {node: '>=v18'} hasBin: true - '@commitlint/config-conventional@20.3.0': - resolution: {integrity: sha512-g1OXVl6E2v0xF1Ru2RpxQ+Vfy7XUcUsCmLKzGUrhFLS4hSNykje0QSy6djBtzOiOBQCepBrmIlqx/gRlzrSh5A==} + '@commitlint/config-conventional@20.4.1': + resolution: {integrity: sha512-0YUvIeBtpi86XriqrR+TCULVFiyYTIOEPjK7tTRMxjcBm1qlzb+kz7IF2WxL6Fq5DaundG8VO37BNgMkMTBwqA==} engines: {node: '>=v18'} - '@commitlint/config-validator@20.2.0': - resolution: {integrity: sha512-SQCBGsL9MFk8utWNSthdxd9iOD1pIVZSHxGBwYIGfd67RTjxqzFOSAYeQVXOu3IxRC3YrTOH37ThnTLjUlyF2w==} + '@commitlint/config-validator@20.4.0': + resolution: {integrity: sha512-zShmKTF+sqyNOfAE0vKcqnpvVpG0YX8F9G/ZIQHI2CoKyK+PSdladXMSns400aZ5/QZs+0fN75B//3Q5CHw++w==} engines: {node: '>=v18'} - '@commitlint/ensure@20.2.0': - resolution: {integrity: sha512-+8TgIGv89rOWyt3eC6lcR1H7hqChAKkpawytlq9P1i/HYugFRVqgoKJ8dhd89fMnlrQTLjA5E97/4sF09QwdoA==} + '@commitlint/ensure@20.4.1': + resolution: {integrity: sha512-WLQqaFx1pBooiVvBrA1YfJNFqZF8wS/YGOtr5RzApDbV9tQ52qT5VkTsY65hFTnXhW8PcDfZLaknfJTmPejmlw==} engines: {node: '>=v18'} '@commitlint/execute-rule@20.0.0': resolution: {integrity: sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==} engines: {node: '>=v18'} - '@commitlint/format@20.2.0': - resolution: {integrity: sha512-PhNoLNhxpfIBlW/i90uZ3yG3hwSSYx7n4d9Yc+2FAorAHS0D9btYRK4ZZXX+Gm3W5tDtu911ow/eWRfcRVgNWg==} + '@commitlint/format@20.4.0': + resolution: {integrity: sha512-i3ki3WR0rgolFVX6r64poBHXM1t8qlFel1G1eCBvVgntE3fCJitmzSvH5JD/KVJN/snz6TfaX2CLdON7+s4WVQ==} engines: {node: '>=v18'} - '@commitlint/is-ignored@20.2.0': - resolution: {integrity: sha512-Lz0OGeZCo/QHUDLx5LmZc0EocwanneYJUM8z0bfWexArk62HKMLfLIodwXuKTO5y0s6ddXaTexrYHs7v96EOmw==} + '@commitlint/is-ignored@20.4.1': + resolution: {integrity: sha512-In5EO4JR1lNsAv1oOBBO24V9ND1IqdAJDKZiEpdfjDl2HMasAcT7oA+5BKONv1pRoLG380DGPE2W2RIcUwdgLA==} engines: {node: '>=v18'} - '@commitlint/lint@20.3.0': - resolution: {integrity: sha512-X19HOGU5nRo6i9DIY0kG0mhgtvpn1UGO1D6aLX1ILLyeqSM5yJyMcrRqNj8SLgeSeUDODhLY9QYsBIG0LdNHkA==} + '@commitlint/lint@20.4.1': + resolution: {integrity: sha512-g94LrGl/c6UhuhDQqNqU232aslLEN2vzc7MPfQTHzwzM4GHNnEAwVWWnh0zX8S5YXecuLXDwbCsoGwmpAgPWKA==} engines: {node: '>=v18'} - '@commitlint/load@20.3.0': - resolution: {integrity: sha512-amkdVZTXp5R65bsRXRSCwoNXbJHR2aAIY/RGFkoyd63t8UEwqEgT3f0MgeLqYw4hwXyq+TYXKdaW133E29pnGQ==} + '@commitlint/load@20.4.0': + resolution: {integrity: sha512-Dauup/GfjwffBXRJUdlX/YRKfSVXsXZLnINXKz0VZkXdKDcaEILAi9oflHGbfydonJnJAbXEbF3nXPm9rm3G6A==} engines: {node: '>=v18'} - '@commitlint/message@20.0.0': - resolution: {integrity: sha512-gLX4YmKnZqSwkmSB9OckQUrI5VyXEYiv3J5JKZRxIp8jOQsWjZgHSG/OgEfMQBK9ibdclEdAyIPYggwXoFGXjQ==} + '@commitlint/message@20.4.0': + resolution: {integrity: sha512-B5lGtvHgiLAIsK5nLINzVW0bN5hXv+EW35sKhYHE8F7V9Uz1fR4tx3wt7mobA5UNhZKUNgB/+ldVMQE6IHZRyA==} engines: {node: '>=v18'} - '@commitlint/parse@20.2.0': - resolution: {integrity: sha512-LXStagGU1ivh07X7sM+hnEr4BvzFYn1iBJ6DRg2QsIN8lBfSzyvkUcVCDwok9Ia4PWiEgei5HQjju6xfJ1YaSQ==} + '@commitlint/parse@20.4.1': + resolution: {integrity: sha512-XNtZjeRcFuAfUnhYrCY02+mpxwY4OmnvD3ETbVPs25xJFFz1nRo/25nHj+5eM+zTeRFvWFwD4GXWU2JEtoK1/w==} engines: {node: '>=v18'} - '@commitlint/read@20.2.0': - resolution: {integrity: sha512-+SjF9mxm5JCbe+8grOpXCXMMRzAnE0WWijhhtasdrpJoAFJYd5UgRTj/oCq5W3HJTwbvTOsijEJ0SUGImECD7Q==} + '@commitlint/read@20.4.0': + resolution: {integrity: sha512-QfpFn6/I240ySEGv7YWqho4vxqtPpx40FS7kZZDjUJ+eHxu3azfhy7fFb5XzfTqVNp1hNoI3tEmiEPbDB44+cg==} engines: {node: '>=v18'} - '@commitlint/resolve-extends@20.2.0': - resolution: {integrity: sha512-KVoLDi9BEuqeq+G0wRABn4azLRiCC22/YHR2aCquwx6bzCHAIN8hMt3Nuf1VFxq/c8ai6s8qBxE8+ZD4HeFTlQ==} + '@commitlint/resolve-extends@20.4.0': + resolution: {integrity: sha512-ay1KM8q0t+/OnlpqXJ+7gEFQNlUtSU5Gxr8GEwnVf2TPN3+ywc5DzL3JCxmpucqxfHBTFwfRMXxPRRnR5Ki20g==} engines: {node: '>=v18'} - '@commitlint/rules@20.3.0': - resolution: {integrity: sha512-TGgXN/qBEhbzVD13crE1l7YSMJRrbPbUL0OBZALbUM5ER36RZmiZRu2ud2W/AA7HO9YLBRbyx6YVi2t/2Be0yQ==} + '@commitlint/rules@20.4.1': + resolution: {integrity: sha512-WtqypKEPbQEuJwJS4aKs0OoJRBKz1HXPBC9wRtzVNH68FLhPWzxXlF09hpUXM9zdYTpm4vAdoTGkWiBgQ/vL0g==} engines: {node: '>=v18'} '@commitlint/to-lines@20.0.0': resolution: {integrity: sha512-2l9gmwiCRqZNWgV+pX1X7z4yP0b3ex/86UmUFgoRt672Ez6cAM2lOQeHFRUTuE6sPpi8XBCGnd8Kh3bMoyHwJw==} engines: {node: '>=v18'} - '@commitlint/top-level@20.0.0': - resolution: {integrity: sha512-drXaPSP2EcopukrUXvUXmsQMu3Ey/FuJDc/5oiW4heoCfoE5BdLQyuc7veGeE3aoQaTVqZnh4D5WTWe2vefYKg==} + '@commitlint/top-level@20.4.0': + resolution: {integrity: sha512-NDzq8Q6jmFaIIBC/GG6n1OQEaHdmaAAYdrZRlMgW6glYWGZ+IeuXmiymDvQNXPc82mVxq2KiE3RVpcs+1OeDeA==} engines: {node: '>=v18'} - '@commitlint/types@20.2.0': - resolution: {integrity: sha512-KTy0OqRDLR5y/zZMnizyx09z/rPlPC/zKhYgH8o/q6PuAjoQAKlRfY4zzv0M64yybQ//6//4H1n14pxaLZfUnA==} + '@commitlint/types@20.4.0': + resolution: {integrity: sha512-aO5l99BQJ0X34ft8b0h7QFkQlqxC6e7ZPVmBKz13xM9O8obDaM1Cld4sQlJDXXU/VFuUzQ30mVtHjVz74TuStw==} engines: {node: '>=v18'} '@dependents/detective-less@5.0.1': @@ -321,202 +310,198 @@ packages: peerDependencies: react: '>=16.8.0' - '@esbuild/aix-ppc64@0.25.5': - resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.5': - resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.5': - resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.5': - resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.5': - resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.5': - resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.5': - resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.5': - resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.5': - resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.5': - resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.5': - resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.5': - resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.5': - resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.5': - resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.5': - resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.5': - resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.5': - resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.5': - resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.5': - resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.5': - resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.5': - resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.25.5': - resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.5': - resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.5': - resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.5': - resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.7.0': - resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.21.0': - resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.3.0': - resolution: {integrity: sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==} + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.14.0': - resolution: {integrity: sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==} + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.15.1': - resolution: {integrity: sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==} + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.3.1': - resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + '@eslint/eslintrc@3.3.3': + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.30.1': - resolution: {integrity: sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==} + '@eslint/js@9.39.2': + resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/object-schema@2.1.6': - resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.3.3': - resolution: {integrity: sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==} + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@feature-sliced/filesystem@3.0.1': @@ -525,45 +510,42 @@ packages: '@feature-sliced/steiger-plugin@0.5.7': resolution: {integrity: sha512-xENW2fvfU+UyMgcB3S+CCMPrH2Tq/BG1W9IxGp5B8+j0TtbgmbzT3DIj3A2HG4kouVYUjzgWA6JIuHbGo3lDzg==} + '@hookform/resolvers@5.2.2': + resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} + peerDependencies: + react-hook-form: ^7.55.0 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.6': - resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/retry@0.3.1': - resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} - engines: {node: '>=18.18'} - '@humanwhocodes/retry@0.4.3': resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@isaacs/fs-minipass@4.0.1': - resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} - engines: {node: '>=18.0.0'} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - '@jridgewell/gen-mapping@0.3.12': - resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.5.4': - resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} - '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@jridgewell/trace-mapping@0.3.29': - resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -577,11 +559,11 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@rolldown/pluginutils@1.0.0-beta.19': - resolution: {integrity: sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==} + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - '@rollup/pluginutils@5.2.0': - resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==} + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 @@ -589,103 +571,128 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.44.2': - resolution: {integrity: sha512-g0dF8P1e2QYPOj1gu7s/3LVP6kze9A7m6x0BZ9iTdXK8N5c2V7cpBKHV3/9A4Zd8xxavdhK0t4PnqjkqVmUc9Q==} + '@rollup/rollup-android-arm-eabi@4.57.1': + resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.44.2': - resolution: {integrity: sha512-Yt5MKrOosSbSaAK5Y4J+vSiID57sOvpBNBR6K7xAaQvk3MkcNVV0f9fE20T+41WYN8hDn6SGFlFrKudtx4EoxA==} + '@rollup/rollup-android-arm64@4.57.1': + resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.44.2': - resolution: {integrity: sha512-EsnFot9ZieM35YNA26nhbLTJBHD0jTwWpPwmRVDzjylQT6gkar+zenfb8mHxWpRrbn+WytRRjE0WKsfaxBkVUA==} + '@rollup/rollup-darwin-arm64@4.57.1': + resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.44.2': - resolution: {integrity: sha512-dv/t1t1RkCvJdWWxQ2lWOO+b7cMsVw5YFaS04oHpZRWehI1h0fV1gF4wgGCTyQHHjJDfbNpwOi6PXEafRBBezw==} + '@rollup/rollup-darwin-x64@4.57.1': + resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.44.2': - resolution: {integrity: sha512-W4tt4BLorKND4qeHElxDoim0+BsprFTwb+vriVQnFFtT/P6v/xO5I99xvYnVzKWrK6j7Hb0yp3x7V5LUbaeOMg==} + '@rollup/rollup-freebsd-arm64@4.57.1': + resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.44.2': - resolution: {integrity: sha512-tdT1PHopokkuBVyHjvYehnIe20fxibxFCEhQP/96MDSOcyjM/shlTkZZLOufV3qO6/FQOSiJTBebhVc12JyPTA==} + '@rollup/rollup-freebsd-x64@4.57.1': + resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.44.2': - resolution: {integrity: sha512-+xmiDGGaSfIIOXMzkhJ++Oa0Gwvl9oXUeIiwarsdRXSe27HUIvjbSIpPxvnNsRebsNdUo7uAiQVgBD1hVriwSQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.44.2': - resolution: {integrity: sha512-bDHvhzOfORk3wt8yxIra8N4k/N0MnKInCW5OGZaeDYa/hMrdPaJzo7CSkjKZqX4JFUWjUGm88lI6QJLCM7lDrA==} + '@rollup/rollup-linux-arm-musleabihf@4.57.1': + resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.44.2': - resolution: {integrity: sha512-NMsDEsDiYghTbeZWEGnNi4F0hSbGnsuOG+VnNvxkKg0IGDvFh7UVpM/14mnMwxRxUf9AdAVJgHPvKXf6FpMB7A==} + '@rollup/rollup-linux-arm64-gnu@4.57.1': + resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.44.2': - resolution: {integrity: sha512-lb5bxXnxXglVq+7imxykIp5xMq+idehfl+wOgiiix0191av84OqbjUED+PRC5OA8eFJYj5xAGcpAZ0pF2MnW+A==} + '@rollup/rollup-linux-arm64-musl@4.57.1': + resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.44.2': - resolution: {integrity: sha512-Yl5Rdpf9pIc4GW1PmkUGHdMtbx0fBLE1//SxDmuf3X0dUC57+zMepow2LK0V21661cjXdTn8hO2tXDdAWAqE5g==} + '@rollup/rollup-linux-loong64-gnu@4.57.1': + resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.57.1': + resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.44.2': - resolution: {integrity: sha512-03vUDH+w55s680YYryyr78jsO1RWU9ocRMaeV2vMniJJW/6HhoTBwyyiiTPVHNWLnhsnwcQ0oH3S9JSBEKuyqw==} + '@rollup/rollup-linux-ppc64-gnu@4.57.1': + resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.44.2': - resolution: {integrity: sha512-iYtAqBg5eEMG4dEfVlkqo05xMOk6y/JXIToRca2bAWuqjrJYJlx/I7+Z+4hSrsWU8GdJDFPL4ktV3dy4yBSrzg==} + '@rollup/rollup-linux-ppc64-musl@4.57.1': + resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.57.1': + resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.44.2': - resolution: {integrity: sha512-e6vEbgaaqz2yEHqtkPXa28fFuBGmUJ0N2dOJK8YUfijejInt9gfCSA7YDdJ4nYlv67JfP3+PSWFX4IVw/xRIPg==} + '@rollup/rollup-linux-riscv64-musl@4.57.1': + resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.44.2': - resolution: {integrity: sha512-evFOtkmVdY3udE+0QKrV5wBx7bKI0iHz5yEVx5WqDJkxp9YQefy4Mpx3RajIVcM6o7jxTvVd/qpC1IXUhGc1Mw==} + '@rollup/rollup-linux-s390x-gnu@4.57.1': + resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.44.2': - resolution: {integrity: sha512-/bXb0bEsWMyEkIsUL2Yt5nFB5naLAwyOWMEviQfQY1x3l5WsLKgvZf66TM7UTfED6erckUVUJQ/jJ1FSpm3pRQ==} + '@rollup/rollup-linux-x64-gnu@4.57.1': + resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.44.2': - resolution: {integrity: sha512-3D3OB1vSSBXmkGEZR27uiMRNiwN08/RVAcBKwhUYPaiZ8bcvdeEwWPvbnXvvXHY+A/7xluzcN+kaiOFNiOZwWg==} + '@rollup/rollup-linux-x64-musl@4.57.1': + resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.44.2': - resolution: {integrity: sha512-VfU0fsMK+rwdK8mwODqYeM2hDrF2WiHaSmCBrS7gColkQft95/8tphyzv2EupVxn3iE0FI78wzffoULH1G+dkw==} + '@rollup/rollup-openbsd-x64@4.57.1': + resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.57.1': + resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.57.1': + resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.44.2': - resolution: {integrity: sha512-+qMUrkbUurpE6DVRjiJCNGZBGo9xM4Y0FXU5cjgudWqIBWbcLkjE3XprJUsOFgC6xjBClwVa9k6O3A7K3vxb5Q==} + '@rollup/rollup-win32-ia32-msvc@4.57.1': + resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.44.2': - resolution: {integrity: sha512-3+QZROYfJ25PDcxFF66UEk8jGWigHJeecZILvkPkyQN7oc5BvFo4YEXFkOs154j3FTMp9mn9Ky8RCOwastduEA==} + '@rollup/rollup-win32-x64-gnu@4.57.1': + resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.57.1': + resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} cpu: [x64] os: [win32] @@ -693,6 +700,9 @@ packages: resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + '@svgr/babel-plugin-add-jsx-attribute@8.0.0': resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} engines: {node: '>=14'} @@ -761,65 +771,65 @@ packages: peerDependencies: '@svgr/core': '*' - '@tailwindcss/node@4.1.11': - resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==} + '@tailwindcss/node@4.1.18': + resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} - '@tailwindcss/oxide-android-arm64@4.1.11': - resolution: {integrity: sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==} + '@tailwindcss/oxide-android-arm64@4.1.18': + resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.11': - resolution: {integrity: sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==} + '@tailwindcss/oxide-darwin-arm64@4.1.18': + resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.11': - resolution: {integrity: sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==} + '@tailwindcss/oxide-darwin-x64@4.1.18': + resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.11': - resolution: {integrity: sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==} + '@tailwindcss/oxide-freebsd-x64@4.1.18': + resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': - resolution: {integrity: sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': - resolution: {integrity: sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==} + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.1.11': - resolution: {integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==} + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.1.11': - resolution: {integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==} + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.1.11': - resolution: {integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==} + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-wasm32-wasi@4.1.11': - resolution: {integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==} + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -830,24 +840,24 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': - resolution: {integrity: sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==} + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.11': - resolution: {integrity: sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==} + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.11': - resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==} + '@tailwindcss/oxide@4.1.18': + resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} engines: {node: '>= 10'} - '@tailwindcss/vite@4.1.11': - resolution: {integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==} + '@tailwindcss/vite@4.1.18': + resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} peerDependencies: vite: ^5.2.0 || ^6 || ^7 @@ -863,8 +873,8 @@ packages: '@tanstack/query-core@5.90.20': resolution: {integrity: sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==} - '@tanstack/react-query@5.90.20': - resolution: {integrity: sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw==} + '@tanstack/react-query@5.90.21': + resolution: {integrity: sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==} peerDependencies: react: ^18 || ^19 @@ -877,11 +887,8 @@ packages: '@types/babel__template@7.4.4': resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - '@types/babel__traverse@7.20.7': - resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} - - '@types/conventional-commits-parser@5.0.2': - resolution: {integrity: sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==} + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -889,37 +896,31 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/node@24.2.1': - resolution: {integrity: sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==} + '@types/node@24.10.13': + resolution: {integrity: sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==} - '@types/react-dom@19.1.6': - resolution: {integrity: sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==} + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: - '@types/react': ^19.0.0 + '@types/react': ^19.2.0 - '@types/react@19.1.8': - resolution: {integrity: sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==} + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - '@typescript-eslint/eslint-plugin@8.35.1': - resolution: {integrity: sha512-9XNTlo7P7RJxbVeICaIIIEipqxLKguyh+3UbXuT2XQuFp6d8VOeDEGuz5IiX0dgZo8CiI6aOFLg4e8cF71SFVg==} + '@typescript-eslint/eslint-plugin@8.55.0': + resolution: {integrity: sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.35.1 + '@typescript-eslint/parser': ^8.55.0 eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.35.1': - resolution: {integrity: sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==} + '@typescript-eslint/parser@8.55.0': + resolution: {integrity: sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - - '@typescript-eslint/project-service@8.35.1': - resolution: {integrity: sha512-VYxn/5LOpVxADAuP3NrnxxHYfzVtQzLKeldIhDhzC8UHaiQvYlXvKuVho1qLduFbJjjy5U5bkGwa3rUGUb1Q6Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/project-service@8.55.0': resolution: {integrity: sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ==} @@ -927,60 +928,33 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.35.1': - resolution: {integrity: sha512-s/Bpd4i7ht2934nG+UoSPlYXd08KYz3bmjLEb7Ye1UVob0d1ENiT3lY8bsCmik4RqfSbPw9xJJHbugpPpP5JUg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.55.0': resolution: {integrity: sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.35.1': - resolution: {integrity: sha512-K5/U9VmT9dTHoNowWZpz+/TObS3xqC5h0xAIjXPw+MNcKV9qg6eSatEnmeAwkjHijhACH0/N7bkhKvbt1+DXWQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/tsconfig-utils@8.55.0': resolution: {integrity: sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.35.1': - resolution: {integrity: sha512-HOrUBlfVRz5W2LIKpXzZoy6VTZzMu2n8q9C2V/cFngIC5U1nStJgv0tMV4sZPzdf4wQm9/ToWUFPMN9Vq9VJQQ==} + '@typescript-eslint/type-utils@8.55.0': + resolution: {integrity: sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - - '@typescript-eslint/types@8.35.1': - resolution: {integrity: sha512-q/O04vVnKHfrrhNAscndAn1tuQhIkwqnaW+eu5waD5IPts2eX1dgJxgqcPx5BX109/qAz7IG6VrEPTOYKCNfRQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/types@8.55.0': resolution: {integrity: sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.35.1': - resolution: {integrity: sha512-Vvpuvj4tBxIka7cPs6Y1uvM7gJgdF5Uu9F+mBJBPY4MhvjrjWGK4H0lVgLJd/8PWZ23FTqsaJaLEkBCFUk8Y9g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/typescript-estree@8.55.0': resolution: {integrity: sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.35.1': - resolution: {integrity: sha512-lhnwatFmOFcazAsUm3ZnZFpXSxiwoa1Lj50HphnDe1Et01NF4+hrdXONSUHIcbVu2eFb1bAf+5yjXkGVkXBKAQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.55.0': resolution: {integrity: sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -988,38 +962,30 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.35.1': - resolution: {integrity: sha512-VRwixir4zBWCSTP/ljEo091lbpypz57PoeAQ9imjG+vbeof9LplljsL1mos4ccG6H9IjfrVGM359RozUnuFhpw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.55.0': resolution: {integrity: sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitejs/plugin-react@4.6.0': - resolution: {integrity: sha512-5Kgff+m8e2PB+9j51eGHEpn5kUzRKH2Ry0qGoe8ItJg7pqnkPrYPkDQZGgGmTa0EGarHrkjLvOdU3b1fzI8otQ==} + '@vitejs/plugin-react@4.7.0': + resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - '@vue/compiler-core@3.5.27': - resolution: {integrity: sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==} + '@vue/compiler-core@3.5.28': + resolution: {integrity: sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==} - '@vue/compiler-dom@3.5.27': - resolution: {integrity: sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==} + '@vue/compiler-dom@3.5.28': + resolution: {integrity: sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA==} - '@vue/compiler-sfc@3.5.27': - resolution: {integrity: sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==} + '@vue/compiler-sfc@3.5.28': + resolution: {integrity: sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==} - '@vue/compiler-ssr@3.5.27': - resolution: {integrity: sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==} + '@vue/compiler-ssr@3.5.28': + resolution: {integrity: sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g==} - '@vue/shared@3.5.27': - resolution: {integrity: sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==} - - JSONStream@1.3.5: - resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} - hasBin: true + '@vue/shared@3.5.28': + resolution: {integrity: sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -1058,12 +1024,16 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - axios@1.13.4: - resolution: {integrity: sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==} + axios@1.13.5: + resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + baseline-browser-mapping@2.9.19: + resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} + hasBin: true + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1074,8 +1044,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.25.1: - resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==} + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -1091,25 +1061,17 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001727: - resolution: {integrity: sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==} + caniuse-lite@1.0.30001769: + resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chalk@5.6.2: - resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} - chownr@3.0.0: - resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} - engines: {node: '>=18'} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -1135,24 +1097,24 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - conventional-changelog-angular@7.0.0: - resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} - engines: {node: '>=16'} + conventional-changelog-angular@8.1.0: + resolution: {integrity: sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==} + engines: {node: '>=18'} - conventional-changelog-conventionalcommits@7.0.2: - resolution: {integrity: sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==} - engines: {node: '>=16'} + conventional-changelog-conventionalcommits@9.1.0: + resolution: {integrity: sha512-MnbEysR8wWa8dAEvbj5xcBgJKQlX/m0lhS8DsyAAWDHdfs2faDJxTgzRYlRYpXSe7UiKrIIlB4TrBKU9q9DgkA==} + engines: {node: '>=18'} - conventional-commits-parser@5.0.0: - resolution: {integrity: sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==} - engines: {node: '>=16'} + conventional-commits-parser@6.2.1: + resolution: {integrity: sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==} + engines: {node: '>=18'} hasBin: true convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie@1.0.2: - resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} cosmiconfig-typescript-loader@6.2.0: @@ -1185,22 +1147,13 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} dargs@8.1.0: resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} engines: {node: '>=12'} - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1217,8 +1170,8 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} detective-amd@6.0.1: @@ -1279,8 +1232,8 @@ packages: resolution: {integrity: sha512-QkZboRN28K/iwxigDhlJcI3ux3aNbt8kYGGH/GkqWG0OlGeyuBhb7PdM89Iu+ogV8Lmz16xIlwnXR2UNWI6psg==} engines: {node: '>=11.0.0'} - electron-to-chromium@1.5.179: - resolution: {integrity: sha512-UWKi/EbBopgfFsc5k61wFpV7WrnnSlSzW/e2XcBmS6qKYTivZlLtoll5/rdqRTxGglGHkmkW0j0pFNJG10EUIQ==} + electron-to-chromium@1.5.286: + resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1289,24 +1242,24 @@ packages: resolution: {integrity: sha512-rsPft6CK3eHtrlp9Y5ALBb+hfK+DWnA4WFebbazxjWyx8vSm3rZeoM3z9irsjcqO3PYRzlfv27XIB4tz2DV7RA==} engines: {node: '>=14'} - enhanced-resolve@5.18.2: - resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==} + enhanced-resolve@5.19.0: + resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} engines: {node: '>=10.13.0'} entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - entities@7.0.0: - resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} @@ -1324,8 +1277,8 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - esbuild@0.25.5: - resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} engines: {node: '>=18'} hasBin: true @@ -1348,8 +1301,8 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - eslint-plugin-react-refresh@0.4.20: - resolution: {integrity: sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==} + eslint-plugin-react-refresh@0.4.26: + resolution: {integrity: sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==} peerDependencies: eslint: '>=8.40' @@ -1365,8 +1318,8 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.30.1: - resolution: {integrity: sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==} + eslint@9.39.2: + resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -1384,8 +1337,8 @@ packages: engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -1423,16 +1376,8 @@ packages: resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} engines: {node: '>= 4.9.1'} - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} - - fdir@6.4.6: - resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -1455,10 +1400,6 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - find-up@7.0.0: - resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} - engines: {node: '>=18'} - flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -1528,8 +1469,8 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globals@16.3.0: - resolution: {integrity: sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==} + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} globby@14.1.0: @@ -1551,9 +1492,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -1619,9 +1557,9 @@ packages: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} - is-text-path@2.0.0: - resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} - engines: {node: '>=8'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} is-url-superb@4.0.0: resolution: {integrity: sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA==} @@ -1640,8 +1578,8 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true jsesc@3.1.0: @@ -1669,10 +1607,6 @@ packages: engines: {node: '>=6'} hasBin: true - jsonparse@1.3.1: - resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} - engines: {'0': node >= 0.2.0} - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -1680,68 +1614,74 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-darwin-arm64@1.30.1: - resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.30.1: - resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.30.1: - resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.30.1: - resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.30.1: - resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-arm64-musl@1.30.1: - resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-x64-gnu@1.30.1: - resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-linux-x64-musl@1.30.1: - resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-win32-arm64-msvc@1.30.1: - resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.30.1: - resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.30.1: - resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} lines-and-columns@1.2.4: @@ -1751,19 +1691,12 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - locate-path@7.2.0: - resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - lodash-es@4.17.22: - resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==} + lodash-es@4.17.23: + resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - lodash.kebabcase@4.1.1: resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} @@ -1779,9 +1712,6 @@ packages: lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - lodash.uniq@4.5.0: - resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} - lodash.upperfirst@4.3.1: resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} @@ -1791,9 +1721,6 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -1805,6 +1732,10 @@ packages: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} + meow@13.2.0: + resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} + engines: {node: '>=18'} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1831,19 +1762,6 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} - - minizlib@3.0.2: - resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} - engines: {node: '>= 18'} - - mkdirp@3.0.1: - resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} - engines: {node: '>=10'} - hasBin: true - module-definition@6.0.1: resolution: {integrity: sha512-FeVc50FTfVVQnolk/WQT8MX+2WVcDnTGiq6Wo+/+lJ2ET1bRVi3HG3YlJUfqagNMc/kUlFSoR96AJkxGpKz13g==} engines: {node: '>=18'} @@ -1863,8 +1781,8 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} node-source-walk@7.0.1: resolution: {integrity: sha512-3VW/8JpPqPvnJvseXowjZcirPisssnBuDikk6JIZ8jQzF7KJQX52iPFX4RYYxLycYH7IbMRSPUOga/esVjy5Yg==} @@ -1878,18 +1796,10 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-limit@4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-locate@6.0.0: - resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -1902,10 +1812,6 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-exists@5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1930,10 +1836,6 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} - picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} @@ -2022,8 +1924,8 @@ packages: prettier-plugin-svelte: optional: true - prettier@3.6.2: - resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} engines: {node: '>=14'} hasBin: true @@ -2044,10 +1946,10 @@ packages: quote-unquote@1.0.0: resolution: {integrity: sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==} - react-dom@19.1.0: - resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: - react: ^19.1.0 + react: ^19.2.4 react-hook-form@7.71.1: resolution: {integrity: sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==} @@ -2059,15 +1961,15 @@ packages: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} - react-router-dom@7.6.3: - resolution: {integrity: sha512-DiWJm9qdUAmiJrVWaeJdu4TKu13+iB/8IEi0EW/XgaHCjW/vWGrwzup0GVvaMteuZjKnh5bEvJP/K0MDnzawHw==} + react-router-dom@7.13.0: + resolution: {integrity: sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' react-dom: '>=18' - react-router@7.6.3: - resolution: {integrity: sha512-zf45LZp5skDC6I3jDLXQUu0u26jtuP4lEGbc7BbdyxenBN1vJSTA18czM2D+h5qyMBuMrD+9uB+mU37HIoKGRA==} + react-router@7.13.0: + resolution: {integrity: sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -2076,8 +1978,8 @@ packages: react-dom: optional: true - react@19.1.0: - resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} readdirp@4.1.2: @@ -2104,28 +2006,28 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rollup@4.44.2: - resolution: {integrity: sha512-PVoapzTwSEcelaWGth3uR66u7ZRo6qhPHc0f2uRO9fX6XDVNrIiGYS0Pj9+R8yIIYSD/mCx2b16Ws9itljKSPg==} + rollup@4.57.1: + resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - scheduler@0.26.0: - resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true - set-cookie-parser@2.7.1: - resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -2197,33 +2099,17 @@ packages: tailwind-merge: optional: true - tailwindcss@4.1.11: - resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==} + tailwindcss@4.1.18: + resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} - tapable@2.2.2: - resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} - tar@7.4.3: - resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} - engines: {node: '>=18'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me - - text-extensions@2.4.0: - resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} - engines: {node: '>=8'} - - through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} - tinyglobby@0.2.14: - resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -2232,12 +2118,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - ts-api-utils@2.4.0: resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} engines: {node: '>=18.12'} @@ -2265,31 +2145,27 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.35.1: - resolution: {integrity: sha512-xslJjFzhOmHYQzSB/QTeASAHbjmxOGEP6Coh93TXmUBFQoJ1VU35UHIDmG06Jd6taf3wqqC1ntBnCMeymy5Ovw==} + typescript-eslint@8.55.0: + resolution: {integrity: sha512-HE4wj+r5lmDVS9gdaN0/+iqNvPZwGfnJ5lZuz7s5vLlg9ODw0bIiiETaios9LvFI1U94/VBXGm3CB2Y5cNFMpw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' typescript@5.8.3: resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} hasBin: true - undici-types@7.10.0: - resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} - - unicorn-magic@0.1.0: - resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} - engines: {node: '>=18'} + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} unicorn-magic@0.3.0: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -2297,8 +2173,8 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - vite-plugin-svgr@4.3.0: - resolution: {integrity: sha512-Jy9qLB2/PyWklpYy0xk0UU3TlU0t2UMpJXZvf+hWII1lAmRHrOUKi11Uw8N3rxoNk7atZNYO3pR3vI1f7oi+6w==} + vite-plugin-svgr@4.5.0: + resolution: {integrity: sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA==} peerDependencies: vite: '>=2.6.0' @@ -2310,8 +2186,8 @@ packages: vite: optional: true - vite@7.0.2: - resolution: {integrity: sha512-hxdyZDY1CM6SNpKI4w4lcUc3Mtkd9ej4ECWVHSMrOdSinVc2zYOAppHeGc/hzmRo3pxM5blMzkuWHOJA/3NiFw==} + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -2370,10 +2246,6 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yallist@5.0.0: - resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} - engines: {node: '>=18'} - yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -2386,10 +2258,6 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-queue@1.2.2: - resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} - engines: {node: '>=12.20'} - zod-validation-error@3.5.4: resolution: {integrity: sha512-+hEiRIiPobgyuFlEojnqjJnhFvg4r/i3cqgcm67eehZf/WBaK3g6cD02YU9mtdVxZjv8CzCA9n/Rhrs3yAAvAw==} engines: {node: '>=18.0.0'} @@ -2399,8 +2267,11 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zustand@5.0.10: - resolution: {integrity: sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + + zustand@5.0.11: + resolution: {integrity: sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==} engines: {node: '>=12.20.0'} peerDependencies: '@types/react': '>=18.0.0' @@ -2419,130 +2290,114 @@ packages: snapshots: - '@ampproject/remapping@2.3.0': - dependencies: - '@jridgewell/gen-mapping': 0.3.12 - '@jridgewell/trace-mapping': 0.3.29 - - '@babel/code-frame@7.27.1': + '@babel/code-frame@7.29.0': dependencies: - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.0': {} + '@babel/compat-data@7.29.0': {} - '@babel/core@7.28.0': + '@babel/core@7.29.0': dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.0 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0) - '@babel/helpers': 7.27.6 - '@babel/parser': 7.28.0 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.0 - '@babel/types': 7.28.0 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.1 + debug: 4.4.3 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/generator@7.28.0': + '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.28.0 - '@babel/types': 7.28.0 - '@jridgewell/gen-mapping': 0.3.12 - '@jridgewell/trace-mapping': 0.3.29 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.27.2': + '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.28.0 + '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.25.1 + browserslist: 4.28.1 lru-cache: 5.1.1 semver: 6.3.1 '@babel/helper-globals@7.28.0': {} - '@babel/helper-module-imports@7.27.1': + '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/traverse': 7.28.0 - '@babel/types': 7.28.0 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.27.3(@babel/core@7.28.0)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.0 + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-plugin-utils@7.28.6': {} '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.27.1': {} - '@babel/helper-validator-identifier@7.28.5': {} '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.27.6': + '@babel/helpers@7.28.6': dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 - '@babel/parser@7.28.0': + '@babel/parser@7.29.0': dependencies: - '@babel/types': 7.28.0 + '@babel/types': 7.29.0 - '@babel/parser@7.28.6': + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/types': 7.28.6 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.0)': + '@babel/template@7.28.6': dependencies: - '@babel/core': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 - '@babel/template@7.27.2': + '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.0 - '@babel/types': 7.28.0 - - '@babel/traverse@7.28.0': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.0 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.0 - '@babel/template': 7.27.2 - '@babel/types': 7.28.0 - debug: 4.4.1 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - - '@babel/types@7.28.6': + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 @@ -2558,32 +2413,32 @@ snapshots: picocolors: 1.1.1 sisteransi: 1.0.5 - '@commitlint/cli@20.3.0(@types/node@24.2.1)(typescript@5.8.3)': + '@commitlint/cli@20.4.1(@types/node@24.10.13)(typescript@5.8.3)': dependencies: - '@commitlint/format': 20.2.0 - '@commitlint/lint': 20.3.0 - '@commitlint/load': 20.3.0(@types/node@24.2.1)(typescript@5.8.3) - '@commitlint/read': 20.2.0 - '@commitlint/types': 20.2.0 + '@commitlint/format': 20.4.0 + '@commitlint/lint': 20.4.1 + '@commitlint/load': 20.4.0(@types/node@24.10.13)(typescript@5.8.3) + '@commitlint/read': 20.4.0 + '@commitlint/types': 20.4.0 tinyexec: 1.0.2 yargs: 17.7.2 transitivePeerDependencies: - '@types/node' - typescript - '@commitlint/config-conventional@20.3.0': + '@commitlint/config-conventional@20.4.1': dependencies: - '@commitlint/types': 20.2.0 - conventional-changelog-conventionalcommits: 7.0.2 + '@commitlint/types': 20.4.0 + conventional-changelog-conventionalcommits: 9.1.0 - '@commitlint/config-validator@20.2.0': + '@commitlint/config-validator@20.4.0': dependencies: - '@commitlint/types': 20.2.0 + '@commitlint/types': 20.4.0 ajv: 8.17.1 - '@commitlint/ensure@20.2.0': + '@commitlint/ensure@20.4.1': dependencies: - '@commitlint/types': 20.2.0 + '@commitlint/types': 20.4.0 lodash.camelcase: 4.3.0 lodash.kebabcase: 4.1.1 lodash.snakecase: 4.1.1 @@ -2592,238 +2447,233 @@ snapshots: '@commitlint/execute-rule@20.0.0': {} - '@commitlint/format@20.2.0': + '@commitlint/format@20.4.0': dependencies: - '@commitlint/types': 20.2.0 - chalk: 5.6.2 + '@commitlint/types': 20.4.0 + picocolors: 1.1.1 - '@commitlint/is-ignored@20.2.0': + '@commitlint/is-ignored@20.4.1': dependencies: - '@commitlint/types': 20.2.0 - semver: 7.7.3 + '@commitlint/types': 20.4.0 + semver: 7.7.4 - '@commitlint/lint@20.3.0': + '@commitlint/lint@20.4.1': dependencies: - '@commitlint/is-ignored': 20.2.0 - '@commitlint/parse': 20.2.0 - '@commitlint/rules': 20.3.0 - '@commitlint/types': 20.2.0 + '@commitlint/is-ignored': 20.4.1 + '@commitlint/parse': 20.4.1 + '@commitlint/rules': 20.4.1 + '@commitlint/types': 20.4.0 - '@commitlint/load@20.3.0(@types/node@24.2.1)(typescript@5.8.3)': + '@commitlint/load@20.4.0(@types/node@24.10.13)(typescript@5.8.3)': dependencies: - '@commitlint/config-validator': 20.2.0 + '@commitlint/config-validator': 20.4.0 '@commitlint/execute-rule': 20.0.0 - '@commitlint/resolve-extends': 20.2.0 - '@commitlint/types': 20.2.0 - chalk: 5.6.2 + '@commitlint/resolve-extends': 20.4.0 + '@commitlint/types': 20.4.0 cosmiconfig: 9.0.0(typescript@5.8.3) - cosmiconfig-typescript-loader: 6.2.0(@types/node@24.2.1)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3) - lodash.isplainobject: 4.0.6 - lodash.merge: 4.6.2 - lodash.uniq: 4.5.0 + cosmiconfig-typescript-loader: 6.2.0(@types/node@24.10.13)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3) + is-plain-obj: 4.1.0 + lodash.mergewith: 4.6.2 + picocolors: 1.1.1 transitivePeerDependencies: - '@types/node' - typescript - '@commitlint/message@20.0.0': {} + '@commitlint/message@20.4.0': {} - '@commitlint/parse@20.2.0': + '@commitlint/parse@20.4.1': dependencies: - '@commitlint/types': 20.2.0 - conventional-changelog-angular: 7.0.0 - conventional-commits-parser: 5.0.0 + '@commitlint/types': 20.4.0 + conventional-changelog-angular: 8.1.0 + conventional-commits-parser: 6.2.1 - '@commitlint/read@20.2.0': + '@commitlint/read@20.4.0': dependencies: - '@commitlint/top-level': 20.0.0 - '@commitlint/types': 20.2.0 + '@commitlint/top-level': 20.4.0 + '@commitlint/types': 20.4.0 git-raw-commits: 4.0.0 minimist: 1.2.8 tinyexec: 1.0.2 - '@commitlint/resolve-extends@20.2.0': + '@commitlint/resolve-extends@20.4.0': dependencies: - '@commitlint/config-validator': 20.2.0 - '@commitlint/types': 20.2.0 + '@commitlint/config-validator': 20.4.0 + '@commitlint/types': 20.4.0 global-directory: 4.0.1 import-meta-resolve: 4.2.0 lodash.mergewith: 4.6.2 resolve-from: 5.0.0 - '@commitlint/rules@20.3.0': + '@commitlint/rules@20.4.1': dependencies: - '@commitlint/ensure': 20.2.0 - '@commitlint/message': 20.0.0 + '@commitlint/ensure': 20.4.1 + '@commitlint/message': 20.4.0 '@commitlint/to-lines': 20.0.0 - '@commitlint/types': 20.2.0 + '@commitlint/types': 20.4.0 '@commitlint/to-lines@20.0.0': {} - '@commitlint/top-level@20.0.0': + '@commitlint/top-level@20.4.0': dependencies: - find-up: 7.0.0 + escalade: 3.2.0 - '@commitlint/types@20.2.0': + '@commitlint/types@20.4.0': dependencies: - '@types/conventional-commits-parser': 5.0.2 - chalk: 5.6.2 + conventional-commits-parser: 6.2.1 + picocolors: 1.1.1 '@dependents/detective-less@5.0.1': dependencies: gonzales-pe: 4.3.0 node-source-walk: 7.0.1 - '@dnd-kit/accessibility@3.1.1(react@19.1.0)': + '@dnd-kit/accessibility@3.1.1(react@19.2.4)': dependencies: - react: 19.1.0 + react: 19.2.4 tslib: 2.8.1 - '@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@dnd-kit/core@6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@dnd-kit/accessibility': 3.1.1(react@19.1.0) - '@dnd-kit/utilities': 3.2.2(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@dnd-kit/accessibility': 3.1.1(react@19.2.4) + '@dnd-kit/utilities': 3.2.2(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) tslib: 2.8.1 - '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)': + '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': dependencies: - '@dnd-kit/core': 6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@dnd-kit/utilities': 3.2.2(react@19.1.0) - react: 19.1.0 + '@dnd-kit/core': 6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@dnd-kit/utilities': 3.2.2(react@19.2.4) + react: 19.2.4 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.1.0)': + '@dnd-kit/utilities@3.2.2(react@19.2.4)': dependencies: - react: 19.1.0 + react: 19.2.4 tslib: 2.8.1 - '@esbuild/aix-ppc64@0.25.5': + '@esbuild/aix-ppc64@0.27.3': optional: true - '@esbuild/android-arm64@0.25.5': + '@esbuild/android-arm64@0.27.3': optional: true - '@esbuild/android-arm@0.25.5': + '@esbuild/android-arm@0.27.3': optional: true - '@esbuild/android-x64@0.25.5': + '@esbuild/android-x64@0.27.3': optional: true - '@esbuild/darwin-arm64@0.25.5': + '@esbuild/darwin-arm64@0.27.3': optional: true - '@esbuild/darwin-x64@0.25.5': + '@esbuild/darwin-x64@0.27.3': optional: true - '@esbuild/freebsd-arm64@0.25.5': + '@esbuild/freebsd-arm64@0.27.3': optional: true - '@esbuild/freebsd-x64@0.25.5': + '@esbuild/freebsd-x64@0.27.3': optional: true - '@esbuild/linux-arm64@0.25.5': + '@esbuild/linux-arm64@0.27.3': optional: true - '@esbuild/linux-arm@0.25.5': + '@esbuild/linux-arm@0.27.3': optional: true - '@esbuild/linux-ia32@0.25.5': + '@esbuild/linux-ia32@0.27.3': optional: true - '@esbuild/linux-loong64@0.25.5': + '@esbuild/linux-loong64@0.27.3': optional: true - '@esbuild/linux-mips64el@0.25.5': + '@esbuild/linux-mips64el@0.27.3': optional: true - '@esbuild/linux-ppc64@0.25.5': + '@esbuild/linux-ppc64@0.27.3': optional: true - '@esbuild/linux-riscv64@0.25.5': + '@esbuild/linux-riscv64@0.27.3': optional: true - '@esbuild/linux-s390x@0.25.5': + '@esbuild/linux-s390x@0.27.3': optional: true - '@esbuild/linux-x64@0.25.5': + '@esbuild/linux-x64@0.27.3': optional: true - '@esbuild/netbsd-arm64@0.25.5': + '@esbuild/netbsd-arm64@0.27.3': optional: true - '@esbuild/netbsd-x64@0.25.5': + '@esbuild/netbsd-x64@0.27.3': optional: true - '@esbuild/openbsd-arm64@0.25.5': + '@esbuild/openbsd-arm64@0.27.3': optional: true - '@esbuild/openbsd-x64@0.25.5': + '@esbuild/openbsd-x64@0.27.3': optional: true - '@esbuild/sunos-x64@0.25.5': + '@esbuild/openharmony-arm64@0.27.3': optional: true - '@esbuild/win32-arm64@0.25.5': + '@esbuild/sunos-x64@0.27.3': optional: true - '@esbuild/win32-ia32@0.25.5': + '@esbuild/win32-arm64@0.27.3': optional: true - '@esbuild/win32-x64@0.25.5': + '@esbuild/win32-ia32@0.27.3': optional: true - '@eslint-community/eslint-utils@4.7.0(eslint@9.30.1(jiti@2.6.1))': - dependencies: - eslint: 9.30.1(jiti@2.6.1) - eslint-visitor-keys: 3.4.3 + '@esbuild/win32-x64@0.27.3': + optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.30.1(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': dependencies: - eslint: 9.30.1(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.12.1': {} + '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.0': + '@eslint/config-array@0.21.1': dependencies: - '@eslint/object-schema': 2.1.6 - debug: 4.4.1 + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 minimatch: 3.1.2 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.3.0': {} - - '@eslint/core@0.14.0': + '@eslint/config-helpers@0.4.2': dependencies: - '@types/json-schema': 7.0.15 + '@eslint/core': 0.17.0 - '@eslint/core@0.15.1': + '@eslint/core@0.17.0': dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.1': + '@eslint/eslintrc@3.3.3': dependencies: ajv: 6.12.6 - debug: 4.4.1 + debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 - js-yaml: 4.1.0 + js-yaml: 4.1.1 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/js@9.30.1': {} + '@eslint/js@9.39.2': {} - '@eslint/object-schema@2.1.6': {} + '@eslint/object-schema@2.1.7': {} - '@eslint/plugin-kit@0.3.3': + '@eslint/plugin-kit@0.4.1': dependencies: - '@eslint/core': 0.15.1 + '@eslint/core': 0.17.0 levn: 0.4.1 '@feature-sliced/filesystem@3.0.1': @@ -2834,7 +2684,7 @@ snapshots: dependencies: '@feature-sliced/filesystem': 3.0.1 fastest-levenshtein: 1.0.16 - lodash-es: 4.17.22 + lodash-es: 4.17.23 pluralize: 8.0.0 precinct: 12.2.0 tsconfck: 3.1.6(typescript@5.8.3) @@ -2842,38 +2692,40 @@ snapshots: - supports-color - typescript + '@hookform/resolvers@5.2.2(react-hook-form@7.71.1(react@19.2.4))': + dependencies: + '@standard-schema/utils': 0.3.0 + react-hook-form: 7.71.1(react@19.2.4) + '@humanfs/core@0.19.1': {} - '@humanfs/node@0.16.6': + '@humanfs/node@0.16.7': dependencies: '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.3.1 + '@humanwhocodes/retry': 0.4.3 '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/retry@0.3.1': {} - '@humanwhocodes/retry@0.4.3': {} - '@isaacs/fs-minipass@4.0.1': + '@jridgewell/gen-mapping@0.3.13': dependencies: - minipass: 7.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/gen-mapping@0.3.12': + '@jridgewell/remapping@2.3.5': dependencies: - '@jridgewell/sourcemap-codec': 1.5.4 - '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/sourcemap-codec@1.5.4': {} - '@jridgewell/sourcemap-codec@1.5.5': {} - '@jridgewell/trace-mapping@0.3.29': + '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/sourcemap-codec': 1.5.5 '@nodelib/fs.scandir@2.1.5': dependencies: @@ -2885,128 +2737,145 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 + fastq: 1.20.1 - '@rolldown/pluginutils@1.0.0-beta.19': {} + '@rolldown/pluginutils@1.0.0-beta.27': {} - '@rollup/pluginutils@5.2.0(rollup@4.44.2)': + '@rollup/pluginutils@5.3.0(rollup@4.57.1)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 - picomatch: 4.0.2 + picomatch: 4.0.3 optionalDependencies: - rollup: 4.44.2 + rollup: 4.57.1 + + '@rollup/rollup-android-arm-eabi@4.57.1': + optional: true + + '@rollup/rollup-android-arm64@4.57.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.57.1': + optional: true + + '@rollup/rollup-darwin-x64@4.57.1': + optional: true - '@rollup/rollup-android-arm-eabi@4.44.2': + '@rollup/rollup-freebsd-arm64@4.57.1': optional: true - '@rollup/rollup-android-arm64@4.44.2': + '@rollup/rollup-freebsd-x64@4.57.1': optional: true - '@rollup/rollup-darwin-arm64@4.44.2': + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': optional: true - '@rollup/rollup-darwin-x64@4.44.2': + '@rollup/rollup-linux-arm-musleabihf@4.57.1': optional: true - '@rollup/rollup-freebsd-arm64@4.44.2': + '@rollup/rollup-linux-arm64-gnu@4.57.1': optional: true - '@rollup/rollup-freebsd-x64@4.44.2': + '@rollup/rollup-linux-arm64-musl@4.57.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.44.2': + '@rollup/rollup-linux-loong64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.44.2': + '@rollup/rollup-linux-loong64-musl@4.57.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.44.2': + '@rollup/rollup-linux-ppc64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.44.2': + '@rollup/rollup-linux-ppc64-musl@4.57.1': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.44.2': + '@rollup/rollup-linux-riscv64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.44.2': + '@rollup/rollup-linux-riscv64-musl@4.57.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.44.2': + '@rollup/rollup-linux-s390x-gnu@4.57.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.44.2': + '@rollup/rollup-linux-x64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.44.2': + '@rollup/rollup-linux-x64-musl@4.57.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.44.2': + '@rollup/rollup-openbsd-x64@4.57.1': optional: true - '@rollup/rollup-linux-x64-musl@4.44.2': + '@rollup/rollup-openharmony-arm64@4.57.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.44.2': + '@rollup/rollup-win32-arm64-msvc@4.57.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.44.2': + '@rollup/rollup-win32-ia32-msvc@4.57.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.44.2': + '@rollup/rollup-win32-x64-gnu@4.57.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.57.1': optional: true '@sindresorhus/merge-streams@2.3.0': {} - '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.0)': + '@standard-schema/utils@0.3.0': {} + + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.0)': + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.0)': + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.0)': + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.0)': + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.0)': + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.0)': + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.0)': + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.29.0 - '@svgr/babel-preset@8.1.0(@babel/core@7.28.0)': + '@svgr/babel-preset@8.1.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.0 - '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.0) - '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.0) - '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.0) - '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.0) - '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.0) - '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.0) - '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.0) - '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.0) + '@babel/core': 7.29.0 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.29.0) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.29.0) '@svgr/core@8.1.0(typescript@5.8.3)': dependencies: - '@babel/core': 7.28.0 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.0) + '@babel/core': 7.29.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.0) camelcase: 6.3.0 cosmiconfig: 8.3.6(typescript@5.8.3) snake-case: 3.0.4 @@ -3016,94 +2885,91 @@ snapshots: '@svgr/hast-util-to-babel-ast@8.0.0': dependencies: - '@babel/types': 7.28.0 + '@babel/types': 7.29.0 entities: 4.5.0 '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.8.3))': dependencies: - '@babel/core': 7.28.0 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.0) + '@babel/core': 7.29.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.0) '@svgr/core': 8.1.0(typescript@5.8.3) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: - supports-color - '@tailwindcss/node@4.1.11': + '@tailwindcss/node@4.1.18': dependencies: - '@ampproject/remapping': 2.3.0 - enhanced-resolve: 5.18.2 + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.19.0 jiti: 2.6.1 - lightningcss: 1.30.1 - magic-string: 0.30.17 + lightningcss: 1.30.2 + magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.1.11 + tailwindcss: 4.1.18 - '@tailwindcss/oxide-android-arm64@4.1.11': + '@tailwindcss/oxide-android-arm64@4.1.18': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.11': + '@tailwindcss/oxide-darwin-arm64@4.1.18': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.11': + '@tailwindcss/oxide-darwin-x64@4.1.18': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.11': + '@tailwindcss/oxide-freebsd-x64@4.1.18': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.11': + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.11': + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.11': + '@tailwindcss/oxide-linux-x64-musl@4.1.18': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.11': + '@tailwindcss/oxide-wasm32-wasi@4.1.18': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.11': + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': optional: true - '@tailwindcss/oxide@4.1.11': - dependencies: - detect-libc: 2.0.4 - tar: 7.4.3 + '@tailwindcss/oxide@4.1.18': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.11 - '@tailwindcss/oxide-darwin-arm64': 4.1.11 - '@tailwindcss/oxide-darwin-x64': 4.1.11 - '@tailwindcss/oxide-freebsd-x64': 4.1.11 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.11 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.11 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.11 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.11 - '@tailwindcss/oxide-linux-x64-musl': 4.1.11 - '@tailwindcss/oxide-wasm32-wasi': 4.1.11 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.11 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.11 - - '@tailwindcss/vite@4.1.11(vite@7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1))': - dependencies: - '@tailwindcss/node': 4.1.11 - '@tailwindcss/oxide': 4.1.11 - tailwindcss: 4.1.11 - vite: 7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1) - - '@tanstack/eslint-plugin-query@5.91.4(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3)': - dependencies: - '@typescript-eslint/utils': 8.55.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) - eslint: 9.30.1(jiti@2.6.1) + '@tailwindcss/oxide-android-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-x64': 4.1.18 + '@tailwindcss/oxide-freebsd-x64': 4.1.18 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-x64-musl': 4.1.18 + '@tailwindcss/oxide-wasm32-wasi': 4.1.18 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 + + '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@tailwindcss/node': 4.1.18 + '@tailwindcss/oxide': 4.1.18 + tailwindcss: 4.1.18 + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2) + + '@tanstack/eslint-plugin-query@5.91.4(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) + eslint: 9.39.2(jiti@2.6.1) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -3111,86 +2977,72 @@ snapshots: '@tanstack/query-core@5.90.20': {} - '@tanstack/react-query@5.90.20(react@19.1.0)': + '@tanstack/react-query@5.90.21(react@19.2.4)': dependencies: '@tanstack/query-core': 5.90.20 - react: 19.1.0 + react: 19.2.4 '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.0 - '@babel/types': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.20.7 + '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.0 + '@babel/types': 7.29.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.0 - '@babel/types': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 - '@types/babel__traverse@7.20.7': + '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.0 - - '@types/conventional-commits-parser@5.0.2': - dependencies: - '@types/node': 24.2.1 + '@babel/types': 7.29.0 '@types/estree@1.0.8': {} '@types/json-schema@7.0.15': {} - '@types/node@24.2.1': + '@types/node@24.10.13': dependencies: - undici-types: 7.10.0 + undici-types: 7.16.0 - '@types/react-dom@19.1.6(@types/react@19.1.8)': + '@types/react-dom@19.2.3(@types/react@19.2.14)': dependencies: - '@types/react': 19.1.8 + '@types/react': 19.2.14 - '@types/react@19.1.8': + '@types/react@19.2.14': dependencies: - csstype: 3.1.3 + csstype: 3.2.3 - '@typescript-eslint/eslint-plugin@8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@8.55.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)': dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/scope-manager': 8.35.1 - '@typescript-eslint/type-utils': 8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.35.1 - eslint: 9.30.1(jiti@2.6.1) - graphemer: 1.4.0 + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/type-utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.55.0 + eslint: 9.39.2(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.35.1 - '@typescript-eslint/types': 8.35.1 - '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.35.1 - debug: 4.4.1 - eslint: 9.30.1(jiti@2.6.1) + ts-api-utils: 2.4.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.35.1(typescript@5.8.3)': + '@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.35.1(typescript@5.8.3) - '@typescript-eslint/types': 8.35.1 - debug: 4.4.1 + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.55.0 + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -3204,55 +3056,29 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.35.1': - dependencies: - '@typescript-eslint/types': 8.35.1 - '@typescript-eslint/visitor-keys': 8.35.1 - '@typescript-eslint/scope-manager@8.55.0': dependencies: '@typescript-eslint/types': 8.55.0 '@typescript-eslint/visitor-keys': 8.55.0 - '@typescript-eslint/tsconfig-utils@8.35.1(typescript@5.8.3)': - dependencies: - typescript: 5.8.3 - '@typescript-eslint/tsconfig-utils@8.55.0(typescript@5.8.3)': dependencies: typescript: 5.8.3 - '@typescript-eslint/type-utils@8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.8.3) - '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) - debug: 4.4.1 - eslint: 9.30.1(jiti@2.6.1) - ts-api-utils: 2.1.0(typescript@5.8.3) + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + ts-api-utils: 2.4.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.35.1': {} - '@typescript-eslint/types@8.55.0': {} - '@typescript-eslint/typescript-estree@8.35.1(typescript@5.8.3)': - dependencies: - '@typescript-eslint/project-service': 8.35.1(typescript@5.8.3) - '@typescript-eslint/tsconfig-utils': 8.35.1(typescript@5.8.3) - '@typescript-eslint/types': 8.35.1 - '@typescript-eslint/visitor-keys': 8.35.1 - debug: 4.4.1 - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.3 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/typescript-estree@8.55.0(typescript@5.8.3)': dependencies: '@typescript-eslint/project-service': 8.55.0(typescript@5.8.3) @@ -3261,93 +3087,72 @@ snapshots: '@typescript-eslint/visitor-keys': 8.55.0 debug: 4.4.3 minimatch: 9.0.5 - semver: 7.7.3 + semver: 7.7.4 tinyglobby: 0.2.15 ts-api-utils: 2.4.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3)': - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.35.1 - '@typescript-eslint/types': 8.35.1 - '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.8.3) - eslint: 9.30.1(jiti@2.6.1) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.55.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3)': + '@typescript-eslint/utils@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.30.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) '@typescript-eslint/scope-manager': 8.55.0 '@typescript-eslint/types': 8.55.0 '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.8.3) - eslint: 9.30.1(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.35.1': - dependencies: - '@typescript-eslint/types': 8.35.1 - eslint-visitor-keys: 4.2.1 - '@typescript-eslint/visitor-keys@8.55.0': dependencies: '@typescript-eslint/types': 8.55.0 eslint-visitor-keys: 4.2.1 - '@vitejs/plugin-react@4.6.0(vite@7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1))': + '@vitejs/plugin-react@4.7.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2))': dependencies: - '@babel/core': 7.28.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.0) - '@rolldown/pluginutils': 1.0.0-beta.19 + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2) transitivePeerDependencies: - supports-color - '@vue/compiler-core@3.5.27': + '@vue/compiler-core@3.5.28': dependencies: - '@babel/parser': 7.28.6 - '@vue/shared': 3.5.27 - entities: 7.0.0 + '@babel/parser': 7.29.0 + '@vue/shared': 3.5.28 + entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.27': + '@vue/compiler-dom@3.5.28': dependencies: - '@vue/compiler-core': 3.5.27 - '@vue/shared': 3.5.27 + '@vue/compiler-core': 3.5.28 + '@vue/shared': 3.5.28 - '@vue/compiler-sfc@3.5.27': + '@vue/compiler-sfc@3.5.28': dependencies: - '@babel/parser': 7.28.6 - '@vue/compiler-core': 3.5.27 - '@vue/compiler-dom': 3.5.27 - '@vue/compiler-ssr': 3.5.27 - '@vue/shared': 3.5.27 + '@babel/parser': 7.29.0 + '@vue/compiler-core': 3.5.28 + '@vue/compiler-dom': 3.5.28 + '@vue/compiler-ssr': 3.5.28 + '@vue/shared': 3.5.28 estree-walker: 2.0.2 magic-string: 0.30.21 postcss: 8.5.6 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.27': + '@vue/compiler-ssr@3.5.28': dependencies: - '@vue/compiler-dom': 3.5.27 - '@vue/shared': 3.5.27 + '@vue/compiler-dom': 3.5.28 + '@vue/shared': 3.5.28 - '@vue/shared@3.5.27': {} - - JSONStream@1.3.5: - dependencies: - jsonparse: 1.3.1 - through: 2.3.8 + '@vue/shared@3.5.28': {} acorn-jsx@5.3.2(acorn@8.15.0): dependencies: @@ -3383,7 +3188,7 @@ snapshots: asynckit@0.4.0: {} - axios@1.13.4: + axios@1.13.5: dependencies: follow-redirects: 1.15.11 form-data: 4.0.5 @@ -3393,6 +3198,8 @@ snapshots: balanced-match@1.0.2: {} + baseline-browser-mapping@2.9.19: {} + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -3406,12 +3213,13 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.25.1: + browserslist@4.28.1: dependencies: - caniuse-lite: 1.0.30001727 - electron-to-chromium: 1.5.179 - node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.25.1) + baseline-browser-mapping: 2.9.19 + caniuse-lite: 1.0.30001769 + electron-to-chromium: 1.5.286 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) call-bind-apply-helpers@1.0.2: dependencies: @@ -3422,21 +3230,17 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001727: {} + caniuse-lite@1.0.30001769: {} chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - chalk@5.6.2: {} - chokidar@4.0.3: dependencies: readdirp: 4.1.2 - chownr@3.0.0: {} - cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -3462,28 +3266,25 @@ snapshots: concat-map@0.0.1: {} - conventional-changelog-angular@7.0.0: + conventional-changelog-angular@8.1.0: dependencies: compare-func: 2.0.0 - conventional-changelog-conventionalcommits@7.0.2: + conventional-changelog-conventionalcommits@9.1.0: dependencies: compare-func: 2.0.0 - conventional-commits-parser@5.0.0: + conventional-commits-parser@6.2.1: dependencies: - JSONStream: 1.3.5 - is-text-path: 2.0.0 - meow: 12.1.1 - split2: 4.2.0 + meow: 13.2.0 convert-source-map@2.0.0: {} - cookie@1.0.2: {} + cookie@1.1.1: {} - cosmiconfig-typescript-loader@6.2.0(@types/node@24.2.1)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3): + cosmiconfig-typescript-loader@6.2.0(@types/node@24.10.13)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3): dependencies: - '@types/node': 24.2.1 + '@types/node': 24.10.13 cosmiconfig: 9.0.0(typescript@5.8.3) jiti: 2.6.1 typescript: 5.8.3 @@ -3491,7 +3292,7 @@ snapshots: cosmiconfig@8.3.6(typescript@5.8.3): dependencies: import-fresh: 3.3.1 - js-yaml: 4.1.0 + js-yaml: 4.1.1 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: @@ -3501,7 +3302,7 @@ snapshots: dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 - js-yaml: 4.1.0 + js-yaml: 4.1.1 parse-json: 5.2.0 optionalDependencies: typescript: 5.8.3 @@ -3512,14 +3313,10 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - csstype@3.1.3: {} + csstype@3.2.3: {} dargs@8.1.0: {} - debug@4.4.1: - dependencies: - ms: 2.1.3 - debug@4.4.3: dependencies: ms: 2.1.3 @@ -3528,7 +3325,7 @@ snapshots: delayed-stream@1.0.0: {} - detect-libc@2.0.4: {} + detect-libc@2.1.2: {} detective-amd@6.0.1: dependencies: @@ -3566,7 +3363,7 @@ snapshots: detective-typescript@14.0.0(typescript@5.8.3): dependencies: - '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.8.3) ast-module-types: 6.0.1 node-source-walk: 7.0.1 typescript: 5.8.3 @@ -3576,7 +3373,7 @@ snapshots: detective-vue2@2.2.0(typescript@5.8.3): dependencies: '@dependents/detective-less': 5.0.1 - '@vue/compiler-sfc': 3.5.27 + '@vue/compiler-sfc': 3.5.28 detective-es6: 5.0.1 detective-sass: 6.0.1 detective-scss: 5.0.1 @@ -3603,24 +3400,24 @@ snapshots: effector@23.4.4: {} - electron-to-chromium@1.5.179: {} + electron-to-chromium@1.5.286: {} emoji-regex@8.0.0: {} empathic@1.1.0: {} - enhanced-resolve@5.18.2: + enhanced-resolve@5.19.0: dependencies: graceful-fs: 4.2.11 - tapable: 2.2.2 + tapable: 2.3.0 entities@4.5.0: {} - entities@7.0.0: {} + entities@7.0.1: {} env-paths@2.2.1: {} - error-ex@1.3.2: + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 @@ -3639,33 +3436,34 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - esbuild@0.25.5: + esbuild@0.27.3: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.5 - '@esbuild/android-arm': 0.25.5 - '@esbuild/android-arm64': 0.25.5 - '@esbuild/android-x64': 0.25.5 - '@esbuild/darwin-arm64': 0.25.5 - '@esbuild/darwin-x64': 0.25.5 - '@esbuild/freebsd-arm64': 0.25.5 - '@esbuild/freebsd-x64': 0.25.5 - '@esbuild/linux-arm': 0.25.5 - '@esbuild/linux-arm64': 0.25.5 - '@esbuild/linux-ia32': 0.25.5 - '@esbuild/linux-loong64': 0.25.5 - '@esbuild/linux-mips64el': 0.25.5 - '@esbuild/linux-ppc64': 0.25.5 - '@esbuild/linux-riscv64': 0.25.5 - '@esbuild/linux-s390x': 0.25.5 - '@esbuild/linux-x64': 0.25.5 - '@esbuild/netbsd-arm64': 0.25.5 - '@esbuild/netbsd-x64': 0.25.5 - '@esbuild/openbsd-arm64': 0.25.5 - '@esbuild/openbsd-x64': 0.25.5 - '@esbuild/sunos-x64': 0.25.5 - '@esbuild/win32-arm64': 0.25.5 - '@esbuild/win32-ia32': 0.25.5 - '@esbuild/win32-x64': 0.25.5 + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 escalade@3.2.0: {} @@ -3679,13 +3477,13 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-plugin-react-hooks@5.2.0(eslint@9.30.1(jiti@2.6.1)): + eslint-plugin-react-hooks@5.2.0(eslint@9.39.2(jiti@2.6.1)): dependencies: - eslint: 9.30.1(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-react-refresh@0.4.20(eslint@9.30.1(jiti@2.6.1)): + eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@2.6.1)): dependencies: - eslint: 9.30.1(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) eslint-scope@8.4.0: dependencies: @@ -3696,30 +3494,29 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.30.1(jiti@2.6.1): - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@2.6.1)) - '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.21.0 - '@eslint/config-helpers': 0.3.0 - '@eslint/core': 0.14.0 - '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.30.1 - '@eslint/plugin-kit': 0.3.3 - '@humanfs/node': 0.16.6 + eslint@9.39.2(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.3 + '@eslint/js': 9.39.2 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.1 + debug: 4.4.3 escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 - esquery: 1.6.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 8.0.0 @@ -3746,7 +3543,7 @@ snapshots: esprima@4.0.1: {} - esquery@1.6.0: + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -3778,14 +3575,10 @@ snapshots: fastest-levenshtein@1.0.16: {} - fastq@1.19.1: + fastq@1.20.1: dependencies: reusify: 1.1.0 - fdir@6.4.6(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -3803,12 +3596,6 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - find-up@7.0.0: - dependencies: - locate-path: 7.2.0 - path-exists: 5.0.0 - unicorn-magic: 0.1.0 - flat-cache@4.0.1: dependencies: flatted: 3.3.3 @@ -3878,7 +3665,7 @@ snapshots: globals@14.0.0: {} - globals@16.3.0: {} + globals@16.5.0: {} globby@14.1.0: dependencies: @@ -3899,8 +3686,6 @@ snapshots: graceful-fs@4.2.11: {} - graphemer@1.4.0: {} - has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -3944,9 +3729,7 @@ snapshots: is-obj@2.0.0: {} - is-text-path@2.0.0: - dependencies: - text-extensions: 2.4.0 + is-plain-obj@4.1.0: {} is-url-superb@4.0.0: {} @@ -3958,7 +3741,7 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@4.1.0: + js-yaml@4.1.1: dependencies: argparse: 2.0.1 @@ -3976,8 +3759,6 @@ snapshots: json5@2.2.3: {} - jsonparse@1.3.1: {} - keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -3987,50 +3768,54 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-darwin-arm64@1.30.1: + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: optional: true - lightningcss-darwin-x64@1.30.1: + lightningcss-darwin-x64@1.30.2: optional: true - lightningcss-freebsd-x64@1.30.1: + lightningcss-freebsd-x64@1.30.2: optional: true - lightningcss-linux-arm-gnueabihf@1.30.1: + lightningcss-linux-arm-gnueabihf@1.30.2: optional: true - lightningcss-linux-arm64-gnu@1.30.1: + lightningcss-linux-arm64-gnu@1.30.2: optional: true - lightningcss-linux-arm64-musl@1.30.1: + lightningcss-linux-arm64-musl@1.30.2: optional: true - lightningcss-linux-x64-gnu@1.30.1: + lightningcss-linux-x64-gnu@1.30.2: optional: true - lightningcss-linux-x64-musl@1.30.1: + lightningcss-linux-x64-musl@1.30.2: optional: true - lightningcss-win32-arm64-msvc@1.30.1: + lightningcss-win32-arm64-msvc@1.30.2: optional: true - lightningcss-win32-x64-msvc@1.30.1: + lightningcss-win32-x64-msvc@1.30.2: optional: true - lightningcss@1.30.1: + lightningcss@1.30.2: dependencies: - detect-libc: 2.0.4 + detect-libc: 2.1.2 optionalDependencies: - lightningcss-darwin-arm64: 1.30.1 - lightningcss-darwin-x64: 1.30.1 - lightningcss-freebsd-x64: 1.30.1 - lightningcss-linux-arm-gnueabihf: 1.30.1 - lightningcss-linux-arm64-gnu: 1.30.1 - lightningcss-linux-arm64-musl: 1.30.1 - lightningcss-linux-x64-gnu: 1.30.1 - lightningcss-linux-x64-musl: 1.30.1 - lightningcss-win32-arm64-msvc: 1.30.1 - lightningcss-win32-x64-msvc: 1.30.1 + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 lines-and-columns@1.2.4: {} @@ -4038,16 +3823,10 @@ snapshots: dependencies: p-locate: 5.0.0 - locate-path@7.2.0: - dependencies: - p-locate: 6.0.0 - - lodash-es@4.17.22: {} + lodash-es@4.17.23: {} lodash.camelcase@4.3.0: {} - lodash.isplainobject@4.0.6: {} - lodash.kebabcase@4.1.1: {} lodash.merge@4.6.2: {} @@ -4058,8 +3837,6 @@ snapshots: lodash.startcase@4.4.0: {} - lodash.uniq@4.5.0: {} - lodash.upperfirst@4.3.1: {} lower-case@2.0.2: @@ -4070,10 +3847,6 @@ snapshots: dependencies: yallist: 3.1.1 - magic-string@0.30.17: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.4 - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -4082,6 +3855,8 @@ snapshots: meow@12.1.1: {} + meow@13.2.0: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -4105,14 +3880,6 @@ snapshots: minimist@1.2.8: {} - minipass@7.1.2: {} - - minizlib@3.0.2: - dependencies: - minipass: 7.1.2 - - mkdirp@3.0.1: {} - module-definition@6.0.1: dependencies: ast-module-types: 6.0.1 @@ -4129,11 +3896,11 @@ snapshots: lower-case: 2.0.2 tslib: 2.8.1 - node-releases@2.0.19: {} + node-releases@2.0.27: {} node-source-walk@7.0.1: dependencies: - '@babel/parser': 7.28.6 + '@babel/parser': 7.29.0 optionator@0.9.4: dependencies: @@ -4148,33 +3915,23 @@ snapshots: dependencies: yocto-queue: 0.1.0 - p-limit@4.0.0: - dependencies: - yocto-queue: 1.2.2 - p-locate@5.0.0: dependencies: p-limit: 3.1.0 - p-locate@6.0.0: - dependencies: - p-limit: 4.0.0 - parent-module@1.0.1: dependencies: callsites: 3.1.0 parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.27.1 - error-ex: 1.3.2 + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 path-exists@4.0.0: {} - path-exists@5.0.0: {} - path-key@3.1.1: {} path-type@4.0.0: {} @@ -4189,8 +3946,6 @@ snapshots: picomatch@2.3.1: {} - picomatch@4.0.2: {} - picomatch@4.0.3: {} pluralize@8.0.0: {} @@ -4230,11 +3985,11 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-tailwindcss@0.6.14(prettier@3.6.2): + prettier-plugin-tailwindcss@0.6.14(prettier@3.8.1): dependencies: - prettier: 3.6.2 + prettier: 3.8.1 - prettier@3.6.2: {} + prettier@3.8.1: {} prexit@2.3.0: {} @@ -4246,32 +4001,32 @@ snapshots: quote-unquote@1.0.0: {} - react-dom@19.1.0(react@19.1.0): + react-dom@19.2.4(react@19.2.4): dependencies: - react: 19.1.0 - scheduler: 0.26.0 + react: 19.2.4 + scheduler: 0.27.0 - react-hook-form@7.71.1(react@19.1.0): + react-hook-form@7.71.1(react@19.2.4): dependencies: - react: 19.1.0 + react: 19.2.4 react-refresh@0.17.0: {} - react-router-dom@7.6.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - react-router: 7.6.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-router: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react-router@7.6.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - cookie: 1.0.2 - react: 19.1.0 - set-cookie-parser: 2.7.1 + cookie: 1.1.1 + react: 19.2.4 + set-cookie-parser: 2.7.2 optionalDependencies: - react-dom: 19.1.0(react@19.1.0) + react-dom: 19.2.4(react@19.2.4) - react@19.1.0: {} + react@19.2.4: {} readdirp@4.1.2: {} @@ -4285,43 +4040,48 @@ snapshots: reusify@1.1.0: {} - rollup@4.44.2: + rollup@4.57.1: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.44.2 - '@rollup/rollup-android-arm64': 4.44.2 - '@rollup/rollup-darwin-arm64': 4.44.2 - '@rollup/rollup-darwin-x64': 4.44.2 - '@rollup/rollup-freebsd-arm64': 4.44.2 - '@rollup/rollup-freebsd-x64': 4.44.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.44.2 - '@rollup/rollup-linux-arm-musleabihf': 4.44.2 - '@rollup/rollup-linux-arm64-gnu': 4.44.2 - '@rollup/rollup-linux-arm64-musl': 4.44.2 - '@rollup/rollup-linux-loongarch64-gnu': 4.44.2 - '@rollup/rollup-linux-powerpc64le-gnu': 4.44.2 - '@rollup/rollup-linux-riscv64-gnu': 4.44.2 - '@rollup/rollup-linux-riscv64-musl': 4.44.2 - '@rollup/rollup-linux-s390x-gnu': 4.44.2 - '@rollup/rollup-linux-x64-gnu': 4.44.2 - '@rollup/rollup-linux-x64-musl': 4.44.2 - '@rollup/rollup-win32-arm64-msvc': 4.44.2 - '@rollup/rollup-win32-ia32-msvc': 4.44.2 - '@rollup/rollup-win32-x64-msvc': 4.44.2 + '@rollup/rollup-android-arm-eabi': 4.57.1 + '@rollup/rollup-android-arm64': 4.57.1 + '@rollup/rollup-darwin-arm64': 4.57.1 + '@rollup/rollup-darwin-x64': 4.57.1 + '@rollup/rollup-freebsd-arm64': 4.57.1 + '@rollup/rollup-freebsd-x64': 4.57.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 + '@rollup/rollup-linux-arm-musleabihf': 4.57.1 + '@rollup/rollup-linux-arm64-gnu': 4.57.1 + '@rollup/rollup-linux-arm64-musl': 4.57.1 + '@rollup/rollup-linux-loong64-gnu': 4.57.1 + '@rollup/rollup-linux-loong64-musl': 4.57.1 + '@rollup/rollup-linux-ppc64-gnu': 4.57.1 + '@rollup/rollup-linux-ppc64-musl': 4.57.1 + '@rollup/rollup-linux-riscv64-gnu': 4.57.1 + '@rollup/rollup-linux-riscv64-musl': 4.57.1 + '@rollup/rollup-linux-s390x-gnu': 4.57.1 + '@rollup/rollup-linux-x64-gnu': 4.57.1 + '@rollup/rollup-linux-x64-musl': 4.57.1 + '@rollup/rollup-openbsd-x64': 4.57.1 + '@rollup/rollup-openharmony-arm64': 4.57.1 + '@rollup/rollup-win32-arm64-msvc': 4.57.1 + '@rollup/rollup-win32-ia32-msvc': 4.57.1 + '@rollup/rollup-win32-x64-gnu': 4.57.1 + '@rollup/rollup-win32-x64-msvc': 4.57.1 fsevents: 2.3.3 run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - scheduler@0.26.0: {} + scheduler@0.27.0: {} semver@6.3.1: {} - semver@7.7.3: {} + semver@7.7.4: {} - set-cookie-parser@2.7.1: {} + set-cookie-parser@2.7.2: {} shebang-command@2.0.0: dependencies: @@ -4356,7 +4116,7 @@ snapshots: fastest-levenshtein: 1.0.16 globby: 14.1.0 immer: 10.2.0 - lodash-es: 4.17.22 + lodash-es: 4.17.23 micromatch: 4.0.8 patronum: 2.3.0(effector@23.4.4) picocolors: 1.1.1 @@ -4390,36 +4150,18 @@ snapshots: tailwind-merge@3.4.0: {} - tailwind-variants@3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.11): + tailwind-variants@3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.18): dependencies: - tailwindcss: 4.1.11 + tailwindcss: 4.1.18 optionalDependencies: tailwind-merge: 3.4.0 - tailwindcss@4.1.11: {} - - tapable@2.2.2: {} + tailwindcss@4.1.18: {} - tar@7.4.3: - dependencies: - '@isaacs/fs-minipass': 4.0.1 - chownr: 3.0.0 - minipass: 7.1.2 - minizlib: 3.0.2 - mkdirp: 3.0.1 - yallist: 5.0.0 - - text-extensions@2.4.0: {} - - through@2.3.8: {} + tapable@2.3.0: {} tinyexec@1.0.2: {} - tinyglobby@0.2.14: - dependencies: - fdir: 6.4.6(picomatch@4.0.2) - picomatch: 4.0.2 - tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -4429,10 +4171,6 @@ snapshots: dependencies: is-number: 7.0.0 - ts-api-utils@2.1.0(typescript@5.8.3): - dependencies: - typescript: 5.8.3 - ts-api-utils@2.4.0(typescript@5.8.3): dependencies: typescript: 5.8.3 @@ -4453,27 +4191,26 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3): + typescript-eslint@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/parser': 8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) - eslint: 9.30.1(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.55.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) + '@typescript-eslint/parser': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) + eslint: 9.39.2(jiti@2.6.1) typescript: 5.8.3 transitivePeerDependencies: - supports-color typescript@5.8.3: {} - undici-types@7.10.0: {} - - unicorn-magic@0.1.0: {} + undici-types@7.16.0: {} unicorn-magic@0.3.0: {} - update-browserslist-db@1.1.3(browserslist@4.25.1): + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: - browserslist: 4.25.1 + browserslist: 4.28.1 escalade: 3.2.0 picocolors: 1.1.1 @@ -4481,41 +4218,41 @@ snapshots: dependencies: punycode: 2.3.1 - vite-plugin-svgr@4.3.0(rollup@4.44.2)(typescript@5.8.3)(vite@7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1)): + vite-plugin-svgr@4.5.0(rollup@4.57.1)(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)): dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.44.2) + '@rollup/pluginutils': 5.3.0(rollup@4.57.1) '@svgr/core': 8.1.0(typescript@5.8.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.8.3)) - vite: 7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2) transitivePeerDependencies: - rollup - supports-color - typescript - vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1)): + vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)): dependencies: - debug: 4.4.1 + debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.8.3) optionalDependencies: - vite: 7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2) transitivePeerDependencies: - supports-color - typescript - vite@7.0.2(@types/node@24.2.1)(jiti@2.6.1)(lightningcss@1.30.1): + vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2): dependencies: - esbuild: 0.25.5 - fdir: 6.4.6(picomatch@4.0.2) - picomatch: 4.0.2 + esbuild: 0.27.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.44.2 - tinyglobby: 0.2.14 + rollup: 4.57.1 + tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.2.1 + '@types/node': 24.10.13 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.30.1 + lightningcss: 1.30.2 which@2.0.2: dependencies: @@ -4533,8 +4270,6 @@ snapshots: yallist@3.1.1: {} - yallist@5.0.0: {} - yargs-parser@21.1.1: {} yargs@17.7.2: @@ -4549,16 +4284,16 @@ snapshots: yocto-queue@0.1.0: {} - yocto-queue@1.2.2: {} - zod-validation-error@3.5.4(zod@3.25.76): dependencies: zod: 3.25.76 zod@3.25.76: {} - zustand@5.0.10(@types/react@19.1.8)(immer@10.2.0)(react@19.1.0): + zod@4.3.6: {} + + zustand@5.0.11(@types/react@19.2.14)(immer@10.2.0)(react@19.2.4): optionalDependencies: - '@types/react': 19.1.8 + '@types/react': 19.2.14 immer: 10.2.0 - react: 19.1.0 + react: 19.2.4 diff --git a/src/pages/create-unit/model/types.ts b/src/pages/create-unit/model/types.ts new file mode 100644 index 0000000..2dadf0e --- /dev/null +++ b/src/pages/create-unit/model/types.ts @@ -0,0 +1,17 @@ +import z from 'zod'; + +// 단원 생성/수정 폼 스키마 +export const unitFormSchema = z + .object({ + title: z.string(), + releaseDate: z.string(), + dueDate: z.string(), + assignmentIds: z.array(z.number()).optional(), + }) + .refine((data) => data.releaseDate <= data.dueDate, { + message: '날짜 범위가 올바르지 않습니다.', + path: ['dueDate'], + }); + +// 단원 생성/수정 폼 타입 +export type TUnitFormSchema = z.infer; diff --git a/src/pages/create-unit/ui/UnitFormEditor.tsx b/src/pages/create-unit/ui/UnitFormEditor.tsx index a5011cb..fb2945b 100644 --- a/src/pages/create-unit/ui/UnitFormEditor.tsx +++ b/src/pages/create-unit/ui/UnitFormEditor.tsx @@ -1,19 +1,21 @@ -import {useForm, type FieldValues} from 'react-hook-form'; +import {useForm} from 'react-hook-form'; import Button from '@/components/common/Button'; import BinIcon from '@/assets/svg/binIcon.svg?react'; import LabeledInput from '@/components/admin/form/LabeledInput'; import type {Unit} from '@/models/course'; import {SortableAssignmentList} from './SortableAssignmentList'; +import {zodResolver} from '@hookform/resolvers/zod'; +import {unitFormSchema, type TUnitFormSchema} from '../model/types'; const UnitFormEditor = ({unit}: {unit: Unit}) => { const { register, handleSubmit, - // formState: {errors, isSubmitting}, + formState: {errors, isSubmitting}, reset, - } = useForm(); + } = useForm({resolver: zodResolver(unitFormSchema)}); - const onSubmit = async (data: FieldValues) => { + const onSubmit = async (data: TUnitFormSchema) => { await new Promise((resolve) => setTimeout(resolve, 1000)); reset(); }; @@ -22,8 +24,9 @@ const UnitFormEditor = ({unit}: {unit: Unit}) => {
    {/* 단원 편집 폼 */} + className='bg-background h-167.5 flex flex-col overflow-x-hidden custom-scrollbar rounded-[30px]'> {/* 폼 헤더 */}
    {/* TODO: 단원 Index 추가하기 */} @@ -42,9 +45,7 @@ const UnitFormEditor = ({unit}: {unit: Unit}) => { {/* 단원 제목 섹션 */}
    @@ -53,21 +54,22 @@ const UnitFormEditor = ({unit}: {unit: Unit}) => { {/* 날짜 섹션 (공개일, 마감일) */}
    + {errors.dueDate && ( + + {errors.dueDate.message} + + )}

    @@ -82,11 +84,12 @@ const UnitFormEditor = ({unit}: {unit: Unit}) => { {/* 제출 버튼 */}
    - +
    ); }; export default UnitFormEditor; -devicePixelRatio; From 291b3c1284d4a98d0145b5c60b64cf53c9e5492d Mon Sep 17 00:00:00 2001 From: suminb99 Date: Wed, 11 Feb 2026 22:28:22 +0900 Subject: [PATCH 36/91] =?UTF-8?q?#44=20feat:=20Button=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=20formID=20prop=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Button.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/common/Button.tsx b/src/components/common/Button.tsx index 759ebde..3502744 100644 --- a/src/components/common/Button.tsx +++ b/src/components/common/Button.tsx @@ -41,6 +41,7 @@ interface ButtonProps extends ButtonVariants { className?: string; type?: 'button' | 'submit'; disabled?: boolean; + formID?: string; onClick?: () => void; onMouseEnter?: () => void; onMouseLeave?: () => void; @@ -52,12 +53,14 @@ const Button = ({ onClick, type = 'button', disabled = false, + formID, ...props }: ButtonProps) => { return ( From e28029781dc4120d0715f3087c83fe0283f39064 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Wed, 11 Feb 2026 22:28:43 +0900 Subject: [PATCH 37/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20=EB=8F=99=EC=A0=81=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=8C=85=20=EB=B0=8F=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EB=8B=A8=EC=9B=90=20=EC=A1=B0=ED=9A=8C=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 2 +- src/pages/create-unit/CreateUnitPage.tsx | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index 2d14d74..fd04a8a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -47,7 +47,7 @@ const AppRoutes = () => { } /> } /> } /> - } /> + } /> diff --git a/src/pages/create-unit/CreateUnitPage.tsx b/src/pages/create-unit/CreateUnitPage.tsx index 3b9d80e..0b70c4e 100644 --- a/src/pages/create-unit/CreateUnitPage.tsx +++ b/src/pages/create-unit/CreateUnitPage.tsx @@ -2,10 +2,19 @@ import SurfaceCard from '@/components/common/SurfaceCard'; import UnitFormEditor from './ui/UnitFormEditor'; import UnitList from './ui/UnitList'; import {allUnitsResponse, singleUnitResponse} from './mocks/response'; +import {useQuery} from '@tanstack/react-query'; +import {allUnitsQueryOptions} from '@/entities/unit/api/unitQueryOptions'; +import {useParams} from 'react-router-dom'; +import {useState} from 'react'; const CreateUnitPage = () => { const unitList = allUnitsResponse.response.units; const currentUnit = singleUnitResponse.response; + const {id} = useParams(); + // const {currentUnitId, setCurrentUnitId} = useState(null); + const {data: allUnits} = useQuery(allUnitsQueryOptions(Number(id))); + + console.log('allUnits', allUnits); return (
    From a0392e9e4df9b23be5d7f78922c28812b59ff306 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Thu, 12 Feb 2026 02:27:27 +0900 Subject: [PATCH 38/91] =?UTF-8?q?#44=20fix:=20EmptyState=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=97=90=EC=84=9C=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20text-center=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/EmptyState.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/common/EmptyState.tsx b/src/components/common/EmptyState.tsx index 0f55789..9b978d9 100644 --- a/src/components/common/EmptyState.tsx +++ b/src/components/common/EmptyState.tsx @@ -6,7 +6,7 @@ interface EmptyStateProps { export const EmptyState = ({children, className}: EmptyStateProps) => { return (
    + className={`text-light-black text-base font-medium ${className ?? ''}`}> {children}
    ); From 54c9f37847e51e32886e077f4d62506d6b1951e9 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Thu, 12 Feb 2026 02:28:04 +0900 Subject: [PATCH 39/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9D=BC=20?= =?UTF-8?q?=EB=8B=A8=EC=9B=90=20=EC=A1=B0=ED=9A=8C=20API=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95=20=EB=B0=8F?= =?UTF-8?q?=20nullable=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitApi.ts | 4 +++- src/entities/unit/api/unitQueryOptions.ts | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/entities/unit/api/unitApi.ts b/src/entities/unit/api/unitApi.ts index a81c3a5..8d53ce5 100644 --- a/src/entities/unit/api/unitApi.ts +++ b/src/entities/unit/api/unitApi.ts @@ -11,7 +11,9 @@ export const getAllUnitsByCourseId = async ( }; // 단일 단원 조회 -export const getUnitById = async (unitId: number): Promise => { +export const getUnitById = async ( + unitId: number | null +): Promise> => { const response = await privateAxios.get(`/units/${unitId}`); return response.data; }; diff --git a/src/entities/unit/api/unitQueryOptions.ts b/src/entities/unit/api/unitQueryOptions.ts index 22080a6..2bb740d 100644 --- a/src/entities/unit/api/unitQueryOptions.ts +++ b/src/entities/unit/api/unitQueryOptions.ts @@ -10,9 +10,10 @@ export function allUnitsQueryOptions(courseId: number) { } // 단일 단원 조회 쿼리 옵션 -export function unitQueryOptions(unitId: number) { +export function unitQueryOptions(unitId: number | null) { return queryOptions({ queryKey: ['unit', unitId], queryFn: () => getUnitById(unitId), + enabled: !!unitId, }); } From da1ce8254095ba3474db36b455379280951ff6bc Mon Sep 17 00:00:00 2001 From: suminb99 Date: Thu, 12 Feb 2026 02:28:18 +0900 Subject: [PATCH 40/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20=EC=83=81=ED=83=9C=20=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20=EB=8B=A8=EC=9D=BC=20=EB=8B=A8=EC=9B=90=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20API=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/CreateUnitPage.tsx | 31 +++++++++++++++--------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/pages/create-unit/CreateUnitPage.tsx b/src/pages/create-unit/CreateUnitPage.tsx index 0b70c4e..2448450 100644 --- a/src/pages/create-unit/CreateUnitPage.tsx +++ b/src/pages/create-unit/CreateUnitPage.tsx @@ -1,31 +1,40 @@ import SurfaceCard from '@/components/common/SurfaceCard'; import UnitFormEditor from './ui/UnitFormEditor'; import UnitList from './ui/UnitList'; -import {allUnitsResponse, singleUnitResponse} from './mocks/response'; -import {useQuery} from '@tanstack/react-query'; -import {allUnitsQueryOptions} from '@/entities/unit/api/unitQueryOptions'; +import {useQuery, useSuspenseQuery} from '@tanstack/react-query'; +import { + allUnitsQueryOptions, + unitQueryOptions, +} from '@/entities/unit/api/unitQueryOptions'; import {useParams} from 'react-router-dom'; -import {useState} from 'react'; +import {useEffect, useState} from 'react'; const CreateUnitPage = () => { - const unitList = allUnitsResponse.response.units; - const currentUnit = singleUnitResponse.response; const {id} = useParams(); - // const {currentUnitId, setCurrentUnitId} = useState(null); - const {data: allUnits} = useQuery(allUnitsQueryOptions(Number(id))); + const [selectedUnitId, setSelectedUnitId] = useState(null); + const {data: allUnits} = useSuspenseQuery(allUnitsQueryOptions(Number(id))); + const {data: unit} = useQuery(unitQueryOptions(selectedUnitId)); - console.log('allUnits', allUnits); + useEffect(() => { + if (allUnits && allUnits.response.count !== 0 && selectedUnitId === null) { + setSelectedUnitId(allUnits.response.units[0].id); + } + }, [allUnits, selectedUnitId, setSelectedUnitId]); return (
    {/* 단원 목차 섹션 */} - + setSelectedUnitId(id)} + selectedUnitId={selectedUnitId} + /> {/* 단원 폼 섹션 */} - +
    ); From 8bbb2c11975651174499785e69e015b9befd5dcb Mon Sep 17 00:00:00 2001 From: suminb99 Date: Thu, 12 Feb 2026 02:29:07 +0900 Subject: [PATCH 41/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=EC=97=90=20=EC=84=A0=ED=83=9D=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20UI=20=EB=B0=8F=20=ED=81=B4=EB=A6=AD=20=ED=95=B8?= =?UTF-8?q?=EB=93=A4=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/ui/UnitList.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pages/create-unit/ui/UnitList.tsx b/src/pages/create-unit/ui/UnitList.tsx index b1f9366..838f243 100644 --- a/src/pages/create-unit/ui/UnitList.tsx +++ b/src/pages/create-unit/ui/UnitList.tsx @@ -6,9 +6,11 @@ import type {AllUnitsResponse} from '@/models/course'; interface UnitListProps { unitList: AllUnitsResponse['response']['units']; + onUnitClick: (id: number) => void; + selectedUnitId?: number | null; } -const UnitList = ({unitList}: UnitListProps) => { +const UnitList = ({unitList, onUnitClick, selectedUnitId}: UnitListProps) => { return (
    {/* 단원 리스트 헤더 */} @@ -19,8 +21,9 @@ const UnitList = ({unitList}: UnitListProps) => { {/* 단원 아이템 */} {unitList.map(({id, title, assignmentCount}) => (
  • onUnitClick(id)} key={id} - className='flex flex-col py-5 px-12 gap-2.5 hover:bg-background cursor-pointer transition-colors group'> + className={`flex flex-col py-5 px-12 gap-2.5 cursor-pointer ${selectedUnitId === id ? 'bg-background' : ''}`}> {/* 단원 인덱스 배지 */}
    @@ -31,7 +34,7 @@ const UnitList = ({unitList}: UnitListProps) => { {/* 단원 제목 및 화살표 아이콘 */}

    {title}

    - + {id === selectedUnitId && }
  • ))} From 0e754e997580b34909b56683b32bbea98fbc8efd Mon Sep 17 00:00:00 2001 From: suminb99 Date: Thu, 12 Feb 2026 02:29:26 +0900 Subject: [PATCH 42/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=ED=8F=BC=EC=97=90=20=EC=A1=B0=ED=9A=8C=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EB=B0=94=EC=9D=B8=EB=94=A9=20=EB=B0=8F=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=EB=93=B1=EB=A1=9D=20=EC=84=B9=EC=85=98=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/model/types.ts | 5 +++ .../create-unit/ui/SortableAssignmentList.tsx | 13 ------ src/pages/create-unit/ui/UnitFormEditor.tsx | 41 ++++++++++++++++--- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/pages/create-unit/model/types.ts b/src/pages/create-unit/model/types.ts index 2dadf0e..e8c1d3d 100644 --- a/src/pages/create-unit/model/types.ts +++ b/src/pages/create-unit/model/types.ts @@ -1,3 +1,4 @@ +import type {Unit} from '@/models/course'; import z from 'zod'; // 단원 생성/수정 폼 스키마 @@ -15,3 +16,7 @@ export const unitFormSchema = z // 단원 생성/수정 폼 타입 export type TUnitFormSchema = z.infer; + +export interface UnitFormEditorProps { + unit?: Unit; +} diff --git a/src/pages/create-unit/ui/SortableAssignmentList.tsx b/src/pages/create-unit/ui/SortableAssignmentList.tsx index ec26a97..c6a15e9 100644 --- a/src/pages/create-unit/ui/SortableAssignmentList.tsx +++ b/src/pages/create-unit/ui/SortableAssignmentList.tsx @@ -19,8 +19,6 @@ import { sortableKeyboardCoordinates, } from '@dnd-kit/sortable'; import {CSS} from '@dnd-kit/utilities'; -import Button from '@/components/common/Button'; -import AddIcon from '@/assets/svg/addIcon.svg?react'; export const SortableAssignmentList = ({ assignmentList, @@ -63,9 +61,6 @@ export const SortableAssignmentList = ({ return (
    - {/* 섹션 제목 - 문제 등록 */} -

    문제 등록

    - {/* draggable & sortable 문제 목록 영역 */} - - {/* 문제 연결 버튼 */} -
    - -
    ); }; diff --git a/src/pages/create-unit/ui/UnitFormEditor.tsx b/src/pages/create-unit/ui/UnitFormEditor.tsx index fb2945b..e028578 100644 --- a/src/pages/create-unit/ui/UnitFormEditor.tsx +++ b/src/pages/create-unit/ui/UnitFormEditor.tsx @@ -2,18 +2,30 @@ import {useForm} from 'react-hook-form'; import Button from '@/components/common/Button'; import BinIcon from '@/assets/svg/binIcon.svg?react'; import LabeledInput from '@/components/admin/form/LabeledInput'; -import type {Unit} from '@/models/course'; import {SortableAssignmentList} from './SortableAssignmentList'; import {zodResolver} from '@hookform/resolvers/zod'; -import {unitFormSchema, type TUnitFormSchema} from '../model/types'; +import { + unitFormSchema, + type TUnitFormSchema, + type UnitFormEditorProps, +} from '../model/types'; +import AddIcon from '@/assets/svg/addIcon.svg?react'; +import {EmptyState} from '@/components/common/EmptyState'; -const UnitFormEditor = ({unit}: {unit: Unit}) => { +const UnitFormEditor = ({unit}: UnitFormEditorProps) => { const { register, handleSubmit, formState: {errors, isSubmitting}, reset, - } = useForm({resolver: zodResolver(unitFormSchema)}); + } = useForm({ + resolver: zodResolver(unitFormSchema), + values: { + title: unit?.title || '', + releaseDate: unit?.releaseDate || '', + dueDate: unit?.dueDate || '', + }, + }); const onSubmit = async (data: TUnitFormSchema) => { await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -75,8 +87,25 @@ const UnitFormEditor = ({unit}: {unit: Unit}) => {
    {/* 문제 등록 섹션 */} -
    - +
    +

    문제 등록

    + + {/* 드래그 앤 드롭 가능한 문제 리스트 */} + {!unit || !unit.assignments || unit.assignments.length === 0 ? ( + + 등록된 문제가 없습니다. + + ) : ( + + )} + + {/* 문제 연결 버튼 */} +
    + +
    From 944d864751e4d2eb17716943dd2c08afdcf13ff9 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Fri, 13 Feb 2026 15:13:56 +0900 Subject: [PATCH 43/91] =?UTF-8?q?#44=20style:=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EB=84=88=EB=B9=84=20=EB=B0=8F=20=EC=A0=95?= =?UTF-8?q?=EB=A0=AC=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layout/Layout.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/layout/Layout.tsx b/src/layout/Layout.tsx index 789c424..1a17107 100644 --- a/src/layout/Layout.tsx +++ b/src/layout/Layout.tsx @@ -9,10 +9,10 @@ const Layout = () => { const showHeader = !noHeaderPages.includes(pathname); return ( -
    -
    +
    +
    {showHeader && ( -
    +
    )} From e3bb94de7595d387c2381e5494d6e8478c9c9559 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Fri, 13 Feb 2026 15:15:06 +0900 Subject: [PATCH 44/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80/=ED=8E=B8=EC=A7=91=20=EB=AA=A8=EB=93=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=EB=8B=A8=EC=9B=90=20=EC=9D=B8?= =?UTF-8?q?=EB=8D=B1=EC=8A=A4=20=EA=B4=80=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/CreateUnitPage.tsx | 27 ++++++++++++++++++--- src/pages/create-unit/model/types.ts | 2 ++ src/pages/create-unit/ui/UnitFormEditor.tsx | 27 +++++++++++++++------ src/pages/create-unit/ui/UnitList.tsx | 26 +++++++++++++++++--- 4 files changed, 68 insertions(+), 14 deletions(-) diff --git a/src/pages/create-unit/CreateUnitPage.tsx b/src/pages/create-unit/CreateUnitPage.tsx index 2448450..5b3ec3a 100644 --- a/src/pages/create-unit/CreateUnitPage.tsx +++ b/src/pages/create-unit/CreateUnitPage.tsx @@ -12,14 +12,29 @@ import {useEffect, useState} from 'react'; const CreateUnitPage = () => { const {id} = useParams(); const [selectedUnitId, setSelectedUnitId] = useState(null); + const [currentIndex, setCurrentIndex] = useState(1); // const {data: allUnits} = useSuspenseQuery(allUnitsQueryOptions(Number(id))); const {data: unit} = useQuery(unitQueryOptions(selectedUnitId)); + const [isEditing, setIsEditing] = useState(false); + // 단원 목록에서 선택된 단원이 없을 때, 첫 번째 단원을 선택하도록 설정 useEffect(() => { if (allUnits && allUnits.response.count !== 0 && selectedUnitId === null) { setSelectedUnitId(allUnits.response.units[0].id); + setIsEditing(true); // 첫 번째 단원이 선택되면 편집 모드로 전환 } - }, [allUnits, selectedUnitId, setSelectedUnitId]); + }, [allUnits, selectedUnitId]); + + const onUnitClick = (id: number) => { + setSelectedUnitId(id); + setIsEditing(true); // 단원이 선택되면 편집 모드로 전환 + }; + + const onAddNewUnit = () => { + setSelectedUnitId(-1); + setCurrentIndex(allUnits ? allUnits.response.count + 1 : 1); // 새 단원의 인덱스 설정 + setIsEditing(false); // 새 단원 추가 시 편집 모드 해제 + }; return (
    @@ -27,14 +42,20 @@ const CreateUnitPage = () => { setSelectedUnitId(id)} + onUnitClick={onUnitClick} + onChangeIndex={(index) => setCurrentIndex(index)} selectedUnitId={selectedUnitId} + onAddNewUnit={onAddNewUnit} /> {/* 단원 폼 섹션 */} - +
    ); diff --git a/src/pages/create-unit/model/types.ts b/src/pages/create-unit/model/types.ts index e8c1d3d..a74fd4f 100644 --- a/src/pages/create-unit/model/types.ts +++ b/src/pages/create-unit/model/types.ts @@ -19,4 +19,6 @@ export type TUnitFormSchema = z.infer; export interface UnitFormEditorProps { unit?: Unit; + unitIndex: number; + isEditing: boolean; } diff --git a/src/pages/create-unit/ui/UnitFormEditor.tsx b/src/pages/create-unit/ui/UnitFormEditor.tsx index e028578..0a03863 100644 --- a/src/pages/create-unit/ui/UnitFormEditor.tsx +++ b/src/pages/create-unit/ui/UnitFormEditor.tsx @@ -11,8 +11,11 @@ import { } from '../model/types'; import AddIcon from '@/assets/svg/addIcon.svg?react'; import {EmptyState} from '@/components/common/EmptyState'; +import {useState} from 'react'; + +const UnitFormEditor = ({unit, unitIndex, isEditing}: UnitFormEditorProps) => { + const [assignmentIds, setAssignmentIds] = useState([]); -const UnitFormEditor = ({unit}: UnitFormEditorProps) => { const { register, handleSubmit, @@ -20,11 +23,19 @@ const UnitFormEditor = ({unit}: UnitFormEditorProps) => { reset, } = useForm({ resolver: zodResolver(unitFormSchema), - values: { - title: unit?.title || '', - releaseDate: unit?.releaseDate || '', - dueDate: unit?.dueDate || '', - }, + values: + isEditing === false + ? { + title: '', + releaseDate: '', + dueDate: '', + assignmentIds: [], + } + : { + title: unit?.title || '', + releaseDate: unit?.releaseDate || '', + dueDate: unit?.dueDate || '', + }, }); const onSubmit = async (data: TUnitFormSchema) => { @@ -42,7 +53,7 @@ const UnitFormEditor = ({unit}: UnitFormEditorProps) => { {/* 폼 헤더 */}
    {/* TODO: 단원 Index 추가하기 */} -

    1. 단원

    +

    {unitIndex}. 단원

    From 2e0944b31f5ccf539dace46f2c8e1ed1259f5ac5 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Fri, 13 Feb 2026 15:15:44 +0900 Subject: [PATCH 45/91] =?UTF-8?q?#44=20refactor:=20Button=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EB=B3=80=EC=88=98=20export=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20-=20=EC=99=B8=EB=B6=80=20=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Button.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/common/Button.tsx b/src/components/common/Button.tsx index 3502744..c0851b6 100644 --- a/src/components/common/Button.tsx +++ b/src/components/common/Button.tsx @@ -1,6 +1,6 @@ import {tv, type VariantProps} from 'tailwind-variants/lite'; -const button = tv({ +export const buttonStyles = tv({ base: 'cursor-pointer rounded-[10px] border', variants: { color: { @@ -34,7 +34,7 @@ const button = tv({ }, }); -type ButtonVariants = VariantProps; +type ButtonVariants = VariantProps; interface ButtonProps extends ButtonVariants { children: React.ReactNode; @@ -61,7 +61,7 @@ const Button = ({ onClick={onClick} disabled={disabled} form={formID} - className={button({...props, className})}> + className={buttonStyles({...props, className})}> {children} ); From 2678611de6eadc4fa82f3a08d00ed6613ee6b1c6 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Fri, 13 Feb 2026 15:16:15 +0900 Subject: [PATCH 46/91] =?UTF-8?q?#44=20fix:=20=EA=B3=BC=EC=A0=9C=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A0=95?= =?UTF-8?q?=EC=A0=81=20=EA=B2=BD=EB=A1=9C=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index fd04a8a..bfb7557 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -43,7 +43,7 @@ const AppRoutes = () => { } /> {/* } /> */} } /> - } /> + } /> } /> } /> } /> From ee6225341e59b6f38ac9e6d77f726b4c299d545e Mon Sep 17 00:00:00 2001 From: suminb99 Date: Fri, 13 Feb 2026 16:59:15 +0900 Subject: [PATCH 47/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20API=20=EB=B0=8F=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EC=98=B5=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitApi.ts | 9 +++++++++ src/entities/unit/api/unitQueryOptions.ts | 15 +++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/entities/unit/api/unitApi.ts b/src/entities/unit/api/unitApi.ts index 8d53ce5..2184b98 100644 --- a/src/entities/unit/api/unitApi.ts +++ b/src/entities/unit/api/unitApi.ts @@ -1,5 +1,6 @@ import type {ApiResponse} from '@/models/common'; import type {AllUnitsResponse, Unit} from '@/models/course'; +import type {TUnitFormSchema} from '@/pages/create-unit/model/types'; import {privateAxios} from '@/shared/api/axiosInstance'; // 강의별 전체 단원 조회 @@ -25,3 +26,11 @@ export const deleteUnitById = async ( const response = await privateAxios.delete(`/units/${unitId}`); return response.data; }; + +export const createUnit = async ( + courseId: number, + unit: TUnitFormSchema +): Promise> => { + const response = await privateAxios.post(`/units/${courseId}`, unit); + return response.data; +}; diff --git a/src/entities/unit/api/unitQueryOptions.ts b/src/entities/unit/api/unitQueryOptions.ts index 2bb740d..c6a1803 100644 --- a/src/entities/unit/api/unitQueryOptions.ts +++ b/src/entities/unit/api/unitQueryOptions.ts @@ -1,5 +1,6 @@ import {queryOptions} from '@tanstack/react-query'; -import {getAllUnitsByCourseId, getUnitById} from './unitApi'; +import {createUnit, getAllUnitsByCourseId, getUnitById} from './unitApi'; +import type {TUnitFormSchema} from '@/pages/create-unit/model/types'; // 강의별 전체 단원 조회 쿼리 옵션 export function allUnitsQueryOptions(courseId: number) { @@ -14,6 +15,16 @@ export function unitQueryOptions(unitId: number | null) { return queryOptions({ queryKey: ['unit', unitId], queryFn: () => getUnitById(unitId), - enabled: !!unitId, + enabled: !!unitId && unitId !== -1, // unitId가 null이거나 -1인 경우 쿼리 비활성화 + }); +} + +export function createUnitQueryOptions( + courseId: number, + unit: TUnitFormSchema +) { + return queryOptions({ + queryKey: ['createUnit', courseId, unit], + queryFn: () => createUnit(courseId, unit), }); } From 40dbbaab23e5c349698a0e69c217fa0b19770729 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Fri, 13 Feb 2026 16:59:22 +0900 Subject: [PATCH 48/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20mutation=20=EC=97=B0=EB=8F=99=20=EB=B0=8F?= =?UTF-8?q?=20UI=20=EB=B0=94=EC=9D=B8=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/CreateUnitPage.tsx | 28 +++++++++++++++++++-- src/pages/create-unit/model/types.ts | 1 + src/pages/create-unit/ui/UnitFormEditor.tsx | 11 +++++--- src/pages/create-unit/ui/UnitList.tsx | 6 ++--- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/pages/create-unit/CreateUnitPage.tsx b/src/pages/create-unit/CreateUnitPage.tsx index 5b3ec3a..dc5d20a 100644 --- a/src/pages/create-unit/CreateUnitPage.tsx +++ b/src/pages/create-unit/CreateUnitPage.tsx @@ -1,19 +1,21 @@ import SurfaceCard from '@/components/common/SurfaceCard'; import UnitFormEditor from './ui/UnitFormEditor'; import UnitList from './ui/UnitList'; -import {useQuery, useSuspenseQuery} from '@tanstack/react-query'; +import {useMutation, useQuery, useSuspenseQuery} from '@tanstack/react-query'; import { allUnitsQueryOptions, unitQueryOptions, } from '@/entities/unit/api/unitQueryOptions'; import {useParams} from 'react-router-dom'; import {useEffect, useState} from 'react'; +import {createUnit} from '@/entities/unit/api/unitApi'; +import type {TUnitFormSchema} from './model/types'; const CreateUnitPage = () => { const {id} = useParams(); const [selectedUnitId, setSelectedUnitId] = useState(null); const [currentIndex, setCurrentIndex] = useState(1); // - const {data: allUnits} = useSuspenseQuery(allUnitsQueryOptions(Number(id))); + const {data: allUnits} = useQuery(allUnitsQueryOptions(Number(id))); const {data: unit} = useQuery(unitQueryOptions(selectedUnitId)); const [isEditing, setIsEditing] = useState(false); @@ -36,6 +38,27 @@ const CreateUnitPage = () => { setIsEditing(false); // 새 단원 추가 시 편집 모드 해제 }; + // 단원 생성 뮤테이션 + const {mutate: addUnit} = useMutation({ + mutationFn: ({courseId, unit}: {courseId: number; unit: TUnitFormSchema}) => + createUnit(courseId, unit), + onSuccess: (data) => { + // 단원 목록 갱신 + alert('새 단원이 성공적으로 생성되었습니다.'); + setSelectedUnitId(data.response.id); + setIsEditing(true); // 새 단원 생성 후 편집 모드로 전환 + }, + onError: (error) => { + console.error('단원 생성 실패', error); + alert('단원 생성에 실패했습니다. 다시 시도해주세요.'); + }, + }); + + // 단원 생성 핸들러 + const onCreateUnit = (unit: TUnitFormSchema) => { + addUnit({courseId: Number(id), unit}); + }; + return (
    {/* 단원 목차 섹션 */} @@ -55,6 +78,7 @@ const CreateUnitPage = () => { unit={unit?.response} unitIndex={currentIndex} isEditing={isEditing} + onCreateUnit={onCreateUnit} />
    diff --git a/src/pages/create-unit/model/types.ts b/src/pages/create-unit/model/types.ts index a74fd4f..be4767d 100644 --- a/src/pages/create-unit/model/types.ts +++ b/src/pages/create-unit/model/types.ts @@ -21,4 +21,5 @@ export interface UnitFormEditorProps { unit?: Unit; unitIndex: number; isEditing: boolean; + onCreateUnit: (unit: TUnitFormSchema) => void; } diff --git a/src/pages/create-unit/ui/UnitFormEditor.tsx b/src/pages/create-unit/ui/UnitFormEditor.tsx index 0a03863..90abbe0 100644 --- a/src/pages/create-unit/ui/UnitFormEditor.tsx +++ b/src/pages/create-unit/ui/UnitFormEditor.tsx @@ -13,14 +13,18 @@ import AddIcon from '@/assets/svg/addIcon.svg?react'; import {EmptyState} from '@/components/common/EmptyState'; import {useState} from 'react'; -const UnitFormEditor = ({unit, unitIndex, isEditing}: UnitFormEditorProps) => { +const UnitFormEditor = ({ + unit, + unitIndex, + isEditing, + onCreateUnit, +}: UnitFormEditorProps) => { const [assignmentIds, setAssignmentIds] = useState([]); const { register, handleSubmit, formState: {errors, isSubmitting}, - reset, } = useForm({ resolver: zodResolver(unitFormSchema), values: @@ -39,8 +43,7 @@ const UnitFormEditor = ({unit, unitIndex, isEditing}: UnitFormEditorProps) => { }); const onSubmit = async (data: TUnitFormSchema) => { - await new Promise((resolve) => setTimeout(resolve, 1000)); - reset(); + onCreateUnit(data); }; return ( diff --git a/src/pages/create-unit/ui/UnitList.tsx b/src/pages/create-unit/ui/UnitList.tsx index 52b90f6..6f86791 100644 --- a/src/pages/create-unit/ui/UnitList.tsx +++ b/src/pages/create-unit/ui/UnitList.tsx @@ -5,7 +5,7 @@ import ArrowrightIcon from '@/assets/svg/arrowrightIcon.svg?react'; import type {AllUnitsResponse} from '@/models/course'; interface UnitListProps { - unitList: AllUnitsResponse['response']['units']; + unitList: AllUnitsResponse['response']['units'] | undefined; onUnitClick: (id: number) => void; selectedUnitId?: number | null; onChangeIndex: (index: number) => void; @@ -23,7 +23,7 @@ const UnitList = ({ onUnitClick(id); // 선택된 단원의 인덱스 찾기 - const index = unitList.findIndex((unit) => unit.id === id); + const index = unitList?.findIndex((unit) => unit.id === id) ?? 0; onChangeIndex(index + 1); }; @@ -35,7 +35,7 @@ const UnitList = ({ {/* 단원 목록 */}
      {/* 단원 아이템 */} - {unitList.map(({id, title, assignmentCount}) => ( + {unitList?.map(({id, title, assignmentCount}) => (
    • handleSelectUnit(id)} key={id} From 52434420bdfa5a7a13d32308f340a64a9d8c28e0 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Sat, 14 Feb 2026 01:34:06 +0900 Subject: [PATCH 49/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=ED=9B=84=20=EB=8B=A8=EC=9B=90=20=EB=AA=A9?= =?UTF-8?q?=EC=B0=A8=20=EA=B0=B1=EC=8B=A0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/create-unit/CreateUnitPage.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/pages/create-unit/CreateUnitPage.tsx b/src/pages/create-unit/CreateUnitPage.tsx index dc5d20a..77e175b 100644 --- a/src/pages/create-unit/CreateUnitPage.tsx +++ b/src/pages/create-unit/CreateUnitPage.tsx @@ -1,7 +1,7 @@ import SurfaceCard from '@/components/common/SurfaceCard'; import UnitFormEditor from './ui/UnitFormEditor'; import UnitList from './ui/UnitList'; -import {useMutation, useQuery, useSuspenseQuery} from '@tanstack/react-query'; +import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'; import { allUnitsQueryOptions, unitQueryOptions, @@ -12,12 +12,13 @@ import {createUnit} from '@/entities/unit/api/unitApi'; import type {TUnitFormSchema} from './model/types'; const CreateUnitPage = () => { - const {id} = useParams(); + const {id} = useParams(); // 강의 ID const [selectedUnitId, setSelectedUnitId] = useState(null); - const [currentIndex, setCurrentIndex] = useState(1); // + const [currentIndex, setCurrentIndex] = useState(1); + const [isEditing, setIsEditing] = useState(false); const {data: allUnits} = useQuery(allUnitsQueryOptions(Number(id))); const {data: unit} = useQuery(unitQueryOptions(selectedUnitId)); - const [isEditing, setIsEditing] = useState(false); + const queryClient = useQueryClient(); // 단원 목록에서 선택된 단원이 없을 때, 첫 번째 단원을 선택하도록 설정 useEffect(() => { @@ -44,9 +45,12 @@ const CreateUnitPage = () => { createUnit(courseId, unit), onSuccess: (data) => { // 단원 목록 갱신 - alert('새 단원이 성공적으로 생성되었습니다.'); setSelectedUnitId(data.response.id); setIsEditing(true); // 새 단원 생성 후 편집 모드로 전환 + queryClient.invalidateQueries({ + queryKey: allUnitsQueryOptions(Number(id)).queryKey, + }); + alert('새 단원이 성공적으로 생성되었습니다.'); }, onError: (error) => { console.error('단원 생성 실패', error); From 6c0812ce21985b6bc51bc0d9ed54ce8bbd8d692c Mon Sep 17 00:00:00 2001 From: suminb99 Date: Sat, 14 Feb 2026 02:59:01 +0900 Subject: [PATCH 50/91] =?UTF-8?q?#44=20refactor:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EC=98=B5=EC=85=98=EC=9D=84=20unitQueries?= =?UTF-8?q?=20=EA=B0=9D=EC=B2=B4=EB=A1=9C=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitQueryOptions.ts | 43 +++++++++-------------- src/pages/create-unit/CreateUnitPage.tsx | 21 +++++------ 2 files changed, 25 insertions(+), 39 deletions(-) diff --git a/src/entities/unit/api/unitQueryOptions.ts b/src/entities/unit/api/unitQueryOptions.ts index c6a1803..0347fd1 100644 --- a/src/entities/unit/api/unitQueryOptions.ts +++ b/src/entities/unit/api/unitQueryOptions.ts @@ -1,30 +1,19 @@ import {queryOptions} from '@tanstack/react-query'; -import {createUnit, getAllUnitsByCourseId, getUnitById} from './unitApi'; -import type {TUnitFormSchema} from '@/pages/create-unit/model/types'; +import {getAllUnitsByCourseId, getUnitById} from './unitApi'; -// 강의별 전체 단원 조회 쿼리 옵션 -export function allUnitsQueryOptions(courseId: number) { - return queryOptions({ - queryKey: ['units', courseId], - queryFn: () => getAllUnitsByCourseId(courseId), - }); -} +export const unitQueries = { + // 강의별 전체 단원 조회 쿼리 옵션 + getUnitList: (courseId: number) => + queryOptions({ + queryKey: ['unit', courseId], + queryFn: () => getAllUnitsByCourseId(courseId), + }), -// 단일 단원 조회 쿼리 옵션 -export function unitQueryOptions(unitId: number | null) { - return queryOptions({ - queryKey: ['unit', unitId], - queryFn: () => getUnitById(unitId), - enabled: !!unitId && unitId !== -1, // unitId가 null이거나 -1인 경우 쿼리 비활성화 - }); -} - -export function createUnitQueryOptions( - courseId: number, - unit: TUnitFormSchema -) { - return queryOptions({ - queryKey: ['createUnit', courseId, unit], - queryFn: () => createUnit(courseId, unit), - }); -} + // 단일 단원 조회 쿼리 옵션 + getUnitDetails: (unitId: number | null) => + queryOptions({ + queryKey: ['unit', unitId], + queryFn: () => getUnitById(unitId), + enabled: !!unitId && unitId !== -1, + }), +}; diff --git a/src/pages/create-unit/CreateUnitPage.tsx b/src/pages/create-unit/CreateUnitPage.tsx index 77e175b..26621c7 100644 --- a/src/pages/create-unit/CreateUnitPage.tsx +++ b/src/pages/create-unit/CreateUnitPage.tsx @@ -2,10 +2,7 @@ import SurfaceCard from '@/components/common/SurfaceCard'; import UnitFormEditor from './ui/UnitFormEditor'; import UnitList from './ui/UnitList'; import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'; -import { - allUnitsQueryOptions, - unitQueryOptions, -} from '@/entities/unit/api/unitQueryOptions'; +import {unitQueries} from '@/entities/unit/api/unitQueryOptions'; import {useParams} from 'react-router-dom'; import {useEffect, useState} from 'react'; import {createUnit} from '@/entities/unit/api/unitApi'; @@ -16,17 +13,17 @@ const CreateUnitPage = () => { const [selectedUnitId, setSelectedUnitId] = useState(null); const [currentIndex, setCurrentIndex] = useState(1); const [isEditing, setIsEditing] = useState(false); - const {data: allUnits} = useQuery(allUnitsQueryOptions(Number(id))); - const {data: unit} = useQuery(unitQueryOptions(selectedUnitId)); + const {data: unitList} = useQuery(unitQueries.getUnitList(Number(id))); + const {data: unit} = useQuery(unitQueries.getUnitDetails(selectedUnitId)); const queryClient = useQueryClient(); // 단원 목록에서 선택된 단원이 없을 때, 첫 번째 단원을 선택하도록 설정 useEffect(() => { - if (allUnits && allUnits.response.count !== 0 && selectedUnitId === null) { - setSelectedUnitId(allUnits.response.units[0].id); + if (unitList && unitList.response.count !== 0 && selectedUnitId === null) { + setSelectedUnitId(unitList.response.units[0].id); setIsEditing(true); // 첫 번째 단원이 선택되면 편집 모드로 전환 } - }, [allUnits, selectedUnitId]); + }, [unitList, selectedUnitId]); const onUnitClick = (id: number) => { setSelectedUnitId(id); @@ -35,7 +32,7 @@ const CreateUnitPage = () => { const onAddNewUnit = () => { setSelectedUnitId(-1); - setCurrentIndex(allUnits ? allUnits.response.count + 1 : 1); // 새 단원의 인덱스 설정 + setCurrentIndex(unitList ? unitList.response.count + 1 : 1); // 새 단원의 인덱스 설정 setIsEditing(false); // 새 단원 추가 시 편집 모드 해제 }; @@ -48,7 +45,7 @@ const CreateUnitPage = () => { setSelectedUnitId(data.response.id); setIsEditing(true); // 새 단원 생성 후 편집 모드로 전환 queryClient.invalidateQueries({ - queryKey: allUnitsQueryOptions(Number(id)).queryKey, + queryKey: unitQueries.getUnitList(Number(id)).queryKey, }); alert('새 단원이 성공적으로 생성되었습니다.'); }, @@ -68,7 +65,7 @@ const CreateUnitPage = () => { {/* 단원 목차 섹션 */} setCurrentIndex(index)} selectedUnitId={selectedUnitId} From 2a16b75568dbcd9e5a07ba7cd334b5f70f100d58 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Sat, 14 Feb 2026 03:10:51 +0900 Subject: [PATCH 51/91] =?UTF-8?q?#44=20refactor:=20queryKey=20=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=EB=B0=8D=20=EB=B0=8F=20=EA=B5=AC=EC=A1=B0=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitQueryOptions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/entities/unit/api/unitQueryOptions.ts b/src/entities/unit/api/unitQueryOptions.ts index 0347fd1..aa9b044 100644 --- a/src/entities/unit/api/unitQueryOptions.ts +++ b/src/entities/unit/api/unitQueryOptions.ts @@ -5,14 +5,14 @@ export const unitQueries = { // 강의별 전체 단원 조회 쿼리 옵션 getUnitList: (courseId: number) => queryOptions({ - queryKey: ['unit', courseId], + queryKey: ['units', courseId], queryFn: () => getAllUnitsByCourseId(courseId), }), // 단일 단원 조회 쿼리 옵션 getUnitDetails: (unitId: number | null) => queryOptions({ - queryKey: ['unit', unitId], + queryKey: ['units', 'detail', unitId], queryFn: () => getUnitById(unitId), enabled: !!unitId && unitId !== -1, }), From 8585c2c0d546cf72f22931fd14ce914bd1b72656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:20:55 +0900 Subject: [PATCH 52/91] =?UTF-8?q?#47=20refactor:=20=EA=B3=B5=ED=86=B5=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=A5=BC=20shared/ui?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20(components,=20layout=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/assignments/AssignmentCard.tsx | 56 --------- .../assignments/AssignmentFormLayout.tsx | 51 -------- .../admin/assignments/dummy/response.ts | 119 ------------------ .../admin/assignments/dummy/types.ts | 34 ----- .../common => shared/ui}/ActionButton.tsx | 0 .../common => shared/ui}/Badge.tsx | 0 .../common => shared/ui}/BaseHeader.tsx | 0 .../common => shared/ui}/Button.tsx | 0 .../common => shared/ui}/Checkbox.module.css | 0 .../common => shared/ui}/Checkbox.tsx | 0 .../common => shared/ui}/Dropdown.tsx | 0 .../common => shared/ui}/EmptyState.tsx | 0 .../admin/form => shared/ui}/FileUpload.tsx | 0 .../common => shared/ui}/Header.tsx | 4 +- .../common => shared/ui}/IconButton.tsx | 0 .../common => shared/ui}/Input.tsx | 0 .../form => shared/ui}/LabeledDropdown.tsx | 2 +- .../admin/form => shared/ui}/LabeledInput.tsx | 0 src/{layout => shared/ui}/Layout.tsx | 2 +- src/shared/ui/PrivateRoute.tsx | 7 -- .../ui}/ProgressIndicators.tsx | 0 .../common => shared/ui}/SelectableItem.tsx | 0 .../common => shared/ui}/SurfaceCard.tsx | 0 23 files changed, 4 insertions(+), 271 deletions(-) delete mode 100644 src/components/admin/assignments/AssignmentCard.tsx delete mode 100644 src/components/admin/assignments/AssignmentFormLayout.tsx delete mode 100644 src/components/admin/assignments/dummy/response.ts delete mode 100644 src/components/admin/assignments/dummy/types.ts rename src/{components/common => shared/ui}/ActionButton.tsx (100%) rename src/{components/common => shared/ui}/Badge.tsx (100%) rename src/{components/common => shared/ui}/BaseHeader.tsx (100%) rename src/{components/common => shared/ui}/Button.tsx (100%) rename src/{components/common => shared/ui}/Checkbox.module.css (100%) rename src/{components/common => shared/ui}/Checkbox.tsx (100%) rename src/{components/common => shared/ui}/Dropdown.tsx (100%) rename src/{components/common => shared/ui}/EmptyState.tsx (100%) rename src/{components/admin/form => shared/ui}/FileUpload.tsx (100%) rename src/{components/common => shared/ui}/Header.tsx (96%) rename src/{components/common => shared/ui}/IconButton.tsx (100%) rename src/{components/common => shared/ui}/Input.tsx (100%) rename src/{components/admin/form => shared/ui}/LabeledDropdown.tsx (96%) rename src/{components/admin/form => shared/ui}/LabeledInput.tsx (100%) rename src/{layout => shared/ui}/Layout.tsx (92%) delete mode 100644 src/shared/ui/PrivateRoute.tsx rename src/{components/common => shared/ui}/ProgressIndicators.tsx (100%) rename src/{components/common => shared/ui}/SelectableItem.tsx (100%) rename src/{components/common => shared/ui}/SurfaceCard.tsx (100%) diff --git a/src/components/admin/assignments/AssignmentCard.tsx b/src/components/admin/assignments/AssignmentCard.tsx deleted file mode 100644 index 9dfc275..0000000 --- a/src/components/admin/assignments/AssignmentCard.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import {useState} from 'react'; -import SingleEllipsisIcon from '@/assets/svg/singleEllipsisIcon.svg?react'; -import DragAndDropIcon from '@/assets/svg/dragAndDropIcon.svg?react'; -import DeleteIcon from '@/assets/svg/deleteIcon.svg?react'; -import EditIcon from '@/assets/svg/editIcon.svg?react'; -import type {Assignment} from './dummy/types'; - -interface AssignmentCardProps extends Assignment { - selectMode: boolean; - onLinkAssignments?: (id: number, title: string, isSelected: boolean) => void; -} - -const AssignmentCard = ({ - id, - title, - selectMode, - onLinkAssignments, -}: AssignmentCardProps) => { - const [isSelected, setIsSelected] = useState(false); - const handleOnClick = () => { - const selectedState = !isSelected; - setIsSelected(selectedState); - onLinkAssignments?.(id, title, selectedState); - }; - - return ( -
      -
      - {selectMode ? ( - - ) : ( - - )} -
      {title}
      -
      - {!selectMode && ( -
      - - -
      - )} -
      - ); -}; - -export default AssignmentCard; diff --git a/src/components/admin/assignments/AssignmentFormLayout.tsx b/src/components/admin/assignments/AssignmentFormLayout.tsx deleted file mode 100644 index e3e2d07..0000000 --- a/src/components/admin/assignments/AssignmentFormLayout.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import Button from '@/components/common/Button'; -import SurfaceCard from '@/components/common/SurfaceCard'; - -type AssignmentFormLayoutProps = { - title: string; - titleExtra?: React.ReactNode; - content: React.ReactNode; - onCancel: () => void; - onConfirm: () => void; - cancelLabel?: string; - confirmLabel?: string; -}; - -const AssignmentFormLayout = ({ - title, - titleExtra, - content, - onCancel, - onConfirm, - cancelLabel = '취소', - confirmLabel = '저장', -}: AssignmentFormLayoutProps) => { - return ( -
      - - {/* 제목 */} -
      -

      {title}

      - {titleExtra} -
      - - {/* 본문 */} -
      {content}
      - - {/* 하단 버튼 */} -
      - - -
      -
      -
      - ); -}; - -export default AssignmentFormLayout; diff --git a/src/components/admin/assignments/dummy/response.ts b/src/components/admin/assignments/dummy/response.ts deleted file mode 100644 index 596ebb5..0000000 --- a/src/components/admin/assignments/dummy/response.ts +++ /dev/null @@ -1,119 +0,0 @@ -import type {CoursesResponse} from './types'; - -export const coursesResponse: CoursesResponse = { - success: true, - response: { - count: 5, - courses: [ - { - id: 1, - title: '데이터구조와 알고리즘', - year: 2025, - semester: 'FIRST', - section: '002', - count: 5, - assignments: [ - {id: 1, title: '날씨 데이터로 크롤링하기'}, - {id: 3, title: '정렬 알고리즘 구현하기'}, - {id: 5, title: '스택과 큐로 계산기 만들기'}, - {id: 6, title: '이진 트리 순회'}, - {id: 7, title: '그래프 탐색 시각화'}, - ], - }, - { - id: 2, - title: '컴퓨터수학', - year: 2025, - semester: 'SECOND', - section: '003', - count: 2, - assignments: [ - {id: 2, title: '행렬 연산 연습문제'}, - {id: 4, title: '이산 수학과 부울 대수'}, - ], - }, - { - id: 3, - title: '운영체제', - year: 2025, - semester: 'SECOND', - section: '001', - count: 3, - assignments: [ - {id: 8, title: 'CPU 스케줄링 시뮬레이터'}, - {id: 9, title: '가상 메모리 구조 분석'}, - {id: 10, title: '프로세스 동기화 실습'}, - ], - }, - { - id: 4, - title: '웹프로그래밍', - year: 2025, - semester: 'SUMMER', - section: '101', - count: 4, - assignments: [ - {id: 11, title: 'HTML/CSS로 개인 홈페이지 만들기'}, - {id: 12, title: 'JavaScript 인터랙션 추가하기'}, - {id: 13, title: 'React로 게시판 구현'}, - {id: 14, title: 'API 연동 과제'}, - ], - }, - { - id: 5, - title: 'AI기초', - year: 2025, - semester: 'WINTER', - section: '201', - count: 3, - assignments: [ - {id: 15, title: '선형회귀 모델 구현'}, - {id: 16, title: '데이터 전처리 실습'}, - {id: 17, title: 'PyTorch 기초 과제'}, - ], - }, - { - id: 6, - title: '소프트웨어의 이해', - year: 2025, - semester: 'WINTER', - section: '005', - count: 3, - assignments: [ - {id: 18, title: '음수 구별하기'}, - {id: 19, title: '조건문과 반복문을 활용한 계산기 만들기'}, - {id: 20, title: '리스트와 튜플의 활용'}, - ], - }, - { - id: 7, - title: '소프트웨어의 이해', - year: 2025, - semester: 'FIRST', - section: '005', - count: 5, - assignments: [ - {id: 21, title: '음수 구별하기'}, - {id: 22, title: '조건문과 반복문을 활용한 계산기 만들기'}, - {id: 23, title: '딕셔너리와 집합의 활용'}, - {id: 24, title: '파이썬에서의 날짜와 시간 처리'}, - {id: 25, title: '클래스와 객체 지향 프로그래밍'}, - ], - }, - { - id: 8, - title: '소프트웨어의 이해', - year: 2025, - semester: 'SECOND', - section: '001', - count: 4, - assignments: [ - {id: 26, title: '음수 구별하기'}, - {id: 27, title: '조건문과 반복문을 활용한 계산기 만들기'}, - {id: 28, title: '리스트와 튜플의 활용'}, - {id: 29, title: '파이썬에서의 예외 처리'}, - ], - }, - ], - }, -}; diff --git a/src/components/admin/assignments/dummy/types.ts b/src/components/admin/assignments/dummy/types.ts deleted file mode 100644 index c07b420..0000000 --- a/src/components/admin/assignments/dummy/types.ts +++ /dev/null @@ -1,34 +0,0 @@ -type SemesterCode = 'FIRST' | 'SECOND' | 'SUMMER' | 'WINTER'; -type SubmissionStatus = 'NOT_SUBMITTED' | 'CORRECT' | 'INCORRECT'; - -interface Assignment { - id: number; - title: string; - submittedStatus?: SubmissionStatus; -} - -interface Course { - id: number; - title: string; - year: number; - semester: SemesterCode; - section: string; - count: number; - assignments: Assignment[]; -} - -interface CoursesResponse { - success: boolean; - response: { - count: number; - courses: Course[]; - }; -} - -export type { - Assignment, - Course, - CoursesResponse, - SemesterCode, - SubmissionStatus, -}; diff --git a/src/components/common/ActionButton.tsx b/src/shared/ui/ActionButton.tsx similarity index 100% rename from src/components/common/ActionButton.tsx rename to src/shared/ui/ActionButton.tsx diff --git a/src/components/common/Badge.tsx b/src/shared/ui/Badge.tsx similarity index 100% rename from src/components/common/Badge.tsx rename to src/shared/ui/Badge.tsx diff --git a/src/components/common/BaseHeader.tsx b/src/shared/ui/BaseHeader.tsx similarity index 100% rename from src/components/common/BaseHeader.tsx rename to src/shared/ui/BaseHeader.tsx diff --git a/src/components/common/Button.tsx b/src/shared/ui/Button.tsx similarity index 100% rename from src/components/common/Button.tsx rename to src/shared/ui/Button.tsx diff --git a/src/components/common/Checkbox.module.css b/src/shared/ui/Checkbox.module.css similarity index 100% rename from src/components/common/Checkbox.module.css rename to src/shared/ui/Checkbox.module.css diff --git a/src/components/common/Checkbox.tsx b/src/shared/ui/Checkbox.tsx similarity index 100% rename from src/components/common/Checkbox.tsx rename to src/shared/ui/Checkbox.tsx diff --git a/src/components/common/Dropdown.tsx b/src/shared/ui/Dropdown.tsx similarity index 100% rename from src/components/common/Dropdown.tsx rename to src/shared/ui/Dropdown.tsx diff --git a/src/components/common/EmptyState.tsx b/src/shared/ui/EmptyState.tsx similarity index 100% rename from src/components/common/EmptyState.tsx rename to src/shared/ui/EmptyState.tsx diff --git a/src/components/admin/form/FileUpload.tsx b/src/shared/ui/FileUpload.tsx similarity index 100% rename from src/components/admin/form/FileUpload.tsx rename to src/shared/ui/FileUpload.tsx diff --git a/src/components/common/Header.tsx b/src/shared/ui/Header.tsx similarity index 96% rename from src/components/common/Header.tsx rename to src/shared/ui/Header.tsx index 6b0fc13..30baf63 100644 --- a/src/components/common/Header.tsx +++ b/src/shared/ui/Header.tsx @@ -1,10 +1,10 @@ import {useNavigate} from 'react-router-dom'; -import BaseHeader from '@/components/common/BaseHeader'; +import BaseHeader from '@/shared/ui/BaseHeader'; import NotificationIcon from '@/assets/svg/notificationIcon.svg?react'; import SignoutIcon from '@/assets/svg/signoutIcon.svg?react'; import UserIcon from '@/assets/svg/userIcon.svg?react'; import ChatIcon from '@/assets/svg/chatIcon.svg?react'; -import Button from '@/components/common/Button'; +import Button from '@/shared/ui/Button'; import {useUserStore} from '@/entities/auth/model/useUserStore'; interface NavButton { diff --git a/src/components/common/IconButton.tsx b/src/shared/ui/IconButton.tsx similarity index 100% rename from src/components/common/IconButton.tsx rename to src/shared/ui/IconButton.tsx diff --git a/src/components/common/Input.tsx b/src/shared/ui/Input.tsx similarity index 100% rename from src/components/common/Input.tsx rename to src/shared/ui/Input.tsx diff --git a/src/components/admin/form/LabeledDropdown.tsx b/src/shared/ui/LabeledDropdown.tsx similarity index 96% rename from src/components/admin/form/LabeledDropdown.tsx rename to src/shared/ui/LabeledDropdown.tsx index 1e3ba5b..3b27a34 100644 --- a/src/components/admin/form/LabeledDropdown.tsx +++ b/src/shared/ui/LabeledDropdown.tsx @@ -1,6 +1,6 @@ import {useState} from 'react'; import Chevrondown from '@/assets/svg/chevrondown.svg?react'; -import Dropdown from '@/components/common/Dropdown'; +import Dropdown from '@/shared/ui/Dropdown'; interface LabeledDropdownProps extends Omit, 'onSelect'> { diff --git a/src/components/admin/form/LabeledInput.tsx b/src/shared/ui/LabeledInput.tsx similarity index 100% rename from src/components/admin/form/LabeledInput.tsx rename to src/shared/ui/LabeledInput.tsx diff --git a/src/layout/Layout.tsx b/src/shared/ui/Layout.tsx similarity index 92% rename from src/layout/Layout.tsx rename to src/shared/ui/Layout.tsx index a864ee4..a99e338 100644 --- a/src/layout/Layout.tsx +++ b/src/shared/ui/Layout.tsx @@ -1,5 +1,5 @@ import {useLocation, Outlet} from 'react-router-dom'; -import Header from '@/components/common/Header'; +import Header from '@/shared/ui/Header'; const Layout = () => { const location = useLocation(); diff --git a/src/shared/ui/PrivateRoute.tsx b/src/shared/ui/PrivateRoute.tsx deleted file mode 100644 index 7aa97bb..0000000 --- a/src/shared/ui/PrivateRoute.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import {Navigate, Outlet} from 'react-router-dom'; -import {useUserStore} from '@/entities/auth/model/useUserStore'; - -export default function PrivateRoute() { - const {isAuthenticated} = useUserStore(); - return isAuthenticated ? : ; -} diff --git a/src/components/common/ProgressIndicators.tsx b/src/shared/ui/ProgressIndicators.tsx similarity index 100% rename from src/components/common/ProgressIndicators.tsx rename to src/shared/ui/ProgressIndicators.tsx diff --git a/src/components/common/SelectableItem.tsx b/src/shared/ui/SelectableItem.tsx similarity index 100% rename from src/components/common/SelectableItem.tsx rename to src/shared/ui/SelectableItem.tsx diff --git a/src/components/common/SurfaceCard.tsx b/src/shared/ui/SurfaceCard.tsx similarity index 100% rename from src/components/common/SurfaceCard.tsx rename to src/shared/ui/SurfaceCard.tsx From 8594c593e606c5840142da1d0e49038e2a0989e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:22:10 +0900 Subject: [PATCH 53/91] =?UTF-8?q?#47=20refactor:=20AssignmentFormLayout?= =?UTF-8?q?=EC=9D=84=20widgets=EB=A1=9C=20=EC=9D=B4=EB=8F=99,=20mock=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A5=BC=20shared/mocks=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/mocks/assignmentDummyResponse.ts | 119 ++++++++++++++++++ src/shared/mocks/assignmentDummyTypes.ts | 34 +++++ src/shared/mocks/assignmentSelectResponse.ts | 104 +++++++++++++++ src/shared/mocks/courseOverviewResponse.ts | 115 +++++++++++++++++ src/shared/mocks/dashboardCourseList.ts | 32 +++++ src/shared/mocks/dashboardScheduleList.ts | 59 +++++++++ .../ui/AssignmentFormLayout.tsx | 51 ++++++++ 7 files changed, 514 insertions(+) create mode 100644 src/shared/mocks/assignmentDummyResponse.ts create mode 100644 src/shared/mocks/assignmentDummyTypes.ts create mode 100644 src/shared/mocks/assignmentSelectResponse.ts create mode 100644 src/shared/mocks/courseOverviewResponse.ts create mode 100644 src/shared/mocks/dashboardCourseList.ts create mode 100644 src/shared/mocks/dashboardScheduleList.ts create mode 100644 src/widgets/assignment-form-layout/ui/AssignmentFormLayout.tsx diff --git a/src/shared/mocks/assignmentDummyResponse.ts b/src/shared/mocks/assignmentDummyResponse.ts new file mode 100644 index 0000000..55f4810 --- /dev/null +++ b/src/shared/mocks/assignmentDummyResponse.ts @@ -0,0 +1,119 @@ +import type {CoursesResponse} from '@/shared/mocks/assignmentDummyTypes'; + +export const coursesResponse: CoursesResponse = { + success: true, + response: { + count: 5, + courses: [ + { + id: 1, + title: '데이터구조와 알고리즘', + year: 2025, + semester: 'FIRST', + section: '002', + count: 5, + assignments: [ + {id: 1, title: '날씨 데이터로 크롤링하기'}, + {id: 3, title: '정렬 알고리즘 구현하기'}, + {id: 5, title: '스택과 큐로 계산기 만들기'}, + {id: 6, title: '이진 트리 순회'}, + {id: 7, title: '그래프 탐색 시각화'}, + ], + }, + { + id: 2, + title: '컴퓨터수학', + year: 2025, + semester: 'SECOND', + section: '003', + count: 2, + assignments: [ + {id: 2, title: '행렬 연산 연습문제'}, + {id: 4, title: '이산 수학과 부울 대수'}, + ], + }, + { + id: 3, + title: '운영체제', + year: 2025, + semester: 'SECOND', + section: '001', + count: 3, + assignments: [ + {id: 8, title: 'CPU 스케줄링 시뮬레이터'}, + {id: 9, title: '가상 메모리 구조 분석'}, + {id: 10, title: '프로세스 동기화 실습'}, + ], + }, + { + id: 4, + title: '웹프로그래밍', + year: 2025, + semester: 'SUMMER', + section: '101', + count: 4, + assignments: [ + {id: 11, title: 'HTML/CSS로 개인 홈페이지 만들기'}, + {id: 12, title: 'JavaScript 인터랙션 추가하기'}, + {id: 13, title: 'React로 게시판 구현'}, + {id: 14, title: 'API 연동 과제'}, + ], + }, + { + id: 5, + title: 'AI기초', + year: 2025, + semester: 'WINTER', + section: '201', + count: 3, + assignments: [ + {id: 15, title: '선형회귀 모델 구현'}, + {id: 16, title: '데이터 전처리 실습'}, + {id: 17, title: 'PyTorch 기초 과제'}, + ], + }, + { + id: 6, + title: '소프트웨어의 이해', + year: 2025, + semester: 'WINTER', + section: '005', + count: 3, + assignments: [ + {id: 18, title: '음수 구별하기'}, + {id: 19, title: '조건문과 반복문을 활용한 계산기 만들기'}, + {id: 20, title: '리스트와 튜플의 활용'}, + ], + }, + { + id: 7, + title: '소프트웨어의 이해', + year: 2025, + semester: 'FIRST', + section: '005', + count: 5, + assignments: [ + {id: 21, title: '음수 구별하기'}, + {id: 22, title: '조건문과 반복문을 활용한 계산기 만들기'}, + {id: 23, title: '딕셔너리와 집합의 활용'}, + {id: 24, title: '파이썬에서의 날짜와 시간 처리'}, + {id: 25, title: '클래스와 객체 지향 프로그래밍'}, + ], + }, + { + id: 8, + title: '소프트웨어의 이해', + year: 2025, + semester: 'SECOND', + section: '001', + count: 4, + assignments: [ + {id: 26, title: '음수 구별하기'}, + {id: 27, title: '조건문과 반복문을 활용한 계산기 만들기'}, + {id: 28, title: '리스트와 튜플의 활용'}, + {id: 29, title: '파이썬에서의 예외 처리'}, + ], + }, + ], + }, +}; diff --git a/src/shared/mocks/assignmentDummyTypes.ts b/src/shared/mocks/assignmentDummyTypes.ts new file mode 100644 index 0000000..c07b420 --- /dev/null +++ b/src/shared/mocks/assignmentDummyTypes.ts @@ -0,0 +1,34 @@ +type SemesterCode = 'FIRST' | 'SECOND' | 'SUMMER' | 'WINTER'; +type SubmissionStatus = 'NOT_SUBMITTED' | 'CORRECT' | 'INCORRECT'; + +interface Assignment { + id: number; + title: string; + submittedStatus?: SubmissionStatus; +} + +interface Course { + id: number; + title: string; + year: number; + semester: SemesterCode; + section: string; + count: number; + assignments: Assignment[]; +} + +interface CoursesResponse { + success: boolean; + response: { + count: number; + courses: Course[]; + }; +} + +export type { + Assignment, + Course, + CoursesResponse, + SemesterCode, + SubmissionStatus, +}; diff --git a/src/shared/mocks/assignmentSelectResponse.ts b/src/shared/mocks/assignmentSelectResponse.ts new file mode 100644 index 0000000..015419d --- /dev/null +++ b/src/shared/mocks/assignmentSelectResponse.ts @@ -0,0 +1,104 @@ +import type { + AssignmentSelectResponse, + CourseOptionsResponse, +} from '@/entities/course/model/types'; + +export const response: AssignmentSelectResponse = { + success: true, + response: { + count: 2, + courses: [ + { + id: 1, + title: '데이터구조와 알고리즘', + year: 2025, + semester: 'FIRST', + section: '002', + count: 2, + assignments: [ + { + id: 1, + title: '날씨 데이터로 크롤링하기 1', + }, + { + id: 3, + title: '날씨 데이터로 크롤링하기 2', + }, + { + id: 7, + title: '날씨 데이터로 크롤링하기 3', + }, + { + id: 8, + title: '날씨 데이터로 크롤링하기 4', + }, + ], + }, + { + id: 2, + title: '데이터구조와 알고리즘', + year: 2025, + semester: 'SECOND', + section: '003', + count: 2, + assignments: [ + { + id: 2, + title: '날씨 데이터로 크롤링하기 5', + }, + { + id: 4, + title: '날씨 데이터로 크롤링하기 6', + }, + { + id: 5, + title: '날씨 데이터로 크롤링하기 7', + }, + { + id: 6, + title: '날씨 데이터로 크롤링하기 8', + }, + ], + }, + ], + }, +}; + +export const courseOptionsResponse: CourseOptionsResponse = { + success: true, + response: { + count: 3, + courses: [ + { + id: 1, + year: 2025, + semester: 'SUMMER', + section: '001', + title: '소프트웨어의이해', + description: '소프트웨어의이해 강의는 파이썬을 배웁니다.', + unitCount: 3, + assignmentCount: 10, + }, + { + id: 2, + year: 2025, + semester: 'SUMMER', + section: '001', + title: '소프트웨어의이해', + description: '소프트웨어의이해 강의는 파이썬을 배웁니다.', + unitCount: 3, + assignmentCount: 10, + }, + { + id: 3, + year: 2025, + semester: 'SUMMER', + section: '001', + title: '소프트웨어의이해', + description: '소프트웨어의이해 강의는 파이썬을 배웁니다.', + unitCount: 3, + assignmentCount: 10, + }, + ], + }, +}; diff --git a/src/shared/mocks/courseOverviewResponse.ts b/src/shared/mocks/courseOverviewResponse.ts new file mode 100644 index 0000000..0ac91fc --- /dev/null +++ b/src/shared/mocks/courseOverviewResponse.ts @@ -0,0 +1,115 @@ +import type {CourseOverviewResponse} from '@/entities/course/model/types'; + +export const courseResponse: CourseOverviewResponse = { + success: true, + response: { + id: 1, + title: '소프트웨어의 이해', + year: 2025, + semester: 'FIRST', + section: '005', + studentCount: 56, + unitCount: 2, + units: [ + { + id: 1, + title: '변수와 수식', + releaseDate: '2025-06-19', + dueDate: '2025-06-25', + isOpen: true, + assignmentCount: 2, + assignments: [ + { + id: 1, + title: '음수 구별하기', + submittedStatus: 'CORRECT', + }, + { + id: 2, + title: '수식 작성 및 결과 확인 실습 과제', + submittedStatus: 'CORRECT', + }, + { + id: 3, + title: '변수 선언 후 값 출력해보기', + submittedStatus: 'NOT_SUBMITTED', + }, + { + id: 4, + title: '변수 수식 결과를 저장해보세요', + submittedStatus: 'INCORRECT', + }, + ], + }, + { + id: 3, + title: '반복문과 조건문', + releaseDate: '2025-06-19', + dueDate: '2025-06-25', + isOpen: false, + assignmentCount: 2, + assignments: [ + { + id: 4, + title: '짝수와 음수 구별하기', + submittedStatus: 'NOT_SUBMITTED', + }, + { + id: 5, + title: '숫자 맞히기 프로그램 만들기 실습', + submittedStatus: 'NOT_SUBMITTED', + }, + ], + }, + ], + }, +}; + +// export const courseResponse: CourseResponse = { +// success: true, +// response: { +// id: 1, +// title: '소프트웨어의 이해', +// year: 2025, +// semester: 'FIRST', +// section: '005', +// studentCount: 56, +// unitCount: 2, +// units: [ +// { +// id: 1, +// title: '변수와 수식', +// releaseDate: '2025-06-19', +// dueDate: '2025-06-25', +// assignmentCount: 2, +// assignments: [ +// { +// id: 1, +// title: '음수 구별하기', +// }, +// { +// id: 3, +// title: '변수 선언 후 값 출력해보기', +// }, +// ], +// }, +// { +// id: 3, +// title: '반복문과 조건문', +// releaseDate: '2025-06-19', +// dueDate: '2025-06-25', +// assignmentCount: 2, +// assignments: [ +// { +// id: 4, +// title: '짝수와 음수 구별하기', +// }, +// { +// id: 5, +// title: '숫자 맞히기 프로그램 만들기 실습', +// }, +// ], +// }, +// ], +// }, +// }; diff --git a/src/shared/mocks/dashboardCourseList.ts b/src/shared/mocks/dashboardCourseList.ts new file mode 100644 index 0000000..e5edffe --- /dev/null +++ b/src/shared/mocks/dashboardCourseList.ts @@ -0,0 +1,32 @@ +import type {DashboardCourseListResponse} from '@/entities/course/model/types'; + +export const responseCourseList: DashboardCourseListResponse = { + success: true, + response: { + count: 2, + courses: [ + { + id: 1, + year: 2025, + semester: 'FIRST', + section: '005', + title: '소프트웨어의 이해', + description: + 'Python 언어를 기반으로 하여 프로그래밍에 대한 기본 원리를 학습한다.', + unitCount: 3, + assignmentCount: 2, + }, + { + id: 2, + year: 2025, + semester: 'FIRST', + section: '005', + title: '소프트웨어의 이해', + description: + 'Python 언어를 기반으로 하여 프로그래밍에 대한 기본 원리를 학습한다.', + unitCount: 3, + assignmentCount: 2, + }, + ], + }, +}; diff --git a/src/shared/mocks/dashboardScheduleList.ts b/src/shared/mocks/dashboardScheduleList.ts new file mode 100644 index 0000000..9f81edd --- /dev/null +++ b/src/shared/mocks/dashboardScheduleList.ts @@ -0,0 +1,59 @@ +import type {DashboardScheduleListResponse} from '@/entities/course/model/types'; + +export const responseScheduleList: DashboardScheduleListResponse = { + success: true, + response: { + count: 4, + schedule: [ + { + date: '2025-07-20', + remainingDays: 0, + assignments: [ + { + course: '데이터구조와 알고리즘', + section: '002', + assignment: 'final', + }, + ], + }, + { + date: '2025-07-21', + remainingDays: 1, + assignments: [ + { + course: '데이터구조와 알고리즘', + section: '002', + assignment: 'file', + }, + ], + }, + { + date: '2025-07-22', + remainingDays: 2, + assignments: [ + { + course: 'test', + section: '003', + assignment: '확인용', + }, + ], + }, + { + date: '2025-07-26', + remainingDays: 6, + assignments: [ + { + course: 'Python을 활용한 데이터 분석', + section: '005', + assignment: '날씨 데이터를 활용한 기온 변화 분석', + }, + { + course: '소프트웨어의이해', + section: '005', + assignment: '날씨 확인', + }, + ], + }, + ], + }, +}; diff --git a/src/widgets/assignment-form-layout/ui/AssignmentFormLayout.tsx b/src/widgets/assignment-form-layout/ui/AssignmentFormLayout.tsx new file mode 100644 index 0000000..461335a --- /dev/null +++ b/src/widgets/assignment-form-layout/ui/AssignmentFormLayout.tsx @@ -0,0 +1,51 @@ +import Button from '@/shared/ui/Button'; +import SurfaceCard from '@/shared/ui/SurfaceCard'; + +type AssignmentFormLayoutProps = { + title: string; + titleExtra?: React.ReactNode; + content: React.ReactNode; + onCancel: () => void; + onConfirm: () => void; + cancelLabel?: string; + confirmLabel?: string; +}; + +const AssignmentFormLayout = ({ + title, + titleExtra, + content, + onCancel, + onConfirm, + cancelLabel = '취소', + confirmLabel = '저장', +}: AssignmentFormLayoutProps) => { + return ( +
      + + {/* 제목 */} +
      +

      {title}

      + {titleExtra} +
      + + {/* 본문 */} +
      {content}
      + + {/* 하단 버튼 */} +
      + + +
      +
      +
      + ); +}; + +export default AssignmentFormLayout; From dce96909e0942058f6389379aef49cef9ffcfc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:22:44 +0900 Subject: [PATCH 54/91] =?UTF-8?q?#47=20refactor:=20pages=EB=A5=BC=20?= =?UTF-8?q?=EC=97=AD=ED=95=A0=EB=B3=84=EB=A1=9C=20=EB=B6=84=EB=A6=AC=20(st?= =?UTF-8?q?udent/,=20admin/,=20common/)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 25 ++-- src/pages/course-overview/models/response.ts | 115 ------------------ src/pages/course-overview/models/types.ts | 66 ---------- .../dashboard/models/ResponseCourseList.ts | 32 ----- .../dashboard/models/ResponseScheduleList.ts | 59 --------- src/pages/dashboard/models/types.ts | 32 ----- src/pages/select-assignment/mocks/response.ts | 104 ---------------- .../course-overview/CourseOverviewPage.tsx | 2 +- .../course-overview/ui/AssignmentList.tsx | 18 ++- .../course-overview/ui/CourseActionsBar.tsx | 2 +- .../course-overview/ui/CourseContent.tsx | 12 +- .../course-overview/ui/CourseHero.tsx | 29 +++-- .../course-overview/ui/UnitItem.tsx | 13 +- .../{ => student}/dashboard/Dashboard.tsx | 4 +- .../{ => student}/dashboard/ui/CourseCard.tsx | 6 +- .../{ => student}/dashboard/ui/CourseList.tsx | 8 +- .../dashboard/ui/CourseManagementDropdown.tsx | 12 +- .../dashboard/ui/ScheduleCard.tsx | 10 +- .../dashboard/ui/ScheduleList.tsx | 9 +- .../AssignmentSelectPage.tsx | 7 +- .../ui/AssignmentListContainer.tsx | 0 21 files changed, 94 insertions(+), 471 deletions(-) delete mode 100644 src/pages/course-overview/models/response.ts delete mode 100644 src/pages/course-overview/models/types.ts delete mode 100644 src/pages/dashboard/models/ResponseCourseList.ts delete mode 100644 src/pages/dashboard/models/ResponseScheduleList.ts delete mode 100644 src/pages/dashboard/models/types.ts delete mode 100644 src/pages/select-assignment/mocks/response.ts rename src/pages/{ => student}/course-overview/CourseOverviewPage.tsx (91%) rename src/pages/{ => student}/course-overview/ui/AssignmentList.tsx (86%) rename src/pages/{ => student}/course-overview/ui/CourseActionsBar.tsx (91%) rename src/pages/{ => student}/course-overview/ui/CourseContent.tsx (83%) rename src/pages/{ => student}/course-overview/ui/CourseHero.tsx (82%) rename src/pages/{ => student}/course-overview/ui/UnitItem.tsx (85%) rename src/pages/{ => student}/dashboard/Dashboard.tsx (96%) rename src/pages/{ => student}/dashboard/ui/CourseCard.tsx (92%) rename src/pages/{ => student}/dashboard/ui/CourseList.tsx (66%) rename src/pages/{ => student}/dashboard/ui/CourseManagementDropdown.tsx (74%) rename src/pages/{ => student}/dashboard/ui/ScheduleCard.tsx (76%) rename src/pages/{ => student}/dashboard/ui/ScheduleList.tsx (88%) rename src/pages/{ => student}/select-assignment/AssignmentSelectPage.tsx (87%) rename src/pages/{ => student}/select-assignment/ui/AssignmentListContainer.tsx (100%) diff --git a/src/App.tsx b/src/App.tsx index 72e176b..1693ad5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,31 +1,20 @@ -import {BrowserRouter, Routes, Route, useLocation} from 'react-router-dom'; -import Layout from '@/layout/Layout'; +import {BrowserRouter, Routes, Route} from 'react-router-dom'; +import Layout from '@/shared/ui/Layout'; import LandingPage from '@/pages/common/LandingPage'; import UserIdInputPage from '@/pages/common/UserIdInputPage'; -import Dashboard from '@/pages/dashboard/Dashboard'; -import AssignmentSelectPage from '@/pages/select-assignment/AssignmentSelectPage'; -import CourseOverviewPage from '@/pages/course-overview/CourseOverviewPage'; +import Dashboard from '@/pages/student/dashboard/Dashboard'; +import AssignmentSelectPage from '@/pages/student/select-assignment/AssignmentSelectPage'; +import CourseOverviewPage from '@/pages/student/course-overview/CourseOverviewPage'; import AssignmentCreatePage from '@/pages/admin/assignments/AssignmentCreatePage'; import CourseCreatePage from '@/pages/admin/courses/CourseCreatePage'; import StudentManagementPage from '@/pages/admin/student/StudentManagementPage'; import StudentProfilePage from '@/pages/admin/student/StudentProfilePage'; import KakaoCallbackPage from '@/pages/common/KakaoCallbackPage'; import PrivateRoute from '@/widgets/private-route/ui/PrivateRoute'; -import {useEffect} from 'react'; -import {useUserStore} from '@/entities/auth/model/useUserStore'; +import {useSyncUserRole} from '@/features/auth/sync-user-role/model/useSyncUserRole'; const AppRoutes = () => { - const {pathname} = useLocation(); - const {setUserType} = useUserStore(); - - useEffect(() => { - const userType = pathname.startsWith('/admin') - ? 'admin' - : pathname.startsWith('/student') - ? 'student' - : 'guest'; - setUserType(userType); - }, [pathname, setUserType]); + useSyncUserRole(); return ( diff --git a/src/pages/course-overview/models/response.ts b/src/pages/course-overview/models/response.ts deleted file mode 100644 index 0ac91fc..0000000 --- a/src/pages/course-overview/models/response.ts +++ /dev/null @@ -1,115 +0,0 @@ -import type {CourseOverviewResponse} from '@/entities/course/model/types'; - -export const courseResponse: CourseOverviewResponse = { - success: true, - response: { - id: 1, - title: '소프트웨어의 이해', - year: 2025, - semester: 'FIRST', - section: '005', - studentCount: 56, - unitCount: 2, - units: [ - { - id: 1, - title: '변수와 수식', - releaseDate: '2025-06-19', - dueDate: '2025-06-25', - isOpen: true, - assignmentCount: 2, - assignments: [ - { - id: 1, - title: '음수 구별하기', - submittedStatus: 'CORRECT', - }, - { - id: 2, - title: '수식 작성 및 결과 확인 실습 과제', - submittedStatus: 'CORRECT', - }, - { - id: 3, - title: '변수 선언 후 값 출력해보기', - submittedStatus: 'NOT_SUBMITTED', - }, - { - id: 4, - title: '변수 수식 결과를 저장해보세요', - submittedStatus: 'INCORRECT', - }, - ], - }, - { - id: 3, - title: '반복문과 조건문', - releaseDate: '2025-06-19', - dueDate: '2025-06-25', - isOpen: false, - assignmentCount: 2, - assignments: [ - { - id: 4, - title: '짝수와 음수 구별하기', - submittedStatus: 'NOT_SUBMITTED', - }, - { - id: 5, - title: '숫자 맞히기 프로그램 만들기 실습', - submittedStatus: 'NOT_SUBMITTED', - }, - ], - }, - ], - }, -}; - -// export const courseResponse: CourseResponse = { -// success: true, -// response: { -// id: 1, -// title: '소프트웨어의 이해', -// year: 2025, -// semester: 'FIRST', -// section: '005', -// studentCount: 56, -// unitCount: 2, -// units: [ -// { -// id: 1, -// title: '변수와 수식', -// releaseDate: '2025-06-19', -// dueDate: '2025-06-25', -// assignmentCount: 2, -// assignments: [ -// { -// id: 1, -// title: '음수 구별하기', -// }, -// { -// id: 3, -// title: '변수 선언 후 값 출력해보기', -// }, -// ], -// }, -// { -// id: 3, -// title: '반복문과 조건문', -// releaseDate: '2025-06-19', -// dueDate: '2025-06-25', -// assignmentCount: 2, -// assignments: [ -// { -// id: 4, -// title: '짝수와 음수 구별하기', -// }, -// { -// id: 5, -// title: '숫자 맞히기 프로그램 만들기 실습', -// }, -// ], -// }, -// ], -// }, -// }; diff --git a/src/pages/course-overview/models/types.ts b/src/pages/course-overview/models/types.ts deleted file mode 100644 index d2c02e6..0000000 --- a/src/pages/course-overview/models/types.ts +++ /dev/null @@ -1,66 +0,0 @@ -import type {Assignment, CourseOverview, Unit} from '@/entities/course/model/types'; - -/** - * CourseHero 컴포넌트 props 타입 정의 - */ -export interface CourseHeroProps { - courseData: Omit; - assignmentCount: number; - isActiveCourse: boolean; -} - -/** - * CourseInfo 컴포넌트 props 타입 정의 - */ -export type CourseInfoProps = Pick< - CourseHeroProps['courseData'], - 'title' | 'year' | 'semester' | 'section' ->; - -/** - * CourseStats 컴포넌트 props 타입 정의 - */ -export interface CourseStatsProps - extends Pick { - assignmentCount: CourseHeroProps['assignmentCount']; - isAdmin: boolean; -} - -/** - * CourseContent 컴포넌트 props 타입 정의 - */ -export interface CourseContentProps { - units: CourseOverview['units']; - isActiveCourse: boolean; -} - -/** - * UnitItem 컴포넌트 props 타입 정의 - */ -export interface UnitProps extends Unit { - index: number; -} - -/** - * UnitHeader 컴포넌트 props 타입 정의 - */ -export type UnitHeaderProps = Omit< - UnitProps, - 'id' | 'assignmentCount' | 'assignments' ->; - -/** - * AssignmentList 컴포넌트 props 타입 정의 - */ -export interface AssignmentListProps { - isOpen?: boolean; - assignments: Assignment[]; -} - -/** - * AssignmentItem 컴포넌트 props 타입 정의 - */ -export interface AssignmentItemProps extends Assignment { - index: number; - isOpen?: boolean; -} diff --git a/src/pages/dashboard/models/ResponseCourseList.ts b/src/pages/dashboard/models/ResponseCourseList.ts deleted file mode 100644 index e5edffe..0000000 --- a/src/pages/dashboard/models/ResponseCourseList.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type {DashboardCourseListResponse} from '@/entities/course/model/types'; - -export const responseCourseList: DashboardCourseListResponse = { - success: true, - response: { - count: 2, - courses: [ - { - id: 1, - year: 2025, - semester: 'FIRST', - section: '005', - title: '소프트웨어의 이해', - description: - 'Python 언어를 기반으로 하여 프로그래밍에 대한 기본 원리를 학습한다.', - unitCount: 3, - assignmentCount: 2, - }, - { - id: 2, - year: 2025, - semester: 'FIRST', - section: '005', - title: '소프트웨어의 이해', - description: - 'Python 언어를 기반으로 하여 프로그래밍에 대한 기본 원리를 학습한다.', - unitCount: 3, - assignmentCount: 2, - }, - ], - }, -}; diff --git a/src/pages/dashboard/models/ResponseScheduleList.ts b/src/pages/dashboard/models/ResponseScheduleList.ts deleted file mode 100644 index 9f81edd..0000000 --- a/src/pages/dashboard/models/ResponseScheduleList.ts +++ /dev/null @@ -1,59 +0,0 @@ -import type {DashboardScheduleListResponse} from '@/entities/course/model/types'; - -export const responseScheduleList: DashboardScheduleListResponse = { - success: true, - response: { - count: 4, - schedule: [ - { - date: '2025-07-20', - remainingDays: 0, - assignments: [ - { - course: '데이터구조와 알고리즘', - section: '002', - assignment: 'final', - }, - ], - }, - { - date: '2025-07-21', - remainingDays: 1, - assignments: [ - { - course: '데이터구조와 알고리즘', - section: '002', - assignment: 'file', - }, - ], - }, - { - date: '2025-07-22', - remainingDays: 2, - assignments: [ - { - course: 'test', - section: '003', - assignment: '확인용', - }, - ], - }, - { - date: '2025-07-26', - remainingDays: 6, - assignments: [ - { - course: 'Python을 활용한 데이터 분석', - section: '005', - assignment: '날씨 데이터를 활용한 기온 변화 분석', - }, - { - course: '소프트웨어의이해', - section: '005', - assignment: '날씨 확인', - }, - ], - }, - ], - }, -}; diff --git a/src/pages/dashboard/models/types.ts b/src/pages/dashboard/models/types.ts deleted file mode 100644 index 08a7ad3..0000000 --- a/src/pages/dashboard/models/types.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type {DashboardCourse, Schedule} from '@/entities/course/model/types'; - -/** - * 강의 목록 컴포넌트 props 타입 - */ -export interface CourseListProps { - courseList: DashboardCourse[]; - onDelete: (courseId: number) => void; -} - -// 스케쥴 할당 타입 -type AssignmentType = Schedule['assignments'][number]; - -/** - * 스케쥴 카드 컴포넌트 props 타입 - */ -export interface ScheduleCardProps extends AssignmentType { - remainingDays: number; -} - -export interface ScheduleListProps { - scheduleList: Schedule[]; -} - -export interface CourseCardProps extends DashboardCourse { - onDelete: (courseId: number) => void; -} - -export interface CourseManagementDropdownProps { - courseId: number; - onDelete: (courseId: number) => void; -} diff --git a/src/pages/select-assignment/mocks/response.ts b/src/pages/select-assignment/mocks/response.ts deleted file mode 100644 index 015419d..0000000 --- a/src/pages/select-assignment/mocks/response.ts +++ /dev/null @@ -1,104 +0,0 @@ -import type { - AssignmentSelectResponse, - CourseOptionsResponse, -} from '@/entities/course/model/types'; - -export const response: AssignmentSelectResponse = { - success: true, - response: { - count: 2, - courses: [ - { - id: 1, - title: '데이터구조와 알고리즘', - year: 2025, - semester: 'FIRST', - section: '002', - count: 2, - assignments: [ - { - id: 1, - title: '날씨 데이터로 크롤링하기 1', - }, - { - id: 3, - title: '날씨 데이터로 크롤링하기 2', - }, - { - id: 7, - title: '날씨 데이터로 크롤링하기 3', - }, - { - id: 8, - title: '날씨 데이터로 크롤링하기 4', - }, - ], - }, - { - id: 2, - title: '데이터구조와 알고리즘', - year: 2025, - semester: 'SECOND', - section: '003', - count: 2, - assignments: [ - { - id: 2, - title: '날씨 데이터로 크롤링하기 5', - }, - { - id: 4, - title: '날씨 데이터로 크롤링하기 6', - }, - { - id: 5, - title: '날씨 데이터로 크롤링하기 7', - }, - { - id: 6, - title: '날씨 데이터로 크롤링하기 8', - }, - ], - }, - ], - }, -}; - -export const courseOptionsResponse: CourseOptionsResponse = { - success: true, - response: { - count: 3, - courses: [ - { - id: 1, - year: 2025, - semester: 'SUMMER', - section: '001', - title: '소프트웨어의이해', - description: '소프트웨어의이해 강의는 파이썬을 배웁니다.', - unitCount: 3, - assignmentCount: 10, - }, - { - id: 2, - year: 2025, - semester: 'SUMMER', - section: '001', - title: '소프트웨어의이해', - description: '소프트웨어의이해 강의는 파이썬을 배웁니다.', - unitCount: 3, - assignmentCount: 10, - }, - { - id: 3, - year: 2025, - semester: 'SUMMER', - section: '001', - title: '소프트웨어의이해', - description: '소프트웨어의이해 강의는 파이썬을 배웁니다.', - unitCount: 3, - assignmentCount: 10, - }, - ], - }, -}; diff --git a/src/pages/course-overview/CourseOverviewPage.tsx b/src/pages/student/course-overview/CourseOverviewPage.tsx similarity index 91% rename from src/pages/course-overview/CourseOverviewPage.tsx rename to src/pages/student/course-overview/CourseOverviewPage.tsx index a25e9f6..e3d8f8a 100644 --- a/src/pages/course-overview/CourseOverviewPage.tsx +++ b/src/pages/student/course-overview/CourseOverviewPage.tsx @@ -1,7 +1,7 @@ import {getTotalAssignmentCount} from '@/shared/lib/course'; import CourseContent from './ui/CourseContent'; import CourseHero from './ui/CourseHero'; -import {courseResponse} from '@/pages/course-overview/models/response'; +import {courseResponse} from '@/shared/mocks/courseOverviewResponse'; const CourseOverviewPage = () => { const courseData = courseResponse.response; diff --git a/src/pages/course-overview/ui/AssignmentList.tsx b/src/pages/student/course-overview/ui/AssignmentList.tsx similarity index 86% rename from src/pages/course-overview/ui/AssignmentList.tsx rename to src/pages/student/course-overview/ui/AssignmentList.tsx index 6ecdaa3..38a3d30 100644 --- a/src/pages/course-overview/ui/AssignmentList.tsx +++ b/src/pages/student/course-overview/ui/AssignmentList.tsx @@ -1,8 +1,17 @@ -import Badge from '@/components/common/Badge'; +import Badge from '@/shared/ui/Badge'; import {Link} from 'react-router-dom'; -import type {AssignmentItemProps, AssignmentListProps} from '../models/types'; +import type {Assignment} from '@/entities/course/model/types'; + +interface AssignmentListProps { + isOpen?: boolean; + assignments: Assignment[]; +} + +interface AssignmentItemProps extends Assignment { + index: number; + isOpen?: boolean; +} -// 문제 목록 const AssignmentList = ({isOpen, assignments}: AssignmentListProps) => { return (
        @@ -18,7 +27,6 @@ const AssignmentList = ({isOpen, assignments}: AssignmentListProps) => { ); }; -// 개별 문제 항목 const AssignmentItem = ({ title, index, @@ -29,7 +37,6 @@ const AssignmentItem = ({ return (
      • - {/* 좌측: 인덱스, 문제명 */}
        @@ -49,7 +56,6 @@ const AssignmentItem = ({ )}
        - {/* 우측: 제출현황 배지 */} {isOpen && (
        { - // 빈 강의 if (isActiveCourse === false) { return ; } @@ -20,7 +24,7 @@ const CourseContent = ({units, isActiveCourse}: CourseContentProps) => { }; const EmptyCourse = () => { - const userType = useUserStore((state) => state.userType); // 유저 타입 확인 + const userType = useUserStore((state) => state.userType); return (
        @@ -29,9 +33,9 @@ const EmptyCourse = () => {

        아직 생성된 단원이 없어요

        - {/* 강의 관리 버튼은 관리자 전용 */} {userType === 'admin' && }
        ); }; + export default CourseContent; diff --git a/src/pages/course-overview/ui/CourseHero.tsx b/src/pages/student/course-overview/ui/CourseHero.tsx similarity index 82% rename from src/pages/course-overview/ui/CourseHero.tsx rename to src/pages/student/course-overview/ui/CourseHero.tsx index 3758c0e..0048b9c 100644 --- a/src/pages/course-overview/ui/CourseHero.tsx +++ b/src/pages/student/course-overview/ui/CourseHero.tsx @@ -2,13 +2,28 @@ import snowcodeOverviewMini from '@/assets/images/snowcode_overview_mini.svg'; import {formatCourseTerm} from '@/shared/lib/course'; import CourseActionsBar from './CourseActionsBar'; import {useUserStore} from '@/entities/auth/model/useUserStore'; -import type { - CourseHeroProps, - CourseInfoProps, - CourseStatsProps, -} from '../models/types'; +import type {CourseOverview, SemesterCode} from '@/entities/course/model/types'; + +interface CourseHeroProps { + courseData: Omit; + assignmentCount: number; + isActiveCourse: boolean; +} + +interface CourseInfoProps { + title: string; + year: number; + semester: SemesterCode; + section: string; +} + +interface CourseStatsProps { + unitCount: number; + assignmentCount: number; + studentCount?: number; + isAdmin: boolean; +} -// 강의 상세 페이지 - Hero 섹션 const CourseHero = ({ courseData, assignmentCount, @@ -44,7 +59,6 @@ const CourseHero = ({ ); }; -// 강의 기본 정보 표시 const CourseInfo = ({title, year, semester, section}: CourseInfoProps) => { return (
        @@ -57,7 +71,6 @@ const CourseInfo = ({title, year, semester, section}: CourseInfoProps) => { ); }; -// 강의 Stats 표시 const CourseStats = ({ unitCount, assignmentCount, diff --git a/src/pages/course-overview/ui/UnitItem.tsx b/src/pages/student/course-overview/ui/UnitItem.tsx similarity index 85% rename from src/pages/course-overview/ui/UnitItem.tsx rename to src/pages/student/course-overview/ui/UnitItem.tsx index 713b4a0..d49b907 100644 --- a/src/pages/course-overview/ui/UnitItem.tsx +++ b/src/pages/student/course-overview/ui/UnitItem.tsx @@ -1,8 +1,14 @@ import AssignmentList from './AssignmentList'; import Lock from '@/assets/svg/lock.svg?react'; -import Badge from '@/components/common/Badge'; +import Badge from '@/shared/ui/Badge'; import {formatPeriod} from '@/shared/lib/course'; -import type {UnitHeaderProps, UnitProps} from '../models/types'; +import type {Unit} from '@/entities/course/model/types'; + +interface UnitProps extends Unit { + index: number; +} + +type UnitHeaderProps = Omit; const UnitItem = ({index, ...unit}: UnitProps) => { const isOpen = unit.isOpen ?? true; @@ -21,7 +27,6 @@ const UnitItem = ({index, ...unit}: UnitProps) => { ); }; -// 단원 헤더 컴포넌트 const UnitHeader = ({ index, title, @@ -32,7 +37,6 @@ const UnitHeader = ({ return (
        - {/* 좌측: 인덱스, 제목, 잠금 아이콘 */}
        {index} @@ -46,7 +50,6 @@ const UnitHeader = ({
        - {/* 우측: 데드라인 */}
        {formatPeriod(releaseDate, dueDate)}
        diff --git a/src/pages/dashboard/Dashboard.tsx b/src/pages/student/dashboard/Dashboard.tsx similarity index 96% rename from src/pages/dashboard/Dashboard.tsx rename to src/pages/student/dashboard/Dashboard.tsx index 9f37d91..7c3f82d 100644 --- a/src/pages/dashboard/Dashboard.tsx +++ b/src/pages/student/dashboard/Dashboard.tsx @@ -1,6 +1,6 @@ import LogoIcon from '@/assets/images/snowCode_logo.svg?react'; import CourseList from './ui/CourseList'; -import Button from '@/components/common/Button'; +import Button from '@/shared/ui/Button'; import AddIcon from '@/assets/svg/addIcon.svg?react'; import ScheduleList from './ui/ScheduleList'; import {Link} from 'react-router-dom'; @@ -13,7 +13,7 @@ import { } from '@tanstack/react-query'; import assignmentQueryOptions from '@/entities/assignment/api/assignmentQueryOptions'; import {deleteCourse} from '@/entities/course'; -import {EmptyState} from '@/components/common/EmptyState'; +import {EmptyState} from '@/shared/ui/EmptyState'; const Dashboard = () => { const userType = useUserStore((state) => state.userType); diff --git a/src/pages/dashboard/ui/CourseCard.tsx b/src/pages/student/dashboard/ui/CourseCard.tsx similarity index 92% rename from src/pages/dashboard/ui/CourseCard.tsx rename to src/pages/student/dashboard/ui/CourseCard.tsx index 070a872..180161b 100644 --- a/src/pages/dashboard/ui/CourseCard.tsx +++ b/src/pages/student/dashboard/ui/CourseCard.tsx @@ -2,7 +2,11 @@ import {formatCourseTermWithSlash} from '@/shared/lib/course'; import CourseManagementDropdown from './CourseManagementDropdown'; import {useNavigate} from 'react-router-dom'; import {useUserStore} from '@/entities/auth/model/useUserStore'; -import type {CourseCardProps} from '../models/types'; +import type {DashboardCourse} from '@/entities/course/model/types'; + +interface CourseCardProps extends DashboardCourse { + onDelete: (courseId: number) => void; +} const CourseCard = ({onDelete, ...course}: CourseCardProps) => { const navigate = useNavigate(); diff --git a/src/pages/dashboard/ui/CourseList.tsx b/src/pages/student/dashboard/ui/CourseList.tsx similarity index 66% rename from src/pages/dashboard/ui/CourseList.tsx rename to src/pages/student/dashboard/ui/CourseList.tsx index 45db5a7..fb480a2 100644 --- a/src/pages/dashboard/ui/CourseList.tsx +++ b/src/pages/student/dashboard/ui/CourseList.tsx @@ -1,7 +1,11 @@ -import type {CourseListProps} from '../models/types'; +import type {DashboardCourse} from '@/entities/course/model/types'; import CourseCard from './CourseCard'; -// 강의 목록 +interface CourseListProps { + courseList: DashboardCourse[]; + onDelete: (courseId: number) => void; +} + const CourseList = ({courseList, onDelete}: CourseListProps) => { return ( <> diff --git a/src/pages/dashboard/ui/CourseManagementDropdown.tsx b/src/pages/student/dashboard/ui/CourseManagementDropdown.tsx similarity index 74% rename from src/pages/dashboard/ui/CourseManagementDropdown.tsx rename to src/pages/student/dashboard/ui/CourseManagementDropdown.tsx index 881d629..ffb18e1 100644 --- a/src/pages/dashboard/ui/CourseManagementDropdown.tsx +++ b/src/pages/student/dashboard/ui/CourseManagementDropdown.tsx @@ -1,7 +1,11 @@ import EllipsisIcon from '@/assets/svg/ellipsisIcon.svg?react'; -import Dropdown from '@/components/common/Dropdown'; +import Dropdown from '@/shared/ui/Dropdown'; import {useNavigate} from 'react-router-dom'; -import type {CourseManagementDropdownProps} from '../models/types'; + +interface CourseManagementDropdownProps { + courseId: number; + onDelete: (courseId: number) => void; +} const COURSE_MENU_OPTIONS = ['수정하기', '삭제하기']; @@ -11,17 +15,15 @@ const CourseManagementDropdown = ({ }: CourseManagementDropdownProps) => { const navigate = useNavigate(); - // 드롭다운 메뉴 옵션 선택 핸들러 const handleSelect = (option: string) => { const actions: Record void> = { - 수정하기: () => navigate('courses/create'), // 강의 생성 페이지 임시 연결 + 수정하기: () => navigate('courses/create'), 삭제하기: () => onDelete(courseId), }; actions[option]?.(); }; - // 강의 관리 드롭다운 메뉴 트리거 const CourseMenuTrigger = (
        diff --git a/src/pages/dashboard/ui/ScheduleCard.tsx b/src/pages/student/dashboard/ui/ScheduleCard.tsx similarity index 76% rename from src/pages/dashboard/ui/ScheduleCard.tsx rename to src/pages/student/dashboard/ui/ScheduleCard.tsx index bec7e21..098fe68 100644 --- a/src/pages/dashboard/ui/ScheduleCard.tsx +++ b/src/pages/student/dashboard/ui/ScheduleCard.tsx @@ -1,5 +1,11 @@ -import Badge from '@/components/common/Badge'; -import type {ScheduleCardProps} from '../models/types'; +import Badge from '@/shared/ui/Badge'; +import type {Schedule} from '@/entities/course/model/types'; + +type AssignmentType = Schedule['assignments'][number]; + +interface ScheduleCardProps extends AssignmentType { + remainingDays: number; +} const ScheduleCard = ({ remainingDays, diff --git a/src/pages/dashboard/ui/ScheduleList.tsx b/src/pages/student/dashboard/ui/ScheduleList.tsx similarity index 88% rename from src/pages/dashboard/ui/ScheduleList.tsx rename to src/pages/student/dashboard/ui/ScheduleList.tsx index adb1898..0489b1e 100644 --- a/src/pages/dashboard/ui/ScheduleList.tsx +++ b/src/pages/student/dashboard/ui/ScheduleList.tsx @@ -1,13 +1,15 @@ import ScheduleCard from './ScheduleCard'; import EventMarkerIcon from '@/assets/svg/eventMarkerIcon.svg?react'; import {formatDateMonthDay} from '@/shared/lib/course'; -import type {ScheduleListProps} from '../models/types'; +import type {Schedule} from '@/entities/course/model/types'; + +interface ScheduleListProps { + scheduleList: Schedule[]; +} -// 스케쥴 목록 컴포넌트 const ScheduleList = ({scheduleList}: ScheduleListProps) => { return (
          - {/* 날짜별 그룹 간의 간격 */} {scheduleList.map((schedule, index) => (
        • {/* 마감일 */} @@ -31,7 +33,6 @@ const ScheduleList = ({scheduleList}: ScheduleListProps) => { ); }; -// 마감일 컴포넌트 const DeadLine = ({date}: {date: string}) => { return ( diff --git a/src/pages/select-assignment/AssignmentSelectPage.tsx b/src/pages/student/select-assignment/AssignmentSelectPage.tsx similarity index 87% rename from src/pages/select-assignment/AssignmentSelectPage.tsx rename to src/pages/student/select-assignment/AssignmentSelectPage.tsx index cb5956f..31847f5 100644 --- a/src/pages/select-assignment/AssignmentSelectPage.tsx +++ b/src/pages/student/select-assignment/AssignmentSelectPage.tsx @@ -1,16 +1,15 @@ import AssignmentListContainer from './ui/AssignmentListContainer'; import {useState} from 'react'; -import {response, courseOptionsResponse} from './mocks/response'; +import {response, courseOptionsResponse} from '@/shared/mocks/assignmentSelectResponse'; import {useCourseFilter} from '@/features/course/filter-course/lib/useCourseFilter'; import {AssignmentPageLayout} from '@/widgets/assignment-page-layout'; -import SelectableItem from '@/components/common/SelectableItem'; +import SelectableItem from '@/shared/ui/SelectableItem'; const AssignmentSelectPage = () => { const {courses} = courseOptionsResponse.response; // /courses/my API 응답 모킹 const [selectedAssignments, setSelectedAssignments] = useState([]); // 선택된 문제 ID 목록 - const {courseOptions, handleCourseSelect, selectedCourseId} = - useCourseFilter(courses); + const {courseOptions, handleCourseSelect} = useCourseFilter(courses); // 문제 목록 /courses/{courseId}/assignments API 응답 모킹 const assignmentList = response.response.courses.flatMap( diff --git a/src/pages/select-assignment/ui/AssignmentListContainer.tsx b/src/pages/student/select-assignment/ui/AssignmentListContainer.tsx similarity index 100% rename from src/pages/select-assignment/ui/AssignmentListContainer.tsx rename to src/pages/student/select-assignment/ui/AssignmentListContainer.tsx From b86a73c5267399db79f8138863dfa7ec08ae77e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:23:37 +0900 Subject: [PATCH 55/91] =?UTF-8?q?#47=20refactor:=20userType=20=EB=8F=99?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20=EB=A1=9C=EC=A7=81=EC=9D=84=20useSyncUserR?= =?UTF-8?q?ole=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 3 +-- src/entities/course/model/types.ts | 2 ++ .../sync-user-role/model/useSyncUserRole.ts | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 src/features/auth/sync-user-role/model/useSyncUserRole.ts diff --git a/index.html b/index.html index d43c495..8e0fad2 100644 --- a/index.html +++ b/index.html @@ -3,8 +3,7 @@ - - +
          diff --git a/src/entities/course/model/types.ts b/src/entities/course/model/types.ts index 94bbd1f..483243a 100644 --- a/src/entities/course/model/types.ts +++ b/src/entities/course/model/types.ts @@ -1,6 +1,8 @@ import type {Assignment} from '@/entities/assignment/model/types'; import type {ApiResponse} from '@/shared/model/common'; +export type {Assignment}; + // 학기 및 제출 상태 상수 타입 정의 export type SemesterCode = 'FIRST' | 'SECOND' | 'SUMMER' | 'WINTER'; export type SubmissionStatus = 'NOT_SUBMITTED' | 'CORRECT' | 'INCORRECT'; diff --git a/src/features/auth/sync-user-role/model/useSyncUserRole.ts b/src/features/auth/sync-user-role/model/useSyncUserRole.ts new file mode 100644 index 0000000..ddb4eaa --- /dev/null +++ b/src/features/auth/sync-user-role/model/useSyncUserRole.ts @@ -0,0 +1,17 @@ +import {useEffect} from 'react'; +import {useLocation} from 'react-router-dom'; +import {useUserStore} from '@/entities/auth/model/useUserStore'; + +export function useSyncUserRole() { + const {pathname} = useLocation(); + const {setUserType} = useUserStore(); + + useEffect(() => { + const userType = pathname.startsWith('/admin') + ? 'admin' + : pathname.startsWith('/student') + ? 'student' + : 'guest'; + setUserType(userType); + }, [pathname, setUserType]); +} From 45c5434ed7a138e1c3882daee01616e8e7d018e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:26:12 +0900 Subject: [PATCH 56/91] =?UTF-8?q?#47=20chore:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=A0=88=EA=B1=B0?= =?UTF-8?q?=EC=8B=9C=20=ED=83=80=EC=9E=85/=EC=9C=A0=ED=8B=B8/=ED=9B=85=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useClickOutside.ts | 32 ------------ src/models/assignment.ts | 10 ---- src/models/course.ts | 97 ------------------------------------ src/utils/course.ts | 64 ------------------------ 4 files changed, 203 deletions(-) delete mode 100644 src/hooks/useClickOutside.ts delete mode 100644 src/models/assignment.ts delete mode 100644 src/models/course.ts delete mode 100644 src/utils/course.ts diff --git a/src/hooks/useClickOutside.ts b/src/hooks/useClickOutside.ts deleted file mode 100644 index 454fe61..0000000 --- a/src/hooks/useClickOutside.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {useEffect} from 'react'; - -type UseClickOutsideProps = { - ref: React.RefObject; - onClickOutside: () => void; - exclude?: (target: HTMLElement) => boolean; -}; - -const useClickOutside = ({ - ref, - onClickOutside, - exclude, -}: UseClickOutsideProps) => { - useEffect(() => { - const handleClickOutside = (e: MouseEvent) => { - const target = e.target as HTMLElement; - - if (exclude?.(target)) return; - - if (ref.current?.contains(target) === false) { - onClickOutside(); - } - }; - - document.addEventListener('mousedown', handleClickOutside); - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, [ref, onClickOutside, exclude]); -}; - -export default useClickOutside; diff --git a/src/models/assignment.ts b/src/models/assignment.ts deleted file mode 100644 index d1257cf..0000000 --- a/src/models/assignment.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type {SubmissionStatus} from './course'; - -/** - * 과제(Assignment) 인터페이스 정의 - */ -export interface Assignment { - id: number; - title: string; - submittedStatus: SubmissionStatus; -} diff --git a/src/models/course.ts b/src/models/course.ts deleted file mode 100644 index ed8cb9d..0000000 --- a/src/models/course.ts +++ /dev/null @@ -1,97 +0,0 @@ -import type {Assignment} from './assignment'; -import type {ApiResponse} from './common'; - -// 학기 및 제출 상태 상수 타입 정의 -export type SemesterCode = 'FIRST' | 'SECOND' | 'SUMMER' | 'WINTER'; -export type SubmissionStatus = 'NOT_SUBMITTED' | 'CORRECT' | 'INCORRECT'; - -/** - * 일정(Schedule) 인터페이스 정의 - */ -export interface Schedule { - date: string; - remainingDays: number; - assignments: { - course: string; - section: string; - assignment: string; - }[]; -} - -/** - * 단원(Unit) 인터페이스 정의 - */ -export interface Unit { - id: number; - title: string; - releaseDate: string; - dueDate: string; - isOpen?: boolean; - assignmentCount: number; - assignments: Assignment[]; -} - -/** - * 강의 기본 정보 인터페이스 정의 - */ -export interface BaseCourse { - id: number; - title: string; - year: number; - semester: SemesterCode; - section: string; - unitCount: number; -} - -/** - * 강의 상세 페이지용 (course-overview) 인터페이스 정의 - * 기본 정보 + 단원, 과제 상세 리스트 - */ -export interface CourseOverview extends BaseCourse { - studentCount?: number; - units: Unit[]; -} - -/** - * 대시보드 강의 목록용 인터페이스 정의 - * 기본 정보 + 강의 설명, 과제 개수 - */ -export interface DashboardCourse extends BaseCourse { - description: string; - assignmentCount: number; -} - -/** - * 문제 선택 페이지용 강의 인터페이스 정의 - */ -export interface AssignmentSelectCourse extends Omit { - count: number; - assignments: Pick[]; -} - -// 강의 상세 응답 타입 정의 -export type CourseOverviewResponse = ApiResponse; - -// 대시보드 강의 목록 응답 타입 정의 -export type DashboardCourseListResponse = ApiResponse<{ - count: number; - courses: DashboardCourse[]; -}>; - -// 대시보드 일정 목록 응답 타입 정의 -export type DashboardScheduleListResponse = ApiResponse<{ - count: number; - schedule: Schedule[]; -}>; - -// 문제 선택 페이지 응답 타입 정의 -export type AssignmentSelectResponse = ApiResponse<{ - count: number; - courses: AssignmentSelectCourse[]; -}>; - -// 강의 옵션 목록 응답 타입 정의 -export type CourseOptionsResponse = ApiResponse<{ - count: number; - courses: DashboardCourse[]; -}>; diff --git a/src/utils/course.ts b/src/utils/course.ts deleted file mode 100644 index 26a87b3..0000000 --- a/src/utils/course.ts +++ /dev/null @@ -1,64 +0,0 @@ -import type {SemesterCode, Unit} from '@/models/course'; - -const SEMESTER_MAP: Record = { - FIRST: '1', - SECOND: '2', - SUMMER: '여름', - WINTER: '겨울', -} as const; - -// 학기 포맷팅 -export const formatSemester = (semester: SemesterCode) => { - const label = SEMESTER_MAP[semester]; - return `${label}학기`; -}; - -// 날짜 포맷팅 -export const formatDate = (date: string) => { - return date.replaceAll('-', '.'); -}; - -// MM.DD 형식으로 변환 -export const formatDateMonthDay = (date: string) => { - const [, month, day] = date.split('-'); - - return `${month}.${day}`; -}; - -// 년/학기/분반 형식으로 변환 -export const formatCourseTermWithSlash = ( - year: number, - semester: SemesterCode, - section: string -): string => { - return `${year}/${formatSemester(semester)}/${section}분반`; -}; - -// 과제 기간 포맷팅 -export const formatPeriod = (releaseDate: string, dueDate: string) => { - return `${formatDate(releaseDate)} ~ ${formatDate(dueDate)}`; -}; - -// 강의 정보 포맷팅 -export const formatCourseTerm = ( - year: number, - semester: SemesterCode, - section: string -) => { - return `${year}년 ${formatSemester(semester)} ${section}분반`; -}; - -// 총 과제 수 계산 -export const getTotalAssignmentCount = (units: Unit[]): number => { - return units.reduce((acc, unit) => acc + unit.assignmentCount, 0); -}; - -// 강의 옵션 라벨 포맷팅 -export const formatCourseOptionLabel = ( - title: string, - year: number, - semester: SemesterCode, - section: string -) => { - return `${title} ${formatCourseTermWithSlash(year, semester, section)}`; -}; From 2709e899dc34b1332d949be151433c50936d9d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:27:00 +0900 Subject: [PATCH 57/91] =?UTF-8?q?#47=20refactor:=20=EA=B3=B5=EC=9A=A9=20UI?= =?UTF-8?q?=20import=20=EA=B2=BD=EB=A1=9C=EB=A5=BC=20shared=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/student/ui/AssignmentProgressCard.tsx | 2 +- src/entities/student/ui/StudentProfile.tsx | 2 +- src/entities/student/ui/StudentTable.tsx | 4 ++-- .../course/filter-course/ui/CourseSelector.tsx | 2 +- src/pages/admin/assignments/AssignmentCreatePage.tsx | 10 +++++----- src/pages/admin/courses/CourseCreatePage.tsx | 8 ++++---- src/pages/admin/student/StudentManagementPage.tsx | 4 ++-- src/pages/admin/student/StudentProfilePage.tsx | 2 +- src/pages/common/LandingPage.tsx | 2 +- src/pages/common/UserIdInputPage.tsx | 2 +- .../assignment-page-layout/ui/AssignmentPageLayout.tsx | 4 ++-- 11 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/entities/student/ui/AssignmentProgressCard.tsx b/src/entities/student/ui/AssignmentProgressCard.tsx index a6abb50..4705191 100644 --- a/src/entities/student/ui/AssignmentProgressCard.tsx +++ b/src/entities/student/ui/AssignmentProgressCard.tsx @@ -1,5 +1,5 @@ import type {Student, ProgressStatus} from '../model/types'; -import {ProgressIndicators} from '@/components/common/ProgressIndicators'; +import {ProgressIndicators} from '@/shared/ui/ProgressIndicators'; import Correct from '@/assets/svg/correct.svg?react'; import Incorrect from '@/assets/svg/incorrect.svg?react'; import Unsubmitted from '@/assets/svg/unsubmitted.svg?react'; diff --git a/src/entities/student/ui/StudentProfile.tsx b/src/entities/student/ui/StudentProfile.tsx index 6939658..66e68e2 100644 --- a/src/entities/student/ui/StudentProfile.tsx +++ b/src/entities/student/ui/StudentProfile.tsx @@ -1,7 +1,7 @@ import ProfileImage from '@/assets/svg/profileImage.svg?react'; import ChatIcon from '@/assets/svg/chatIcon.svg?react'; import MailIcon from '@/assets/svg/mailIcon.svg?react'; -import Button from '@/components/common/Button'; +import Button from '@/shared/ui/Button'; interface StudentProfileProps { name: string; diff --git a/src/entities/student/ui/StudentTable.tsx b/src/entities/student/ui/StudentTable.tsx index a7b26de..ab2bc8c 100644 --- a/src/entities/student/ui/StudentTable.tsx +++ b/src/entities/student/ui/StudentTable.tsx @@ -1,5 +1,5 @@ -import {Checkbox} from '@/components/common/Checkbox'; -import {ProgressIndicators} from '@/components/common/ProgressIndicators'; +import {Checkbox} from '@/shared/ui/Checkbox'; +import {ProgressIndicators} from '@/shared/ui/ProgressIndicators'; import {useState, useEffect} from 'react'; import {Link} from 'react-router-dom'; import type {Student} from '@/entities/student/model/types'; diff --git a/src/features/course/filter-course/ui/CourseSelector.tsx b/src/features/course/filter-course/ui/CourseSelector.tsx index a942a5e..f2e1eb8 100644 --- a/src/features/course/filter-course/ui/CourseSelector.tsx +++ b/src/features/course/filter-course/ui/CourseSelector.tsx @@ -1,4 +1,4 @@ -import LabeledDropdown from '@/components/admin/form/LabeledDropdown'; +import LabeledDropdown from '@/shared/ui/LabeledDropdown'; export const CourseSelector = ({ options, diff --git a/src/pages/admin/assignments/AssignmentCreatePage.tsx b/src/pages/admin/assignments/AssignmentCreatePage.tsx index a24d404..d98d0e8 100644 --- a/src/pages/admin/assignments/AssignmentCreatePage.tsx +++ b/src/pages/admin/assignments/AssignmentCreatePage.tsx @@ -1,9 +1,9 @@ -import AssignmentFormLayout from '@/components/admin/assignments/AssignmentFormLayout'; -import LabeledInput from '@/components/admin/form/LabeledInput'; -import FileUpload from '@/components/admin/form/FileUpload'; +import AssignmentFormLayout from '@/widgets/assignment-form-layout/ui/AssignmentFormLayout'; +import LabeledInput from '@/shared/ui/LabeledInput'; +import FileUpload from '@/shared/ui/FileUpload'; import {useState} from 'react'; -import LabeledDropdown from '@/components/admin/form/LabeledDropdown'; -import Button from '@/components/common/Button'; +import LabeledDropdown from '@/shared/ui/LabeledDropdown'; +import Button from '@/shared/ui/Button'; import AddIcon from '@/assets/svg/addIcon.svg?react'; const PUBLIC_OPTIONS = ['공개', '비공개']; diff --git a/src/pages/admin/courses/CourseCreatePage.tsx b/src/pages/admin/courses/CourseCreatePage.tsx index 6cd5015..03d3b70 100644 --- a/src/pages/admin/courses/CourseCreatePage.tsx +++ b/src/pages/admin/courses/CourseCreatePage.tsx @@ -1,7 +1,7 @@ -import AssignmentFormLayout from '@/components/admin/assignments/AssignmentFormLayout'; -import LabeledInput from '@/components/admin/form/LabeledInput'; -import FileUpload from '@/components/admin/form/FileUpload'; -import LabeledDropdown from '@/components/admin/form/LabeledDropdown'; +import AssignmentFormLayout from '@/widgets/assignment-form-layout/ui/AssignmentFormLayout'; +import LabeledInput from '@/shared/ui/LabeledInput'; +import FileUpload from '@/shared/ui/FileUpload'; +import LabeledDropdown from '@/shared/ui/LabeledDropdown'; const YEAR_OPTIONS = ['2021', '2022', '2023', '2024', '2025', '2026']; const SEMESTER_OPTIONS = ['1학기', '2학기', '여름학기', '겨울학기']; diff --git a/src/pages/admin/student/StudentManagementPage.tsx b/src/pages/admin/student/StudentManagementPage.tsx index 2c8bd64..ab02ad2 100644 --- a/src/pages/admin/student/StudentManagementPage.tsx +++ b/src/pages/admin/student/StudentManagementPage.tsx @@ -1,9 +1,9 @@ -import AssignmentFormLayout from '@/components/admin/assignments/AssignmentFormLayout'; +import AssignmentFormLayout from '@/widgets/assignment-form-layout/ui/AssignmentFormLayout'; import Search from '@/assets/svg/search.svg?react'; import {useForm} from 'react-hook-form'; import {Pagination} from '@/shared/ui/pagination/pagination'; import {useState} from 'react'; -import Input from '@/components/common/Input'; +import Input from '@/shared/ui/Input'; import {StudentTable} from '@/entities/student/ui/StudentTable'; import mockCourseStudents from '@/entities/student/model/mock'; diff --git a/src/pages/admin/student/StudentProfilePage.tsx b/src/pages/admin/student/StudentProfilePage.tsx index 75d9743..3b4f03a 100644 --- a/src/pages/admin/student/StudentProfilePage.tsx +++ b/src/pages/admin/student/StudentProfilePage.tsx @@ -1,5 +1,5 @@ import {useParams} from 'react-router-dom'; -import SurfaceCard from '@/components/common/SurfaceCard'; +import SurfaceCard from '@/shared/ui/SurfaceCard'; import {StudentProfile} from '@/entities/student/ui/StudentProfile'; import {AssignmentProgressCard} from '@/entities/student/ui/AssignmentProgressCard'; import mockCourseStudents from '@/entities/student/model/mock'; diff --git a/src/pages/common/LandingPage.tsx b/src/pages/common/LandingPage.tsx index a2e1a45..09f351c 100644 --- a/src/pages/common/LandingPage.tsx +++ b/src/pages/common/LandingPage.tsx @@ -5,7 +5,7 @@ import snowCodeEntry from '@/assets/images/snowCode_entry.svg'; import snowCodeStudent from '@/assets/images/snowCode_student.svg'; import snowCodeAdmin from '@/assets/images/snowCode_admin.svg'; import ArrowrightIcon from '@/assets/svg/arrowrightIcon.svg?react'; -import Button from '@/components/common/Button'; +import Button from '@/shared/ui/Button'; type HoverState = 'none' | 'student' | 'admin'; diff --git a/src/pages/common/UserIdInputPage.tsx b/src/pages/common/UserIdInputPage.tsx index 022774b..4d45a15 100644 --- a/src/pages/common/UserIdInputPage.tsx +++ b/src/pages/common/UserIdInputPage.tsx @@ -3,7 +3,7 @@ import {useNavigate, useLocation} from 'react-router-dom'; import SnowCodeEntryMini from '@/assets/images/snowCode_entry_mini.svg'; import kakaoLogo from '@/assets/images/kakao_logo.svg'; import ArrowleftIcon from '@/assets/svg/arrowleftIcon.svg?react'; -import Button from '@/components/common/Button'; +import Button from '@/shared/ui/Button'; import {kakaoService} from '@/features/auth/kakao/lib/kakaoService'; export default function UserIdInputPage() { diff --git a/src/widgets/assignment-page-layout/ui/AssignmentPageLayout.tsx b/src/widgets/assignment-page-layout/ui/AssignmentPageLayout.tsx index 2b10294..213ea1a 100644 --- a/src/widgets/assignment-page-layout/ui/AssignmentPageLayout.tsx +++ b/src/widgets/assignment-page-layout/ui/AssignmentPageLayout.tsx @@ -1,5 +1,5 @@ -import SurfaceCard from '@/components/common/SurfaceCard'; -import Button from '@/components/common/Button'; +import SurfaceCard from '@/shared/ui/SurfaceCard'; +import Button from '@/shared/ui/Button'; import {CourseSelector} from '@/features/course/filter-course'; interface AssignmentPageLayoutProps { From 039403b1c75fe9af9ab209f8226a30d897c9cd18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:16:36 +0900 Subject: [PATCH 58/91] =?UTF-8?q?#47=20fix:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EC=88=98=EC=A0=95=20=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- src/App.tsx | 6 +++--- .../{student => }/course-overview/CourseOverviewPage.tsx | 0 .../{student => }/course-overview/ui/AssignmentList.tsx | 4 ++++ .../{student => }/course-overview/ui/CourseActionsBar.tsx | 0 .../{student => }/course-overview/ui/CourseContent.tsx | 2 ++ src/pages/{student => }/course-overview/ui/CourseHero.tsx | 3 +++ src/pages/{student => }/course-overview/ui/UnitItem.tsx | 8 +++++++- src/pages/{student => }/dashboard/Dashboard.tsx | 0 src/pages/{student => }/dashboard/ui/CourseCard.tsx | 0 src/pages/{student => }/dashboard/ui/CourseList.tsx | 0 .../dashboard/ui/CourseManagementDropdown.tsx | 2 ++ src/pages/{student => }/dashboard/ui/ScheduleCard.tsx | 0 src/pages/{student => }/dashboard/ui/ScheduleList.tsx | 3 +++ .../select-assignment/AssignmentSelectPage.tsx | 0 .../select-assignment/ui/AssignmentListContainer.tsx | 0 16 files changed, 25 insertions(+), 5 deletions(-) rename src/pages/{student => }/course-overview/CourseOverviewPage.tsx (100%) rename src/pages/{student => }/course-overview/ui/AssignmentList.tsx (93%) rename src/pages/{student => }/course-overview/ui/CourseActionsBar.tsx (100%) rename src/pages/{student => }/course-overview/ui/CourseContent.tsx (94%) rename src/pages/{student => }/course-overview/ui/CourseHero.tsx (96%) rename src/pages/{student => }/course-overview/ui/UnitItem.tsx (87%) rename src/pages/{student => }/dashboard/Dashboard.tsx (100%) rename src/pages/{student => }/dashboard/ui/CourseCard.tsx (100%) rename src/pages/{student => }/dashboard/ui/CourseList.tsx (100%) rename src/pages/{student => }/dashboard/ui/CourseManagementDropdown.tsx (91%) rename src/pages/{student => }/dashboard/ui/ScheduleCard.tsx (100%) rename src/pages/{student => }/dashboard/ui/ScheduleList.tsx (93%) rename src/pages/{student => }/select-assignment/AssignmentSelectPage.tsx (100%) rename src/pages/{student => }/select-assignment/ui/AssignmentListContainer.tsx (100%) diff --git a/index.html b/index.html index 8e0fad2..22f6ccf 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - +
          diff --git a/src/App.tsx b/src/App.tsx index 1693ad5..34e0c9f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,9 +2,9 @@ import {BrowserRouter, Routes, Route} from 'react-router-dom'; import Layout from '@/shared/ui/Layout'; import LandingPage from '@/pages/common/LandingPage'; import UserIdInputPage from '@/pages/common/UserIdInputPage'; -import Dashboard from '@/pages/student/dashboard/Dashboard'; -import AssignmentSelectPage from '@/pages/student/select-assignment/AssignmentSelectPage'; -import CourseOverviewPage from '@/pages/student/course-overview/CourseOverviewPage'; +import Dashboard from '@/pages/dashboard/Dashboard'; +import AssignmentSelectPage from '@/pages/select-assignment/AssignmentSelectPage'; +import CourseOverviewPage from '@/pages/course-overview/CourseOverviewPage'; import AssignmentCreatePage from '@/pages/admin/assignments/AssignmentCreatePage'; import CourseCreatePage from '@/pages/admin/courses/CourseCreatePage'; import StudentManagementPage from '@/pages/admin/student/StudentManagementPage'; diff --git a/src/pages/student/course-overview/CourseOverviewPage.tsx b/src/pages/course-overview/CourseOverviewPage.tsx similarity index 100% rename from src/pages/student/course-overview/CourseOverviewPage.tsx rename to src/pages/course-overview/CourseOverviewPage.tsx diff --git a/src/pages/student/course-overview/ui/AssignmentList.tsx b/src/pages/course-overview/ui/AssignmentList.tsx similarity index 93% rename from src/pages/student/course-overview/ui/AssignmentList.tsx rename to src/pages/course-overview/ui/AssignmentList.tsx index 38a3d30..5da79cb 100644 --- a/src/pages/student/course-overview/ui/AssignmentList.tsx +++ b/src/pages/course-overview/ui/AssignmentList.tsx @@ -12,6 +12,7 @@ interface AssignmentItemProps extends Assignment { isOpen?: boolean; } +// 문제 목록 const AssignmentList = ({isOpen, assignments}: AssignmentListProps) => { return (
            @@ -27,6 +28,7 @@ const AssignmentList = ({isOpen, assignments}: AssignmentListProps) => { ); }; +// 개별 문제 항목 const AssignmentItem = ({ title, index, @@ -37,6 +39,7 @@ const AssignmentItem = ({ return (
          • + {/* 좌측: 인덱스, 문제명 */}
            @@ -56,6 +59,7 @@ const AssignmentItem = ({ )}
            + {/* 우측: 제출현황 배지 */} {isOpen && (
            { + // 빈 강의 if (isActiveCourse === false) { return ; } @@ -33,6 +34,7 @@ const EmptyCourse = () => {

            아직 생성된 단원이 없어요

            + {/* 강의 관리 버튼은 관리자 전용 */} {userType === 'admin' && }
    ); diff --git a/src/pages/student/course-overview/ui/CourseHero.tsx b/src/pages/course-overview/ui/CourseHero.tsx similarity index 96% rename from src/pages/student/course-overview/ui/CourseHero.tsx rename to src/pages/course-overview/ui/CourseHero.tsx index 0048b9c..b0b3a9a 100644 --- a/src/pages/student/course-overview/ui/CourseHero.tsx +++ b/src/pages/course-overview/ui/CourseHero.tsx @@ -24,6 +24,7 @@ interface CourseStatsProps { isAdmin: boolean; } +// 강의 상세 페이지 Hero 섹션 const CourseHero = ({ courseData, assignmentCount, @@ -59,6 +60,7 @@ const CourseHero = ({ ); }; +// 강의 기본 정보 표시 const CourseInfo = ({title, year, semester, section}: CourseInfoProps) => { return (
    @@ -71,6 +73,7 @@ const CourseInfo = ({title, year, semester, section}: CourseInfoProps) => { ); }; +// 강의 Stats 표시 const CourseStats = ({ unitCount, assignmentCount, diff --git a/src/pages/student/course-overview/ui/UnitItem.tsx b/src/pages/course-overview/ui/UnitItem.tsx similarity index 87% rename from src/pages/student/course-overview/ui/UnitItem.tsx rename to src/pages/course-overview/ui/UnitItem.tsx index d49b907..f2f49b4 100644 --- a/src/pages/student/course-overview/ui/UnitItem.tsx +++ b/src/pages/course-overview/ui/UnitItem.tsx @@ -8,7 +8,10 @@ interface UnitProps extends Unit { index: number; } -type UnitHeaderProps = Omit; +type UnitHeaderProps = Omit< + UnitProps, + 'id' | 'assignmentCount' | 'assignments' +>; const UnitItem = ({index, ...unit}: UnitProps) => { const isOpen = unit.isOpen ?? true; @@ -27,6 +30,7 @@ const UnitItem = ({index, ...unit}: UnitProps) => { ); }; +// 단원 헤더 컴포넌트 const UnitHeader = ({ index, title, @@ -37,6 +41,7 @@ const UnitHeader = ({ return (
    + {/* 좌측: 인덱스, 단원명, 잠금 아이콘 */}
    {index} @@ -50,6 +55,7 @@ const UnitHeader = ({
    + {/* 우측: 데드라인 */}
    {formatPeriod(releaseDate, dueDate)}
    diff --git a/src/pages/student/dashboard/Dashboard.tsx b/src/pages/dashboard/Dashboard.tsx similarity index 100% rename from src/pages/student/dashboard/Dashboard.tsx rename to src/pages/dashboard/Dashboard.tsx diff --git a/src/pages/student/dashboard/ui/CourseCard.tsx b/src/pages/dashboard/ui/CourseCard.tsx similarity index 100% rename from src/pages/student/dashboard/ui/CourseCard.tsx rename to src/pages/dashboard/ui/CourseCard.tsx diff --git a/src/pages/student/dashboard/ui/CourseList.tsx b/src/pages/dashboard/ui/CourseList.tsx similarity index 100% rename from src/pages/student/dashboard/ui/CourseList.tsx rename to src/pages/dashboard/ui/CourseList.tsx diff --git a/src/pages/student/dashboard/ui/CourseManagementDropdown.tsx b/src/pages/dashboard/ui/CourseManagementDropdown.tsx similarity index 91% rename from src/pages/student/dashboard/ui/CourseManagementDropdown.tsx rename to src/pages/dashboard/ui/CourseManagementDropdown.tsx index ffb18e1..bd49c50 100644 --- a/src/pages/student/dashboard/ui/CourseManagementDropdown.tsx +++ b/src/pages/dashboard/ui/CourseManagementDropdown.tsx @@ -15,6 +15,7 @@ const CourseManagementDropdown = ({ }: CourseManagementDropdownProps) => { const navigate = useNavigate(); + // 드롭다운 메뉴 옵션 선택 핸들러 const handleSelect = (option: string) => { const actions: Record void> = { 수정하기: () => navigate('courses/create'), @@ -24,6 +25,7 @@ const CourseManagementDropdown = ({ actions[option]?.(); }; + // 강의 관리 드롭다운 메뉴 트리거 const CourseMenuTrigger = (
    diff --git a/src/pages/student/dashboard/ui/ScheduleCard.tsx b/src/pages/dashboard/ui/ScheduleCard.tsx similarity index 100% rename from src/pages/student/dashboard/ui/ScheduleCard.tsx rename to src/pages/dashboard/ui/ScheduleCard.tsx diff --git a/src/pages/student/dashboard/ui/ScheduleList.tsx b/src/pages/dashboard/ui/ScheduleList.tsx similarity index 93% rename from src/pages/student/dashboard/ui/ScheduleList.tsx rename to src/pages/dashboard/ui/ScheduleList.tsx index 0489b1e..62a6d17 100644 --- a/src/pages/student/dashboard/ui/ScheduleList.tsx +++ b/src/pages/dashboard/ui/ScheduleList.tsx @@ -7,9 +7,11 @@ interface ScheduleListProps { scheduleList: Schedule[]; } +// 스케줄 목록 컴포넌트 const ScheduleList = ({scheduleList}: ScheduleListProps) => { return (
      + {/* 날짜별 그룹 간의 간격 */} {scheduleList.map((schedule, index) => (
    • {/* 마감일 */} @@ -33,6 +35,7 @@ const ScheduleList = ({scheduleList}: ScheduleListProps) => { ); }; +// 마감일 컴포넌트 const DeadLine = ({date}: {date: string}) => { return ( diff --git a/src/pages/student/select-assignment/AssignmentSelectPage.tsx b/src/pages/select-assignment/AssignmentSelectPage.tsx similarity index 100% rename from src/pages/student/select-assignment/AssignmentSelectPage.tsx rename to src/pages/select-assignment/AssignmentSelectPage.tsx diff --git a/src/pages/student/select-assignment/ui/AssignmentListContainer.tsx b/src/pages/select-assignment/ui/AssignmentListContainer.tsx similarity index 100% rename from src/pages/student/select-assignment/ui/AssignmentListContainer.tsx rename to src/pages/select-assignment/ui/AssignmentListContainer.tsx From 37452f4df27d93ba2a332c043760a9d09b3becd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 19:48:40 +0900 Subject: [PATCH 59/91] =?UTF-8?q?fix:=20=EB=B9=8C=EB=93=9C=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=ED=95=B4=EA=B2=B0=20(FSD=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/assignment/model/types.ts | 2 +- src/entities/course/model/types.ts | 7 ++----- src/shared/model/common.ts | 4 ++++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/entities/assignment/model/types.ts b/src/entities/assignment/model/types.ts index 5ff4d4d..0da333c 100644 --- a/src/entities/assignment/model/types.ts +++ b/src/entities/assignment/model/types.ts @@ -1,4 +1,4 @@ -import type {SubmissionStatus} from '@/entities/course/model/types'; +import type {SubmissionStatus} from '@/shared/model/common'; /** * 과제(Assignment) 인터페이스 정의 diff --git a/src/entities/course/model/types.ts b/src/entities/course/model/types.ts index 483243a..7d336c4 100644 --- a/src/entities/course/model/types.ts +++ b/src/entities/course/model/types.ts @@ -1,11 +1,8 @@ import type {Assignment} from '@/entities/assignment/model/types'; -import type {ApiResponse} from '@/shared/model/common'; +import type {ApiResponse, SemesterCode} from '@/shared/model/common'; export type {Assignment}; - -// 학기 및 제출 상태 상수 타입 정의 -export type SemesterCode = 'FIRST' | 'SECOND' | 'SUMMER' | 'WINTER'; -export type SubmissionStatus = 'NOT_SUBMITTED' | 'CORRECT' | 'INCORRECT'; +export type {SemesterCode, SubmissionStatus} from '@/shared/model/common'; /** * 일정(Schedule) 인터페이스 정의 diff --git a/src/shared/model/common.ts b/src/shared/model/common.ts index b40de49..9842ae5 100644 --- a/src/shared/model/common.ts +++ b/src/shared/model/common.ts @@ -8,3 +8,7 @@ export interface ApiResponse { } export type UserType = 'admin' | 'student' | 'guest'; + +// 학기 및 제출 상태 상수 타입 정의 +export type SemesterCode = 'FIRST' | 'SECOND' | 'SUMMER' | 'WINTER'; +export type SubmissionStatus = 'NOT_SUBMITTED' | 'CORRECT' | 'INCORRECT'; From b8f84d92507fce19e831066ee41c4aaf91ca59ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:45:30 +0900 Subject: [PATCH 60/91] =?UTF-8?q?fix:=20=EB=B9=8C=EB=93=9C=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/models/course.ts | 97 +++++++++++++++++++ .../AssignmentSelectPage.tsx | 5 +- 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/models/course.ts diff --git a/src/models/course.ts b/src/models/course.ts new file mode 100644 index 0000000..7d42792 --- /dev/null +++ b/src/models/course.ts @@ -0,0 +1,97 @@ +import type {Assignment} from './assignment'; +import type {ApiResponse} from '../shared/model/common'; + +// 학기 및 제출 상태 상수 타입 정의 +export type SemesterCode = 'FIRST' | 'SECOND' | 'SUMMER' | 'WINTER'; +export type SubmissionStatus = 'NOT_SUBMITTED' | 'CORRECT' | 'INCORRECT'; + +/** + * 일정(Schedule) 인터페이스 정의 + */ +export interface Schedule { + date: string; + remainingDays: number; + assignments: { + course: string; + section: string; + assignment: string; + }[]; +} + +/** + * 단원(Unit) 인터페이스 정의 + */ +export interface Unit { + id: number; + title: string; + releaseDate: string; + dueDate: string; + isOpen?: boolean; + assignmentCount: number; + assignments: Assignment[]; +} + +/** + * 강의 기본 정보 인터페이스 정의 + */ +export interface BaseCourse { + id: number; + title: string; + year: number; + semester: SemesterCode; + section: string; + unitCount: number; +} + +/** + * 강의 상세 페이지용 (course-overview) 인터페이스 정의 + * 기본 정보 + 단원, 과제 상세 리스트 + */ +export interface CourseOverview extends BaseCourse { + studentCount?: number; + units: Unit[]; +} + +/** + * 대시보드 강의 목록용 인터페이스 정의 + * 기본 정보 + 강의 설명, 과제 개수 + */ +export interface DashboardCourse extends BaseCourse { + description: string; + assignmentCount: number; +} + +/** + * 문제 선택 페이지용 강의 인터페이스 정의 + */ +export interface AssignmentSelectCourse extends Omit { + count: number; + assignments: Pick[]; +} + +// 강의 상세 응답 타입 정의 +export type CourseOverviewResponse = ApiResponse; + +// 대시보드 강의 목록 응답 타입 정의 +export type DashboardCourseListResponse = ApiResponse<{ + count: number; + courses: DashboardCourse[]; +}>; + +// 대시보드 일정 목록 응답 타입 정의 +export type DashboardScheduleListResponse = ApiResponse<{ + count: number; + schedule: Schedule[]; +}>; + +// 문제 선택 페이지 응답 타입 정의 +export type AssignmentSelectResponse = ApiResponse<{ + count: number; + courses: AssignmentSelectCourse[]; +}>; + +// 강의 옵션 목록 응답 타입 정의 +export type CourseOptionsResponse = ApiResponse<{ + count: number; + courses: DashboardCourse[]; +}>; diff --git a/src/pages/select-assignment/AssignmentSelectPage.tsx b/src/pages/select-assignment/AssignmentSelectPage.tsx index 31847f5..b87ee50 100644 --- a/src/pages/select-assignment/AssignmentSelectPage.tsx +++ b/src/pages/select-assignment/AssignmentSelectPage.tsx @@ -1,6 +1,9 @@ import AssignmentListContainer from './ui/AssignmentListContainer'; import {useState} from 'react'; -import {response, courseOptionsResponse} from '@/shared/mocks/assignmentSelectResponse'; +import { + response, + courseOptionsResponse, +} from '@/shared/mocks/assignmentSelectResponse'; import {useCourseFilter} from '@/features/course/filter-course/lib/useCourseFilter'; import {AssignmentPageLayout} from '@/widgets/assignment-page-layout'; import SelectableItem from '@/shared/ui/SelectableItem'; From 87b6617f856fde6dc526d94f6dbfa3800598c7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:15:14 +0900 Subject: [PATCH 61/91] =?UTF-8?q?fix:=20=EB=B9=8C=EB=93=9C=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=ED=95=B4=EA=B2=B0=EC=9D=84=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=EC=88=9C=ED=99=98=20=EC=B0=B8=EC=A1=B0=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/models/assignment.ts | 10 ++++++++++ src/models/course.ts | 7 +++---- 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 src/models/assignment.ts diff --git a/src/models/assignment.ts b/src/models/assignment.ts new file mode 100644 index 0000000..ad4ae83 --- /dev/null +++ b/src/models/assignment.ts @@ -0,0 +1,10 @@ +import type {SubmissionStatus} from '../shared/model/common'; + +/** + * 과제(Assignment) 인터페이스 정의 + */ +export interface Assignment { + id: number; + title: string; + submittedStatus: SubmissionStatus; +} diff --git a/src/models/course.ts b/src/models/course.ts index 7d42792..1928abd 100644 --- a/src/models/course.ts +++ b/src/models/course.ts @@ -1,9 +1,8 @@ import type {Assignment} from './assignment'; -import type {ApiResponse} from '../shared/model/common'; +import type {ApiResponse, SemesterCode} from '../shared/model/common'; +export type {SemesterCode, SubmissionStatus} from '../shared/model/common'; + -// 학기 및 제출 상태 상수 타입 정의 -export type SemesterCode = 'FIRST' | 'SECOND' | 'SUMMER' | 'WINTER'; -export type SubmissionStatus = 'NOT_SUBMITTED' | 'CORRECT' | 'INCORRECT'; /** * 일정(Schedule) 인터페이스 정의 From 8c5b86b8c30f09e3eb37aa37adcf194806fd52ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:32:07 +0900 Subject: [PATCH 62/91] =?UTF-8?q?#49=20chore:=20CI=20=ED=8C=8C=EC=9D=B4?= =?UTF-8?q?=ED=94=84=EB=9D=BC=EC=9D=B8=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 69 +++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 .github/workflows/ci-cd.yml diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 0000000..d8df425 --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,69 @@ +name: CI/CD Pipeline + +on: + push: + branches: [main] + pull_request: + branches: [main] + +# 동일한 브랜치에서 새로운 Push가 발생하면 이전 실행을 취소하여 자원 절약 +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install + + - name: Lint + run: pnpm lint + + - name: Build + run: pnpm build + env: + VITE_KAKAO_REST_API_KEY: ${{ secrets.VITE_KAKAO_REST_API_KEY }} + VITE_KAKAO_REDIRECT_URI: ${{ secrets.VITE_KAKAO_REDIRECT_URI }} + VITE_API_BASE_URL: ${{ secrets.VITE_API_BASE_URL }} + + - name: Deploy to Vercel + uses: amondnet/vercel-action@v25 + with: + vercel-token: ${{ secrets.VERCEL_TOKEN }} + vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} + vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} + github-token: ${{ secrets.GITHUB_TOKEN }} + vercel-args: '--prod' + working-directory: ./ + github-comment: false From ba049f85908cfe4275f54c71857292c7dcf4e6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:37:23 +0900 Subject: [PATCH 63/91] =?UTF-8?q?#49=20chore:=20CI=20=ED=8C=8C=EC=9D=B4?= =?UTF-8?q?=ED=94=84=EB=9D=BC=EC=9D=B8=20=EC=88=98=EC=A0=95=20=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index d8df425..93a0ed7 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -2,9 +2,9 @@ name: CI/CD Pipeline on: push: - branches: [main] + branches: [develop, main] pull_request: - branches: [main] + branches: [develop, main] # 동일한 브랜치에서 새로운 Push가 발생하면 이전 실행을 취소하여 자원 절약 concurrency: @@ -56,14 +56,3 @@ jobs: VITE_KAKAO_REST_API_KEY: ${{ secrets.VITE_KAKAO_REST_API_KEY }} VITE_KAKAO_REDIRECT_URI: ${{ secrets.VITE_KAKAO_REDIRECT_URI }} VITE_API_BASE_URL: ${{ secrets.VITE_API_BASE_URL }} - - - name: Deploy to Vercel - uses: amondnet/vercel-action@v25 - with: - vercel-token: ${{ secrets.VERCEL_TOKEN }} - vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} - vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} - github-token: ${{ secrets.GITHUB_TOKEN }} - vercel-args: '--prod' - working-directory: ./ - github-comment: false From f50c1203567c6efc80942ee8970e48f845fe1908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 21:53:52 +0900 Subject: [PATCH 64/91] =?UTF-8?q?#49=20chore:=20=EB=A6=B0=ED=8A=B8=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/ui/Badge.tsx | 6 ++++-- src/shared/ui/SelectableItem.tsx | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/shared/ui/Badge.tsx b/src/shared/ui/Badge.tsx index 5df5d98..493baaf 100644 --- a/src/shared/ui/Badge.tsx +++ b/src/shared/ui/Badge.tsx @@ -84,7 +84,7 @@ const Badge = (props: BadgeProps) => { ); // 인덱스 배지 (단원, 문제 등) - case 'index': + case 'index': { const suffix = props.kind === 'unit' ? '단원' : ' 문제'; return ( @@ -93,9 +93,10 @@ const Badge = (props: BadgeProps) => { {suffix} ); + } // 제출 상태 배지 - case 'submission': + case 'submission': { const {label, icon} = SubmissionMeta[props.status!]; return ( @@ -106,6 +107,7 @@ const Badge = (props: BadgeProps) => { {icon} {label} ); + } } }; diff --git a/src/shared/ui/SelectableItem.tsx b/src/shared/ui/SelectableItem.tsx index 7822024..fbcea51 100644 --- a/src/shared/ui/SelectableItem.tsx +++ b/src/shared/ui/SelectableItem.tsx @@ -1,6 +1,6 @@ import {tv, type VariantProps} from 'tailwind-variants'; -export const selectableItemStyles = tv({ +const selectableItemStyles = tv({ base: 'cursor-pointer bg-background w-full flex items-center rounded-[9px] pl-4.5 pr-7.5 py-4 gap-4 border', variants: { selected: { From b2956709854c72da13c2f87008c9cfcb450977aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:03:08 +0900 Subject: [PATCH 65/91] =?UTF-8?q?#49=20ci:=20Release=20Drafter=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/template/release-drafter.yml | 47 +++++++++++++++++++++++++++ .github/workflows/release-drafter.yml | 36 ++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 .github/template/release-drafter.yml create mode 100644 .github/workflows/release-drafter.yml diff --git a/.github/template/release-drafter.yml b/.github/template/release-drafter.yml new file mode 100644 index 0000000..90e61e4 --- /dev/null +++ b/.github/template/release-drafter.yml @@ -0,0 +1,47 @@ +name-template: 'v$RESOLVED_VERSION' +tag-template: 'v$RESOLVED_VERSION' +version-template: $MAJOR.$MINOR.$PATCH + +categories: + - title: '🚀 기능 추가' + labels: + - 'Feat' + - title: '⚙️ 기능 개선' + labels: + - 'Refactor' + - title: '🐛 버그 수정' + labels: + - 'Fix' + - title: '🧰 그 외' + labels: + - 'Chore' + - 'CI/CD' + - 'Docs' + - 'Build' + - 'Common' + - 'Test' + +version-resolver: + major: + labels: + - 'Major' + minor: + labels: + - 'Minor' + patch: + labels: + - 'Patch' + default: minor + +exclude-labels: + - 'Release' + +change-template: '- $TITLE (#$NUMBER) - @$AUTHOR' +change-title-escapes: '\\<*_&' + +template: | + ## ✨ 변경 사항 + $CHANGES + + ## 📦 전체 변경 이력 + [$PREVIOUS_TAG ~ v$RESOLVED_VERSION]() diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 0000000..f5f8713 --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,36 @@ +name: Release Drafter + +on: + push: + branches: + - release/* + - main + +permissions: + contents: write + pull-requests: read + +jobs: + update_release_draft: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Update Draft Release + if: startsWith(github.ref, 'refs/heads/release/') + uses: release-drafter/release-drafter@v6 + with: + config-name: template/release-drafter.yml + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish Release + if: github.ref == 'refs/heads/main' + id: drafter + uses: release-drafter/release-drafter@v6 + with: + config-name: template/release-drafter.yml + publish: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From f736c0c4a1e07d170ad54ac60bc8a1ea4e520d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:14:32 +0900 Subject: [PATCH 66/91] =?UTF-8?q?#49=20refactor:=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EB=9E=98=EB=B9=97=20=EC=88=98=EC=A0=95=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/course/model/types.ts | 3 - src/models/assignment.ts | 10 ---- src/models/course.ts | 96 ------------------------------ 3 files changed, 109 deletions(-) delete mode 100644 src/models/assignment.ts delete mode 100644 src/models/course.ts diff --git a/src/entities/course/model/types.ts b/src/entities/course/model/types.ts index 7d336c4..b293c45 100644 --- a/src/entities/course/model/types.ts +++ b/src/entities/course/model/types.ts @@ -1,9 +1,6 @@ import type {Assignment} from '@/entities/assignment/model/types'; import type {ApiResponse, SemesterCode} from '@/shared/model/common'; -export type {Assignment}; -export type {SemesterCode, SubmissionStatus} from '@/shared/model/common'; - /** * 일정(Schedule) 인터페이스 정의 */ diff --git a/src/models/assignment.ts b/src/models/assignment.ts deleted file mode 100644 index ad4ae83..0000000 --- a/src/models/assignment.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type {SubmissionStatus} from '../shared/model/common'; - -/** - * 과제(Assignment) 인터페이스 정의 - */ -export interface Assignment { - id: number; - title: string; - submittedStatus: SubmissionStatus; -} diff --git a/src/models/course.ts b/src/models/course.ts deleted file mode 100644 index 1928abd..0000000 --- a/src/models/course.ts +++ /dev/null @@ -1,96 +0,0 @@ -import type {Assignment} from './assignment'; -import type {ApiResponse, SemesterCode} from '../shared/model/common'; -export type {SemesterCode, SubmissionStatus} from '../shared/model/common'; - - - -/** - * 일정(Schedule) 인터페이스 정의 - */ -export interface Schedule { - date: string; - remainingDays: number; - assignments: { - course: string; - section: string; - assignment: string; - }[]; -} - -/** - * 단원(Unit) 인터페이스 정의 - */ -export interface Unit { - id: number; - title: string; - releaseDate: string; - dueDate: string; - isOpen?: boolean; - assignmentCount: number; - assignments: Assignment[]; -} - -/** - * 강의 기본 정보 인터페이스 정의 - */ -export interface BaseCourse { - id: number; - title: string; - year: number; - semester: SemesterCode; - section: string; - unitCount: number; -} - -/** - * 강의 상세 페이지용 (course-overview) 인터페이스 정의 - * 기본 정보 + 단원, 과제 상세 리스트 - */ -export interface CourseOverview extends BaseCourse { - studentCount?: number; - units: Unit[]; -} - -/** - * 대시보드 강의 목록용 인터페이스 정의 - * 기본 정보 + 강의 설명, 과제 개수 - */ -export interface DashboardCourse extends BaseCourse { - description: string; - assignmentCount: number; -} - -/** - * 문제 선택 페이지용 강의 인터페이스 정의 - */ -export interface AssignmentSelectCourse extends Omit { - count: number; - assignments: Pick[]; -} - -// 강의 상세 응답 타입 정의 -export type CourseOverviewResponse = ApiResponse; - -// 대시보드 강의 목록 응답 타입 정의 -export type DashboardCourseListResponse = ApiResponse<{ - count: number; - courses: DashboardCourse[]; -}>; - -// 대시보드 일정 목록 응답 타입 정의 -export type DashboardScheduleListResponse = ApiResponse<{ - count: number; - schedule: Schedule[]; -}>; - -// 문제 선택 페이지 응답 타입 정의 -export type AssignmentSelectResponse = ApiResponse<{ - count: number; - courses: AssignmentSelectCourse[]; -}>; - -// 강의 옵션 목록 응답 타입 정의 -export type CourseOptionsResponse = ApiResponse<{ - count: number; - courses: DashboardCourse[]; -}>; From d5766407ffb6e9e2c08e7c00f52422e4a61ff68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:17:49 +0900 Subject: [PATCH 67/91] =?UTF-8?q?#49=20fix:=20=EB=B9=8C=EB=93=9C=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/course-overview/ui/AssignmentList.tsx | 2 +- src/pages/course-overview/ui/CourseHero.tsx | 3 ++- src/shared/lib/course.ts | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/course-overview/ui/AssignmentList.tsx b/src/pages/course-overview/ui/AssignmentList.tsx index 5da79cb..37cf6ff 100644 --- a/src/pages/course-overview/ui/AssignmentList.tsx +++ b/src/pages/course-overview/ui/AssignmentList.tsx @@ -1,6 +1,6 @@ import Badge from '@/shared/ui/Badge'; import {Link} from 'react-router-dom'; -import type {Assignment} from '@/entities/course/model/types'; +import type {Assignment} from '@/entities/assignment/model/types'; interface AssignmentListProps { isOpen?: boolean; diff --git a/src/pages/course-overview/ui/CourseHero.tsx b/src/pages/course-overview/ui/CourseHero.tsx index b0b3a9a..81a7ff7 100644 --- a/src/pages/course-overview/ui/CourseHero.tsx +++ b/src/pages/course-overview/ui/CourseHero.tsx @@ -2,7 +2,8 @@ import snowcodeOverviewMini from '@/assets/images/snowcode_overview_mini.svg'; import {formatCourseTerm} from '@/shared/lib/course'; import CourseActionsBar from './CourseActionsBar'; import {useUserStore} from '@/entities/auth/model/useUserStore'; -import type {CourseOverview, SemesterCode} from '@/entities/course/model/types'; +import type {CourseOverview} from '@/entities/course/model/types'; +import type {SemesterCode} from '@/shared/model/common'; interface CourseHeroProps { courseData: Omit; diff --git a/src/shared/lib/course.ts b/src/shared/lib/course.ts index 7be0cfc..d4eb59c 100644 --- a/src/shared/lib/course.ts +++ b/src/shared/lib/course.ts @@ -1,4 +1,5 @@ -import type {SemesterCode, Unit} from '@/entities/course/model/types'; +import type {Unit} from '@/entities/course/model/types'; +import type {SemesterCode} from '@/shared/model/common'; const SEMESTER_MAP: Record = { FIRST: '1', From 3174240a0ba038c46bf937e8f33c2f9c1f0a7b1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:27:06 +0900 Subject: [PATCH 68/91] =?UTF-8?q?#49=20chore:=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EB=9E=98=EB=B9=97=20=EC=A0=9C=EC=95=88=20=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/template/release-drafter.yml | 2 +- .github/workflows/release-drafter.yml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/template/release-drafter.yml b/.github/template/release-drafter.yml index 90e61e4..45fd877 100644 --- a/.github/template/release-drafter.yml +++ b/.github/template/release-drafter.yml @@ -6,7 +6,7 @@ categories: - title: '🚀 기능 추가' labels: - 'Feat' - - title: '⚙️ 기능 개선' + - title: '♻️ 리팩토링' labels: - 'Refactor' - title: '🐛 버그 수정' diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index f5f8713..92a5687 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -5,6 +5,9 @@ on: branches: - release/* - main + # PR 이벤트 추가로 자동화 범위 확대 + pull_request: + types: [opened, reopened, synchronize] permissions: contents: write @@ -14,11 +17,9 @@ jobs: update_release_draft: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - + # Checkout 단계 제거 (불필요한 작업 생략) - name: Update Draft Release - if: startsWith(github.ref, 'refs/heads/release/') + if: startsWith(github.ref, 'refs/heads/release/') || github.event_name == 'pull_request' uses: release-drafter/release-drafter@v6 with: config-name: template/release-drafter.yml @@ -26,8 +27,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Publish Release - if: github.ref == 'refs/heads/main' - id: drafter + if: github.ref == 'refs/heads/main' && github.event_name == 'push' uses: release-drafter/release-drafter@v6 with: config-name: template/release-drafter.yml From 80894e1348592fa6888dad22cfcbf89aa0dede3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:38:45 +0900 Subject: [PATCH 69/91] =?UTF-8?q?#49=20chore:=20=ED=8C=80=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98=20=EB=A7=9E=EC=B6=B0=EC=84=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/template/release-drafter.yml | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/.github/template/release-drafter.yml b/.github/template/release-drafter.yml index 45fd877..57d307d 100644 --- a/.github/template/release-drafter.yml +++ b/.github/template/release-drafter.yml @@ -5,32 +5,33 @@ version-template: $MAJOR.$MINOR.$PATCH categories: - title: '🚀 기능 추가' labels: - - 'Feat' + - 'feat' - title: '♻️ 리팩토링' labels: - - 'Refactor' + - 'refactor' - title: '🐛 버그 수정' labels: - - 'Fix' + - 'fix' - title: '🧰 그 외' labels: - - 'Chore' - - 'CI/CD' - - 'Docs' - - 'Build' - - 'Common' - - 'Test' + - 'chore' + - 'ci/cd' + - 'docs' + - 'style' + - 'build' + - 'common' + - 'test' version-resolver: major: labels: - - 'Major' + - 'major' minor: labels: - - 'Minor' + - 'minor' patch: labels: - - 'Patch' + - 'patch' default: minor exclude-labels: From f55ac76e909366def1bb31551d54274437679fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:52:54 +0900 Subject: [PATCH 70/91] =?UTF-8?q?chore:=20=EB=94=94=ED=8F=B4=ED=8A=B8=20?= =?UTF-8?q?=EB=B8=8C=EB=9E=9C=EC=B9=98=20=EC=84=A4=EC=A0=95=EC=9D=84=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20.github=20=ED=8F=B4=EB=8D=94=20=EC=9A=B0?= =?UTF-8?q?=EC=84=A0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/template/release-drafter.yml | 48 ++++++++++++++++++++++ .github/workflows/ci-cd.yml | 58 +++++++++++++++++++++++++++ .github/workflows/release-drafter.yml | 36 +++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 .github/template/release-drafter.yml create mode 100644 .github/workflows/ci-cd.yml create mode 100644 .github/workflows/release-drafter.yml diff --git a/.github/template/release-drafter.yml b/.github/template/release-drafter.yml new file mode 100644 index 0000000..57d307d --- /dev/null +++ b/.github/template/release-drafter.yml @@ -0,0 +1,48 @@ +name-template: 'v$RESOLVED_VERSION' +tag-template: 'v$RESOLVED_VERSION' +version-template: $MAJOR.$MINOR.$PATCH + +categories: + - title: '🚀 기능 추가' + labels: + - 'feat' + - title: '♻️ 리팩토링' + labels: + - 'refactor' + - title: '🐛 버그 수정' + labels: + - 'fix' + - title: '🧰 그 외' + labels: + - 'chore' + - 'ci/cd' + - 'docs' + - 'style' + - 'build' + - 'common' + - 'test' + +version-resolver: + major: + labels: + - 'major' + minor: + labels: + - 'minor' + patch: + labels: + - 'patch' + default: minor + +exclude-labels: + - 'Release' + +change-template: '- $TITLE (#$NUMBER) - @$AUTHOR' +change-title-escapes: '\\<*_&' + +template: | + ## ✨ 변경 사항 + $CHANGES + + ## 📦 전체 변경 이력 + [$PREVIOUS_TAG ~ v$RESOLVED_VERSION]() diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 0000000..93a0ed7 --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,58 @@ +name: CI/CD Pipeline + +on: + push: + branches: [develop, main] + pull_request: + branches: [develop, main] + +# 동일한 브랜치에서 새로운 Push가 발생하면 이전 실행을 취소하여 자원 절약 +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install + + - name: Lint + run: pnpm lint + + - name: Build + run: pnpm build + env: + VITE_KAKAO_REST_API_KEY: ${{ secrets.VITE_KAKAO_REST_API_KEY }} + VITE_KAKAO_REDIRECT_URI: ${{ secrets.VITE_KAKAO_REDIRECT_URI }} + VITE_API_BASE_URL: ${{ secrets.VITE_API_BASE_URL }} diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 0000000..92a5687 --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,36 @@ +name: Release Drafter + +on: + push: + branches: + - release/* + - main + # PR 이벤트 추가로 자동화 범위 확대 + pull_request: + types: [opened, reopened, synchronize] + +permissions: + contents: write + pull-requests: read + +jobs: + update_release_draft: + runs-on: ubuntu-latest + steps: + # Checkout 단계 제거 (불필요한 작업 생략) + - name: Update Draft Release + if: startsWith(github.ref, 'refs/heads/release/') || github.event_name == 'pull_request' + uses: release-drafter/release-drafter@v6 + with: + config-name: template/release-drafter.yml + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish Release + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + uses: release-drafter/release-drafter@v6 + with: + config-name: template/release-drafter.yml + publish: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From e021aa31e8cfb6516784694a4a743d509ccf8d1c Mon Sep 17 00:00:00 2001 From: suminb99 Date: Sun, 22 Feb 2026 15:56:05 +0900 Subject: [PATCH 71/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=C2=B7=EC=82=AD=EC=A0=9C=20API=20=EB=B0=8F=20?= =?UTF-8?q?mutation=20=EC=98=B5=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitApi.ts | 12 +++++++++++- src/entities/unit/api/unitMutations.ts | 24 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/entities/unit/api/unitMutations.ts diff --git a/src/entities/unit/api/unitApi.ts b/src/entities/unit/api/unitApi.ts index 2184b98..f4fcc64 100644 --- a/src/entities/unit/api/unitApi.ts +++ b/src/entities/unit/api/unitApi.ts @@ -20,13 +20,14 @@ export const getUnitById = async ( }; // 단원 삭제 -export const deleteUnitById = async ( +export const deleteUnit = async ( unitId: number ): Promise> => { const response = await privateAxios.delete(`/units/${unitId}`); return response.data; }; +// 단원 생성 export const createUnit = async ( courseId: number, unit: TUnitFormSchema @@ -34,3 +35,12 @@ export const createUnit = async ( const response = await privateAxios.post(`/units/${courseId}`, unit); return response.data; }; + +// 단원 수정 +export const updateUnit = async ( + unitId: number, + unit: TUnitFormSchema +): Promise> => { + const response = await privateAxios.put(`/units/${unitId}`, unit); + return response.data; +}; diff --git a/src/entities/unit/api/unitMutations.ts b/src/entities/unit/api/unitMutations.ts new file mode 100644 index 0000000..e5df6d5 --- /dev/null +++ b/src/entities/unit/api/unitMutations.ts @@ -0,0 +1,24 @@ +import type {TUnitFormSchema} from '@/pages/create-unit/model/types'; +import {createUnit, deleteUnit, updateUnit} from './unitApi'; + +export const unitMutations = { + // 단원 추가 뮤테이션 옵션 + createUnit: { + mutationKey: ['createUnit'], + mutationFn: ({courseId, unit}: {courseId: number; unit: TUnitFormSchema}) => + createUnit(courseId, unit), + }, + + // 단원 수정 뮤테이션 옵션 + updateUnit: { + mutationKey: ['updateUnit'], + mutationFn: ({unitId, unit}: {unitId: number; unit: TUnitFormSchema}) => + updateUnit(unitId, unit), + }, + + // 단원 삭제 뮤테이션 옵션 + deleteUnit: { + mutationKey: ['deleteUnit'], + mutationFn: (unitId: number) => deleteUnit(unitId), + }, +}; From 55ebf7a0d2fb660c3059e763698c4bf892d409ff Mon Sep 17 00:00:00 2001 From: suminb99 Date: Sun, 22 Feb 2026 15:56:47 +0900 Subject: [PATCH 72/91] =?UTF-8?q?#44=20refactor:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=83=81=ED=83=9C=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=8F=20CRUD=20=EC=A0=84=EC=B2=B4=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitQueryOptions.ts | 2 +- src/pages/create-unit/CreateUnitPage.tsx | 108 ++++++++++++++++------ src/pages/create-unit/model/types.ts | 13 ++- 3 files changed, 91 insertions(+), 32 deletions(-) diff --git a/src/entities/unit/api/unitQueryOptions.ts b/src/entities/unit/api/unitQueryOptions.ts index aa9b044..ff10576 100644 --- a/src/entities/unit/api/unitQueryOptions.ts +++ b/src/entities/unit/api/unitQueryOptions.ts @@ -14,6 +14,6 @@ export const unitQueries = { queryOptions({ queryKey: ['units', 'detail', unitId], queryFn: () => getUnitById(unitId), - enabled: !!unitId && unitId !== -1, + enabled: !!unitId, }), }; diff --git a/src/pages/create-unit/CreateUnitPage.tsx b/src/pages/create-unit/CreateUnitPage.tsx index 26621c7..c217b89 100644 --- a/src/pages/create-unit/CreateUnitPage.tsx +++ b/src/pages/create-unit/CreateUnitPage.tsx @@ -5,48 +5,42 @@ import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'; import {unitQueries} from '@/entities/unit/api/unitQueryOptions'; import {useParams} from 'react-router-dom'; import {useEffect, useState} from 'react'; -import {createUnit} from '@/entities/unit/api/unitApi'; -import type {TUnitFormSchema} from './model/types'; +import type {Mode, TUnitFormSchema} from './model/types'; +import {unitMutations} from '@/entities/unit/api/unitMutations'; +import {EmptyState} from '@/components/common/EmptyState'; const CreateUnitPage = () => { const {id} = useParams(); // 강의 ID + const courseId = Number(id); + const [mode, setMode] = useState('idle'); const [selectedUnitId, setSelectedUnitId] = useState(null); const [currentIndex, setCurrentIndex] = useState(1); - const [isEditing, setIsEditing] = useState(false); - const {data: unitList} = useQuery(unitQueries.getUnitList(Number(id))); + const {data: unitList} = useQuery(unitQueries.getUnitList(courseId)); const {data: unit} = useQuery(unitQueries.getUnitDetails(selectedUnitId)); - const queryClient = useQueryClient(); - // 단원 목록에서 선택된 단원이 없을 때, 첫 번째 단원을 선택하도록 설정 + // 자동으로 첫 번째 단원 선택 useEffect(() => { - if (unitList && unitList.response.count !== 0 && selectedUnitId === null) { + if (unitList && unitList.response.count !== 0 && mode === 'idle') { setSelectedUnitId(unitList.response.units[0].id); - setIsEditing(true); // 첫 번째 단원이 선택되면 편집 모드로 전환 + setMode('editing'); // 편집 모드로 전환 } - }, [unitList, selectedUnitId]); - - const onUnitClick = (id: number) => { - setSelectedUnitId(id); - setIsEditing(true); // 단원이 선택되면 편집 모드로 전환 - }; + }, [unitList, mode]); - const onAddNewUnit = () => { - setSelectedUnitId(-1); - setCurrentIndex(unitList ? unitList.response.count + 1 : 1); // 새 단원의 인덱스 설정 - setIsEditing(false); // 새 단원 추가 시 편집 모드 해제 + const queryClient = useQueryClient(); + const invalidateUnitList = () => { + queryClient.invalidateQueries({ + queryKey: unitQueries.getUnitList(courseId).queryKey, + }); }; - // 단원 생성 뮤테이션 + // 단원 생성 const {mutate: addUnit} = useMutation({ - mutationFn: ({courseId, unit}: {courseId: number; unit: TUnitFormSchema}) => - createUnit(courseId, unit), + ...unitMutations.createUnit, onSuccess: (data) => { // 단원 목록 갱신 + invalidateUnitList(); setSelectedUnitId(data.response.id); - setIsEditing(true); // 새 단원 생성 후 편집 모드로 전환 - queryClient.invalidateQueries({ - queryKey: unitQueries.getUnitList(Number(id)).queryKey, - }); + setMode('editing'); // 생성 후 편집 모드로 전환 alert('새 단원이 성공적으로 생성되었습니다.'); }, onError: (error) => { @@ -55,11 +49,69 @@ const CreateUnitPage = () => { }, }); + // 단원 업데이트 + const {mutate: updateUnit} = useMutation({ + ...unitMutations.updateUnit, + onSuccess: () => { + invalidateUnitList(); + alert('단원이 성공적으로 업데이트되었습니다.'); + }, + onError: (error) => { + console.error('단원 업데이트 실패', error); + alert('단원 업데이트에 실패했습니다. 다시 시도해주세요.'); + }, + }); + + // 단원 삭제 + const {mutate: deleteUnit} = useMutation({ + ...unitMutations.deleteUnit, + onSuccess: () => { + invalidateUnitList(); + setMode('idle'); // 삭제 후 대기 모드로 전환 + setSelectedUnitId(null); // 선택된 단원 초기화 + alert('단원이 성공적으로 삭제되었습니다.'); + }, + onError: (error) => { + console.error('단원 삭제 실패', error); + alert('단원 삭제에 실패했습니다. 다시 시도해주세요.'); + }, + }); + + // 단원 선택 핸들러 + const onUnitClick = (id: number) => { + setSelectedUnitId(id); + setMode('editing'); // 편집 모드로 전환 + }; + + // 단원 추가 핸들러 + const onAddNewUnit = () => { + setSelectedUnitId(null); + setCurrentIndex(unitList ? unitList.response.count + 1 : 1); // 새 단원의 인덱스 설정 + setMode('creating'); // 생성 모드로 전환 + }; + // 단원 생성 핸들러 const onCreateUnit = (unit: TUnitFormSchema) => { - addUnit({courseId: Number(id), unit}); + addUnit({courseId: courseId, unit}); + }; + + // 단원 업데이트 핸들러 + const onUpdateUnit = (unitId: number, unit: TUnitFormSchema) => { + updateUnit({unitId, unit}); }; + // 단원 삭제 핸들러 + const onDeleteUnit = (unitId: number) => { + if (window.confirm('정말로 이 단원을 삭제하시겠습니까?')) { + deleteUnit(unitId); + } + }; + + // 강의 ID가 없는 경우 빈 상태 표시 + if (!id) { + return 선택한 강의가 없습니다.; + } + return (
      {/* 단원 목차 섹션 */} @@ -78,8 +130,10 @@ const CreateUnitPage = () => {
      diff --git a/src/pages/create-unit/model/types.ts b/src/pages/create-unit/model/types.ts index be4767d..6e8a728 100644 --- a/src/pages/create-unit/model/types.ts +++ b/src/pages/create-unit/model/types.ts @@ -4,9 +4,9 @@ import z from 'zod'; // 단원 생성/수정 폼 스키마 export const unitFormSchema = z .object({ - title: z.string(), - releaseDate: z.string(), - dueDate: z.string(), + title: z.string().min(1, '단원 제목을 입력해주세요.'), + releaseDate: z.string().min(1, '공개일을 입력해주세요.'), + dueDate: z.string().min(1, '마감일을 입력해주세요.'), assignmentIds: z.array(z.number()).optional(), }) .refine((data) => data.releaseDate <= data.dueDate, { @@ -17,9 +17,14 @@ export const unitFormSchema = z // 단원 생성/수정 폼 타입 export type TUnitFormSchema = z.infer; +// 단원 편집 모드 타입 +export type Mode = 'idle' | 'creating' | 'editing'; + export interface UnitFormEditorProps { unit?: Unit; unitIndex: number; - isEditing: boolean; + mode: Mode; onCreateUnit: (unit: TUnitFormSchema) => void; + onUpdateUnit: (unitId: number, unit: TUnitFormSchema) => void; + onDeleteUnit: (unitId: number) => void; } From 96c12c176cbe97982750d4847ab8ade266d91594 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Sun, 22 Feb 2026 15:59:41 +0900 Subject: [PATCH 73/91] =?UTF-8?q?#44=20feat:=20=EB=8B=A8=EC=9B=90=20CRUD?= =?UTF-8?q?=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EB=B2=84=ED=8A=BC=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99=20=EB=B0=8F=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Button.tsx | 1 + src/pages/create-unit/ui/UnitFormEditor.tsx | 43 +++++++++++++++------ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/components/common/Button.tsx b/src/components/common/Button.tsx index c0851b6..5395c0d 100644 --- a/src/components/common/Button.tsx +++ b/src/components/common/Button.tsx @@ -58,6 +58,7 @@ const Button = ({ }: ButtonProps) => { return (
    @@ -91,14 +112,12 @@ const UnitFormEditor = ({ type='date' placeholder='마감일을 선택하세요' /> - {errors.dueDate && ( - - {errors.dueDate.message} - - )} + + {errors.dueDate?.message} + -
    +
    {/* 문제 등록 섹션 */}
    @@ -126,7 +145,9 @@ const UnitFormEditor = ({ {/* 제출 버튼 */}
    - + From 067b95ab3632828bbb9e37c882b281fff81637a9 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Sun, 22 Feb 2026 16:00:01 +0900 Subject: [PATCH 74/91] =?UTF-8?q?#44=20fix:=20barrel=20export=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/index.ts | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 src/entities/unit/index.ts diff --git a/src/entities/unit/index.ts b/src/entities/unit/index.ts deleted file mode 100644 index dd51a55..0000000 --- a/src/entities/unit/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { - getAllUnitsByCourseId, - getUnitById, - deleteUnitById, -} from './api/unitApi'; From 85e674f1f62739a219420b3abf98dd6d1847abec Mon Sep 17 00:00:00 2001 From: suminb99 Date: Sun, 22 Feb 2026 22:46:35 +0900 Subject: [PATCH 75/91] =?UTF-8?q?#44=20refactor:=20unit=20entity=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EB=AA=85=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitApi.ts | 2 +- src/entities/unit/api/unitMutations.ts | 2 +- src/entities/unit/api/unitQueries.ts | 19 +++++++++++++++++++ src/entities/unit/model/types.ts | 17 +++++++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/entities/unit/api/unitQueries.ts create mode 100644 src/entities/unit/model/types.ts diff --git a/src/entities/unit/api/unitApi.ts b/src/entities/unit/api/unitApi.ts index f4fcc64..39af8ea 100644 --- a/src/entities/unit/api/unitApi.ts +++ b/src/entities/unit/api/unitApi.ts @@ -1,7 +1,7 @@ import type {ApiResponse} from '@/models/common'; import type {AllUnitsResponse, Unit} from '@/models/course'; -import type {TUnitFormSchema} from '@/pages/create-unit/model/types'; import {privateAxios} from '@/shared/api/axiosInstance'; +import type {TUnitFormSchema} from '../model/types'; // 강의별 전체 단원 조회 export const getAllUnitsByCourseId = async ( diff --git a/src/entities/unit/api/unitMutations.ts b/src/entities/unit/api/unitMutations.ts index e5df6d5..a0e6c91 100644 --- a/src/entities/unit/api/unitMutations.ts +++ b/src/entities/unit/api/unitMutations.ts @@ -1,4 +1,4 @@ -import type {TUnitFormSchema} from '@/pages/create-unit/model/types'; +import type {TUnitFormSchema} from '../model/types'; import {createUnit, deleteUnit, updateUnit} from './unitApi'; export const unitMutations = { diff --git a/src/entities/unit/api/unitQueries.ts b/src/entities/unit/api/unitQueries.ts new file mode 100644 index 0000000..ff10576 --- /dev/null +++ b/src/entities/unit/api/unitQueries.ts @@ -0,0 +1,19 @@ +import {queryOptions} from '@tanstack/react-query'; +import {getAllUnitsByCourseId, getUnitById} from './unitApi'; + +export const unitQueries = { + // 강의별 전체 단원 조회 쿼리 옵션 + getUnitList: (courseId: number) => + queryOptions({ + queryKey: ['units', courseId], + queryFn: () => getAllUnitsByCourseId(courseId), + }), + + // 단일 단원 조회 쿼리 옵션 + getUnitDetails: (unitId: number | null) => + queryOptions({ + queryKey: ['units', 'detail', unitId], + queryFn: () => getUnitById(unitId), + enabled: !!unitId, + }), +}; diff --git a/src/entities/unit/model/types.ts b/src/entities/unit/model/types.ts new file mode 100644 index 0000000..e97dfdd --- /dev/null +++ b/src/entities/unit/model/types.ts @@ -0,0 +1,17 @@ +import z from 'zod'; + +// 단원 생성/수정 폼 스키마 +export const unitFormSchema = z + .object({ + title: z.string().min(1, '단원 제목을 입력해주세요.'), + releaseDate: z.string().min(1, '공개일을 입력해주세요.'), + dueDate: z.string().min(1, '마감일을 입력해주세요.'), + assignmentIds: z.array(z.number()).optional(), + }) + .refine((data) => data.releaseDate <= data.dueDate, { + message: '날짜 범위가 올바르지 않습니다.', + path: ['dueDate'], + }); + +// 단원 생성/수정 폼 타입 +export type TUnitFormSchema = z.infer; From eb927e1dcaef9e0964697de19ae6e64032153cc0 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Sun, 22 Feb 2026 22:47:00 +0900 Subject: [PATCH 76/91] =?UTF-8?q?#44=20refactor:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=EC=97=90=EB=94=94=ED=84=B0=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=ED=8F=B4=EB=8D=94=20=EA=B5=AC=EC=A1=B0=20=EB=B0=8F=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EB=AA=85=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 4 +-- src/entities/unit/api/unitQueryOptions.ts | 19 ------------ src/pages/create-unit/model/types.ts | 30 ------------------- .../UnitEditorPage.tsx} | 15 +++++----- .../mock/unitMock.ts} | 0 src/pages/unit-editor/model/types.ts | 14 +++++++++ .../ui/UnitAssignmentList.tsx} | 2 +- .../ui/UnitForm.tsx} | 20 ++++++------- .../ui/UnitList.tsx | 4 +-- 9 files changed, 34 insertions(+), 74 deletions(-) delete mode 100644 src/entities/unit/api/unitQueryOptions.ts delete mode 100644 src/pages/create-unit/model/types.ts rename src/pages/{create-unit/CreateUnitPage.tsx => unit-editor/UnitEditorPage.tsx} (93%) rename src/pages/{create-unit/mocks/response.ts => unit-editor/mock/unitMock.ts} (100%) create mode 100644 src/pages/unit-editor/model/types.ts rename src/pages/{create-unit/ui/SortableAssignmentList.tsx => unit-editor/ui/UnitAssignmentList.tsx} (98%) rename src/pages/{create-unit/ui/UnitFormEditor.tsx => unit-editor/ui/UnitForm.tsx} (94%) rename src/pages/{create-unit => unit-editor}/ui/UnitList.tsx (98%) diff --git a/src/App.tsx b/src/App.tsx index bfb7557..726caed 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,7 +10,7 @@ import CourseCreatePage from './pages/admin/courses/CourseCreatePage'; import StudentManagementPage from './pages/admin/student/StudentManagementPage'; import {useEffect} from 'react'; import {useUserStore} from '@/entities/auth/model/useUserStore'; -import CreateUnitPage from './pages/create-unit/CreateUnitPage'; +import {UnitEditorPage} from './pages/unit-editor/UnitEditorPage'; const AppRoutes = () => { const {pathname} = useLocation(); @@ -47,7 +47,7 @@ const AppRoutes = () => { } /> } /> } /> - } /> + } /> diff --git a/src/entities/unit/api/unitQueryOptions.ts b/src/entities/unit/api/unitQueryOptions.ts deleted file mode 100644 index ff10576..0000000 --- a/src/entities/unit/api/unitQueryOptions.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {queryOptions} from '@tanstack/react-query'; -import {getAllUnitsByCourseId, getUnitById} from './unitApi'; - -export const unitQueries = { - // 강의별 전체 단원 조회 쿼리 옵션 - getUnitList: (courseId: number) => - queryOptions({ - queryKey: ['units', courseId], - queryFn: () => getAllUnitsByCourseId(courseId), - }), - - // 단일 단원 조회 쿼리 옵션 - getUnitDetails: (unitId: number | null) => - queryOptions({ - queryKey: ['units', 'detail', unitId], - queryFn: () => getUnitById(unitId), - enabled: !!unitId, - }), -}; diff --git a/src/pages/create-unit/model/types.ts b/src/pages/create-unit/model/types.ts deleted file mode 100644 index 6e8a728..0000000 --- a/src/pages/create-unit/model/types.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type {Unit} from '@/models/course'; -import z from 'zod'; - -// 단원 생성/수정 폼 스키마 -export const unitFormSchema = z - .object({ - title: z.string().min(1, '단원 제목을 입력해주세요.'), - releaseDate: z.string().min(1, '공개일을 입력해주세요.'), - dueDate: z.string().min(1, '마감일을 입력해주세요.'), - assignmentIds: z.array(z.number()).optional(), - }) - .refine((data) => data.releaseDate <= data.dueDate, { - message: '날짜 범위가 올바르지 않습니다.', - path: ['dueDate'], - }); - -// 단원 생성/수정 폼 타입 -export type TUnitFormSchema = z.infer; - -// 단원 편집 모드 타입 -export type Mode = 'idle' | 'creating' | 'editing'; - -export interface UnitFormEditorProps { - unit?: Unit; - unitIndex: number; - mode: Mode; - onCreateUnit: (unit: TUnitFormSchema) => void; - onUpdateUnit: (unitId: number, unit: TUnitFormSchema) => void; - onDeleteUnit: (unitId: number) => void; -} diff --git a/src/pages/create-unit/CreateUnitPage.tsx b/src/pages/unit-editor/UnitEditorPage.tsx similarity index 93% rename from src/pages/create-unit/CreateUnitPage.tsx rename to src/pages/unit-editor/UnitEditorPage.tsx index c217b89..6c9e1c2 100644 --- a/src/pages/create-unit/CreateUnitPage.tsx +++ b/src/pages/unit-editor/UnitEditorPage.tsx @@ -1,15 +1,16 @@ import SurfaceCard from '@/components/common/SurfaceCard'; -import UnitFormEditor from './ui/UnitFormEditor'; -import UnitList from './ui/UnitList'; +import {UnitList} from './ui/UnitList'; +import {UnitForm} from './ui/UnitForm'; import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'; -import {unitQueries} from '@/entities/unit/api/unitQueryOptions'; +import {unitQueries} from '@/entities/unit/api/unitQueries'; import {useParams} from 'react-router-dom'; import {useEffect, useState} from 'react'; -import type {Mode, TUnitFormSchema} from './model/types'; +import type {Mode} from './model/types'; import {unitMutations} from '@/entities/unit/api/unitMutations'; import {EmptyState} from '@/components/common/EmptyState'; +import type {TUnitFormSchema} from '@/entities/unit/model/types'; -const CreateUnitPage = () => { +export const UnitEditorPage = () => { const {id} = useParams(); // 강의 ID const courseId = Number(id); const [mode, setMode] = useState('idle'); @@ -127,7 +128,7 @@ const CreateUnitPage = () => { {/* 단원 폼 섹션 */} - {
    ); }; - -export default CreateUnitPage; diff --git a/src/pages/create-unit/mocks/response.ts b/src/pages/unit-editor/mock/unitMock.ts similarity index 100% rename from src/pages/create-unit/mocks/response.ts rename to src/pages/unit-editor/mock/unitMock.ts diff --git a/src/pages/unit-editor/model/types.ts b/src/pages/unit-editor/model/types.ts new file mode 100644 index 0000000..db73ff7 --- /dev/null +++ b/src/pages/unit-editor/model/types.ts @@ -0,0 +1,14 @@ +import type {TUnitFormSchema} from '@/entities/unit/model/types'; +import type {Unit} from '@/models/course'; + +// 단원 편집 모드 타입 +export type Mode = 'idle' | 'creating' | 'editing'; + +export interface UnitFormProps { + unit?: Unit; + unitIndex: number; + mode: Mode; + onCreateUnit: (unit: TUnitFormSchema) => void; + onUpdateUnit: (unitId: number, unit: TUnitFormSchema) => void; + onDeleteUnit: (unitId: number) => void; +} diff --git a/src/pages/create-unit/ui/SortableAssignmentList.tsx b/src/pages/unit-editor/ui/UnitAssignmentList.tsx similarity index 98% rename from src/pages/create-unit/ui/SortableAssignmentList.tsx rename to src/pages/unit-editor/ui/UnitAssignmentList.tsx index c6a15e9..d829c94 100644 --- a/src/pages/create-unit/ui/SortableAssignmentList.tsx +++ b/src/pages/unit-editor/ui/UnitAssignmentList.tsx @@ -20,7 +20,7 @@ import { } from '@dnd-kit/sortable'; import {CSS} from '@dnd-kit/utilities'; -export const SortableAssignmentList = ({ +export const UnitAssignmentList = ({ assignmentList, }: { assignmentList: Assignment[]; diff --git a/src/pages/create-unit/ui/UnitFormEditor.tsx b/src/pages/unit-editor/ui/UnitForm.tsx similarity index 94% rename from src/pages/create-unit/ui/UnitFormEditor.tsx rename to src/pages/unit-editor/ui/UnitForm.tsx index 3fcd208..d5e2ecd 100644 --- a/src/pages/create-unit/ui/UnitFormEditor.tsx +++ b/src/pages/unit-editor/ui/UnitForm.tsx @@ -2,25 +2,25 @@ import {useForm} from 'react-hook-form'; import Button from '@/components/common/Button'; import BinIcon from '@/assets/svg/binIcon.svg?react'; import LabeledInput from '@/components/admin/form/LabeledInput'; -import {SortableAssignmentList} from './SortableAssignmentList'; +import {UnitAssignmentList} from './UnitAssignmentList'; import {zodResolver} from '@hookform/resolvers/zod'; -import { - unitFormSchema, - type TUnitFormSchema, - type UnitFormEditorProps, -} from '../model/types'; +import {type UnitFormProps} from '../model/types'; import AddIcon from '@/assets/svg/addIcon.svg?react'; import {EmptyState} from '@/components/common/EmptyState'; import {useState} from 'react'; +import { + unitFormSchema, + type TUnitFormSchema, +} from '@/entities/unit/model/types'; -const UnitFormEditor = ({ +export const UnitForm = ({ unit, unitIndex, mode, onCreateUnit, onUpdateUnit, onDeleteUnit, -}: UnitFormEditorProps) => { +}: UnitFormProps) => { const [assignmentIds, setAssignmentIds] = useState([]); const { @@ -129,7 +129,7 @@ const UnitFormEditor = ({ 등록된 문제가 없습니다. ) : ( - + )} {/* 문제 연결 버튼 */} @@ -155,5 +155,3 @@ const UnitFormEditor = ({
    ); }; - -export default UnitFormEditor; diff --git a/src/pages/create-unit/ui/UnitList.tsx b/src/pages/unit-editor/ui/UnitList.tsx similarity index 98% rename from src/pages/create-unit/ui/UnitList.tsx rename to src/pages/unit-editor/ui/UnitList.tsx index 6f86791..23d223f 100644 --- a/src/pages/create-unit/ui/UnitList.tsx +++ b/src/pages/unit-editor/ui/UnitList.tsx @@ -12,7 +12,7 @@ interface UnitListProps { onAddNewUnit?: () => void; } -const UnitList = ({ +export const UnitList = ({ unitList, onUnitClick, selectedUnitId, @@ -70,5 +70,3 @@ const UnitList = ({
    ); }; - -export default UnitList; From 85009396a2ddf977290b6734aea4148588abd4cd Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 23 Feb 2026 18:02:56 +0900 Subject: [PATCH 77/91] =?UTF-8?q?#44=20chore:=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=ED=8C=8C=EC=9D=BC=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F?= =?UTF-8?q?=20import=20=EA=B2=BD=EB=A1=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/student/ui/StudentProfile.tsx | 2 +- src/entities/student/ui/StudentTable.tsx | 2 +- src/entities/unit/api/unitApi.ts | 4 +- .../assignments/AssignmentCreatePage.tsx | 2 +- src/pages/common/LandingPage.tsx | 2 +- src/pages/common/UserIdInputPage.tsx | 2 +- .../course-overview/ui/AssignmentList.tsx | 2 +- .../course-overview/ui/CourseActionsBar.tsx | 4 +- src/pages/course-overview/ui/UnitItem.tsx | 2 +- src/pages/dashboard/Dashboard.tsx | 2 +- src/pages/dashboard/ui/ScheduleCard.tsx | 2 +- .../AssignmentSelectPage.tsx | 4 +- src/pages/unit-editor/UnitEditorPage.tsx | 15 +++--- src/pages/unit-editor/mock/unitMock.ts | 5 +- src/pages/unit-editor/model/types.ts | 2 +- .../unit-editor/ui/UnitAssignmentList.tsx | 6 +-- src/pages/unit-editor/ui/UnitForm.tsx | 6 +-- src/pages/unit-editor/ui/UnitList.tsx | 8 +-- src/shared/ui/ActionButton.tsx | 36 ------------- src/shared/ui/Header.tsx | 2 +- src/shared/ui/IconButton.tsx | 11 ---- src/shared/ui/SelectableItem.tsx | 42 --------------- src/shared/ui/{ => badge}/Badge.tsx | 52 ++++--------------- src/shared/ui/badge/badge-styles.ts | 43 +++++++++++++++ src/shared/ui/button/Button.tsx | 36 +++++++++++++ .../{Button.tsx => button/button-styles.ts} | 37 +------------ .../ui/{ => checkbox}/Checkbox.module.css | 0 src/shared/ui/{ => checkbox}/Checkbox.tsx | 0 src/shared/ui/list-row/ListRow.tsx | 27 ++++++++++ src/shared/ui/list-row/list-row-styles.ts | 16 ++++++ .../ui/AssignmentFormLayout.tsx | 2 +- .../ui/AssignmentPageLayout.tsx | 2 +- 32 files changed, 176 insertions(+), 202 deletions(-) delete mode 100644 src/shared/ui/ActionButton.tsx delete mode 100644 src/shared/ui/IconButton.tsx delete mode 100644 src/shared/ui/SelectableItem.tsx rename src/shared/ui/{ => badge}/Badge.tsx (58%) create mode 100644 src/shared/ui/badge/badge-styles.ts create mode 100644 src/shared/ui/button/Button.tsx rename src/shared/ui/{Button.tsx => button/button-styles.ts} (62%) rename src/shared/ui/{ => checkbox}/Checkbox.module.css (100%) rename src/shared/ui/{ => checkbox}/Checkbox.tsx (100%) create mode 100644 src/shared/ui/list-row/ListRow.tsx create mode 100644 src/shared/ui/list-row/list-row-styles.ts diff --git a/src/entities/student/ui/StudentProfile.tsx b/src/entities/student/ui/StudentProfile.tsx index 66e68e2..a852c00 100644 --- a/src/entities/student/ui/StudentProfile.tsx +++ b/src/entities/student/ui/StudentProfile.tsx @@ -1,7 +1,7 @@ import ProfileImage from '@/assets/svg/profileImage.svg?react'; import ChatIcon from '@/assets/svg/chatIcon.svg?react'; import MailIcon from '@/assets/svg/mailIcon.svg?react'; -import Button from '@/shared/ui/Button'; +import Button from '@/shared/ui/button/Button'; interface StudentProfileProps { name: string; diff --git a/src/entities/student/ui/StudentTable.tsx b/src/entities/student/ui/StudentTable.tsx index ab2bc8c..bae08f8 100644 --- a/src/entities/student/ui/StudentTable.tsx +++ b/src/entities/student/ui/StudentTable.tsx @@ -1,4 +1,4 @@ -import {Checkbox} from '@/shared/ui/Checkbox'; +import {Checkbox} from '@/shared/ui/checkbox/Checkbox'; import {ProgressIndicators} from '@/shared/ui/ProgressIndicators'; import {useState, useEffect} from 'react'; import {Link} from 'react-router-dom'; diff --git a/src/entities/unit/api/unitApi.ts b/src/entities/unit/api/unitApi.ts index 39af8ea..b716386 100644 --- a/src/entities/unit/api/unitApi.ts +++ b/src/entities/unit/api/unitApi.ts @@ -1,7 +1,7 @@ -import type {ApiResponse} from '@/models/common'; -import type {AllUnitsResponse, Unit} from '@/models/course'; import {privateAxios} from '@/shared/api/axiosInstance'; import type {TUnitFormSchema} from '../model/types'; +import type {ApiResponse} from '@/shared/model'; +import type {AllUnitsResponse, Unit} from '@/entities/course/model/types'; // 강의별 전체 단원 조회 export const getAllUnitsByCourseId = async ( diff --git a/src/pages/admin/assignments/AssignmentCreatePage.tsx b/src/pages/admin/assignments/AssignmentCreatePage.tsx index d98d0e8..484063e 100644 --- a/src/pages/admin/assignments/AssignmentCreatePage.tsx +++ b/src/pages/admin/assignments/AssignmentCreatePage.tsx @@ -3,7 +3,7 @@ import LabeledInput from '@/shared/ui/LabeledInput'; import FileUpload from '@/shared/ui/FileUpload'; import {useState} from 'react'; import LabeledDropdown from '@/shared/ui/LabeledDropdown'; -import Button from '@/shared/ui/Button'; +import Button from '@/shared/ui/button/Button'; import AddIcon from '@/assets/svg/addIcon.svg?react'; const PUBLIC_OPTIONS = ['공개', '비공개']; diff --git a/src/pages/common/LandingPage.tsx b/src/pages/common/LandingPage.tsx index 09f351c..1012bab 100644 --- a/src/pages/common/LandingPage.tsx +++ b/src/pages/common/LandingPage.tsx @@ -5,7 +5,7 @@ import snowCodeEntry from '@/assets/images/snowCode_entry.svg'; import snowCodeStudent from '@/assets/images/snowCode_student.svg'; import snowCodeAdmin from '@/assets/images/snowCode_admin.svg'; import ArrowrightIcon from '@/assets/svg/arrowrightIcon.svg?react'; -import Button from '@/shared/ui/Button'; +import Button from '@/shared/ui/button/Button'; type HoverState = 'none' | 'student' | 'admin'; diff --git a/src/pages/common/UserIdInputPage.tsx b/src/pages/common/UserIdInputPage.tsx index 4d45a15..911dd9c 100644 --- a/src/pages/common/UserIdInputPage.tsx +++ b/src/pages/common/UserIdInputPage.tsx @@ -3,7 +3,7 @@ import {useNavigate, useLocation} from 'react-router-dom'; import SnowCodeEntryMini from '@/assets/images/snowCode_entry_mini.svg'; import kakaoLogo from '@/assets/images/kakao_logo.svg'; import ArrowleftIcon from '@/assets/svg/arrowleftIcon.svg?react'; -import Button from '@/shared/ui/Button'; +import Button from '@/shared/ui/button/Button'; import {kakaoService} from '@/features/auth/kakao/lib/kakaoService'; export default function UserIdInputPage() { diff --git a/src/pages/course-overview/ui/AssignmentList.tsx b/src/pages/course-overview/ui/AssignmentList.tsx index 37cf6ff..83d76c2 100644 --- a/src/pages/course-overview/ui/AssignmentList.tsx +++ b/src/pages/course-overview/ui/AssignmentList.tsx @@ -1,4 +1,4 @@ -import Badge from '@/shared/ui/Badge'; +import Badge from '@/shared/ui/badge/Badge'; import {Link} from 'react-router-dom'; import type {Assignment} from '@/entities/assignment/model/types'; diff --git a/src/pages/course-overview/ui/CourseActionsBar.tsx b/src/pages/course-overview/ui/CourseActionsBar.tsx index 7653f3c..746a240 100644 --- a/src/pages/course-overview/ui/CourseActionsBar.tsx +++ b/src/pages/course-overview/ui/CourseActionsBar.tsx @@ -1,4 +1,4 @@ -import Button from '@/shared/ui/Button'; +import Button from '@/shared/ui/button/Button'; import {Link} from 'react-router-dom'; // 강의 관리 버튼 바 (관리자 전용) @@ -10,7 +10,7 @@ const CourseActionsBar = ({isActiveCourse}: {isActiveCourse: boolean}) => { 학생 목록 - + diff --git a/src/pages/course-overview/ui/UnitItem.tsx b/src/pages/course-overview/ui/UnitItem.tsx index f2f49b4..10049d9 100644 --- a/src/pages/course-overview/ui/UnitItem.tsx +++ b/src/pages/course-overview/ui/UnitItem.tsx @@ -1,6 +1,6 @@ import AssignmentList from './AssignmentList'; import Lock from '@/assets/svg/lock.svg?react'; -import Badge from '@/shared/ui/Badge'; +import Badge from '@/shared/ui/badge/Badge'; import {formatPeriod} from '@/shared/lib/course'; import type {Unit} from '@/entities/course/model/types'; diff --git a/src/pages/dashboard/Dashboard.tsx b/src/pages/dashboard/Dashboard.tsx index 7c3f82d..e1ca73a 100644 --- a/src/pages/dashboard/Dashboard.tsx +++ b/src/pages/dashboard/Dashboard.tsx @@ -1,6 +1,6 @@ import LogoIcon from '@/assets/images/snowCode_logo.svg?react'; import CourseList from './ui/CourseList'; -import Button from '@/shared/ui/Button'; +import Button from '@/shared/ui/button/Button'; import AddIcon from '@/assets/svg/addIcon.svg?react'; import ScheduleList from './ui/ScheduleList'; import {Link} from 'react-router-dom'; diff --git a/src/pages/dashboard/ui/ScheduleCard.tsx b/src/pages/dashboard/ui/ScheduleCard.tsx index 098fe68..0707f49 100644 --- a/src/pages/dashboard/ui/ScheduleCard.tsx +++ b/src/pages/dashboard/ui/ScheduleCard.tsx @@ -1,4 +1,4 @@ -import Badge from '@/shared/ui/Badge'; +import Badge from '@/shared/ui/badge/Badge'; import type {Schedule} from '@/entities/course/model/types'; type AssignmentType = Schedule['assignments'][number]; diff --git a/src/pages/select-assignment/AssignmentSelectPage.tsx b/src/pages/select-assignment/AssignmentSelectPage.tsx index b87ee50..b84b174 100644 --- a/src/pages/select-assignment/AssignmentSelectPage.tsx +++ b/src/pages/select-assignment/AssignmentSelectPage.tsx @@ -6,7 +6,7 @@ import { } from '@/shared/mocks/assignmentSelectResponse'; import {useCourseFilter} from '@/features/course/filter-course/lib/useCourseFilter'; import {AssignmentPageLayout} from '@/widgets/assignment-page-layout'; -import SelectableItem from '@/shared/ui/SelectableItem'; +import ListRow from '@/shared/ui/list-row/ListRow'; const AssignmentSelectPage = () => { const {courses} = courseOptionsResponse.response; // /courses/my API 응답 모킹 @@ -41,7 +41,7 @@ const AssignmentSelectPage = () => { title={`${assignmentList.length}문제`} onSelect={handleAssignmentSelect} renderItem={(assignment) => ( - diff --git a/src/pages/unit-editor/UnitEditorPage.tsx b/src/pages/unit-editor/UnitEditorPage.tsx index 6c9e1c2..1e632b9 100644 --- a/src/pages/unit-editor/UnitEditorPage.tsx +++ b/src/pages/unit-editor/UnitEditorPage.tsx @@ -1,4 +1,3 @@ -import SurfaceCard from '@/components/common/SurfaceCard'; import {UnitList} from './ui/UnitList'; import {UnitForm} from './ui/UnitForm'; import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'; @@ -7,10 +6,11 @@ import {useParams} from 'react-router-dom'; import {useEffect, useState} from 'react'; import type {Mode} from './model/types'; import {unitMutations} from '@/entities/unit/api/unitMutations'; -import {EmptyState} from '@/components/common/EmptyState'; import type {TUnitFormSchema} from '@/entities/unit/model/types'; +import {EmptyState} from '@/shared/ui/EmptyState'; +import SurfaceCard from '@/shared/ui/SurfaceCard'; -export const UnitEditorPage = () => { +const UnitEditorPage = () => { const {id} = useParams(); // 강의 ID const courseId = Number(id); const [mode, setMode] = useState('idle'); @@ -19,11 +19,12 @@ export const UnitEditorPage = () => { const {data: unitList} = useQuery(unitQueries.getUnitList(courseId)); const {data: unit} = useQuery(unitQueries.getUnitDetails(selectedUnitId)); - // 자동으로 첫 번째 단원 선택 useEffect(() => { - if (unitList && unitList.response.count !== 0 && mode === 'idle') { + if (unitList && unitList?.response.count !== 0 && mode === 'idle') { setSelectedUnitId(unitList.response.units[0].id); - setMode('editing'); // 편집 모드로 전환 + setMode('editing'); // 편집 모드 + } else if (unitList?.response.count === 0 && mode === 'idle') { + setMode('creating'); // 생성 모드 } }, [unitList, mode]); @@ -140,3 +141,5 @@ export const UnitEditorPage = () => {
    ); }; + +export default UnitEditorPage; diff --git a/src/pages/unit-editor/mock/unitMock.ts b/src/pages/unit-editor/mock/unitMock.ts index a2f1b57..9d9d2f9 100644 --- a/src/pages/unit-editor/mock/unitMock.ts +++ b/src/pages/unit-editor/mock/unitMock.ts @@ -1,4 +1,7 @@ -import type {AllUnitsResponse, SingleUnitResponse} from '@/models/course'; +import type { + AllUnitsResponse, + SingleUnitResponse, +} from '@/entities/course/model/types'; export const singleUnitResponse: SingleUnitResponse = { success: true, diff --git a/src/pages/unit-editor/model/types.ts b/src/pages/unit-editor/model/types.ts index db73ff7..c845cef 100644 --- a/src/pages/unit-editor/model/types.ts +++ b/src/pages/unit-editor/model/types.ts @@ -1,5 +1,5 @@ +import type {Unit} from '@/entities/course/model/types'; import type {TUnitFormSchema} from '@/entities/unit/model/types'; -import type {Unit} from '@/models/course'; // 단원 편집 모드 타입 export type Mode = 'idle' | 'creating' | 'editing'; diff --git a/src/pages/unit-editor/ui/UnitAssignmentList.tsx b/src/pages/unit-editor/ui/UnitAssignmentList.tsx index d829c94..842326b 100644 --- a/src/pages/unit-editor/ui/UnitAssignmentList.tsx +++ b/src/pages/unit-editor/ui/UnitAssignmentList.tsx @@ -1,5 +1,5 @@ -import SelectableItem from '@/components/common/SelectableItem'; -import type {Assignment} from '@/models/assignment'; +import ListRow from '@/shared/ui/list-row/ListRow'; +import type {Assignment} from '@/entities/assignment/model/types'; import {useState} from 'react'; import DragAndDropIcon from '@/assets/svg/dragAndDropIcon.svg?react'; import DeleteIcon from '@/assets/svg/deleteIcon.svg?react'; @@ -92,7 +92,7 @@ const DraggableAssignmentItem = ({id, title}: Assignment) => { return (
  • - } rightIcon={} diff --git a/src/pages/unit-editor/ui/UnitForm.tsx b/src/pages/unit-editor/ui/UnitForm.tsx index d5e2ecd..d685bd1 100644 --- a/src/pages/unit-editor/ui/UnitForm.tsx +++ b/src/pages/unit-editor/ui/UnitForm.tsx @@ -1,12 +1,12 @@ import {useForm} from 'react-hook-form'; -import Button from '@/components/common/Button'; +import Button from '@/shared/ui/button/Button'; import BinIcon from '@/assets/svg/binIcon.svg?react'; -import LabeledInput from '@/components/admin/form/LabeledInput'; +import LabeledInput from '@/shared/ui/LabeledInput'; import {UnitAssignmentList} from './UnitAssignmentList'; import {zodResolver} from '@hookform/resolvers/zod'; import {type UnitFormProps} from '../model/types'; import AddIcon from '@/assets/svg/addIcon.svg?react'; -import {EmptyState} from '@/components/common/EmptyState'; +import {EmptyState} from '@/shared/ui/EmptyState'; import {useState} from 'react'; import { unitFormSchema, diff --git a/src/pages/unit-editor/ui/UnitList.tsx b/src/pages/unit-editor/ui/UnitList.tsx index 23d223f..c741afd 100644 --- a/src/pages/unit-editor/ui/UnitList.tsx +++ b/src/pages/unit-editor/ui/UnitList.tsx @@ -1,8 +1,8 @@ -import Button from '@/components/common/Button'; -import AddIcon from '@/assets/svg/addIcon.svg?react'; -import Badge from '@/components/common/Badge'; import ArrowrightIcon from '@/assets/svg/arrowrightIcon.svg?react'; -import type {AllUnitsResponse} from '@/models/course'; +import type {AllUnitsResponse} from '@/entities/course/model/types'; +import Badge from '@/shared/ui/badge/Badge'; +import Button from '@/shared/ui/button/Button'; +import AddIcon from '@/assets/svg/addIcon.svg?react'; interface UnitListProps { unitList: AllUnitsResponse['response']['units'] | undefined; diff --git a/src/shared/ui/ActionButton.tsx b/src/shared/ui/ActionButton.tsx deleted file mode 100644 index e81206f..0000000 --- a/src/shared/ui/ActionButton.tsx +++ /dev/null @@ -1,36 +0,0 @@ -interface ActionButtonProps { - label?: string; - children?: React.ReactNode; - onClick?: () => void; - onMouseEnter?: () => void; - onMouseLeave?: () => void; - className?: string; // 추가 스타일링 위해 - selected?: boolean; - disabled?: boolean; -} - -export default function ActionButton({ - label, - children, - onClick, - onMouseEnter, - onMouseLeave, - className = '', - selected = false, -}: ActionButtonProps) { - const baseClass = - 'w-40 py-[15px] rounded-xl border border-stroke font-medium transition-colors'; - const selectedClass = selected - ? 'bg-primary text-white' - : 'bg-white text-primary-black hover:bg-hover hover:text-white'; - - return ( - - ); -} diff --git a/src/shared/ui/Header.tsx b/src/shared/ui/Header.tsx index 30baf63..eb5ba32 100644 --- a/src/shared/ui/Header.tsx +++ b/src/shared/ui/Header.tsx @@ -4,7 +4,7 @@ import NotificationIcon from '@/assets/svg/notificationIcon.svg?react'; import SignoutIcon from '@/assets/svg/signoutIcon.svg?react'; import UserIcon from '@/assets/svg/userIcon.svg?react'; import ChatIcon from '@/assets/svg/chatIcon.svg?react'; -import Button from '@/shared/ui/Button'; +import Button from '@/shared/ui/button/Button'; import {useUserStore} from '@/entities/auth/model/useUserStore'; interface NavButton { diff --git a/src/shared/ui/IconButton.tsx b/src/shared/ui/IconButton.tsx deleted file mode 100644 index 8845a84..0000000 --- a/src/shared/ui/IconButton.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import * as React from 'react'; - -interface IconButtonProps { - icon: React.ReactElement; -} - -const IconButton = ({icon}: IconButtonProps) => { - return ; -}; - -export default IconButton; \ No newline at end of file diff --git a/src/shared/ui/SelectableItem.tsx b/src/shared/ui/SelectableItem.tsx deleted file mode 100644 index 9ec0502..0000000 --- a/src/shared/ui/SelectableItem.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import {tv, type VariantProps} from 'tailwind-variants'; - -const selectableItemStyles = tv({ - base: 'cursor-pointer bg-background w-full flex items-center rounded-[9px] pl-4.5 pr-7.5 py-4 gap-4 border', - variants: { - selected: { - true: 'border-primary', - false: 'border-transparent', - }, - }, - defaultVariants: { - selected: false, - }, -}); - -type SelectableItemVariants = VariantProps; - -interface SelectableItemProps extends SelectableItemVariants { - selected?: boolean; - leftIcon?: React.ReactNode; - title: string; - rightIcon?: React.ReactNode; - className?: string; -} - -const SelectableItem = ({ - selected = false, - leftIcon, - title, - rightIcon, - className, -}: SelectableItemProps) => { - return ( -
    -
    {leftIcon}
    -

    {title}

    -
    {rightIcon}
    -
    - ); -}; - -export default SelectableItem; diff --git a/src/shared/ui/Badge.tsx b/src/shared/ui/badge/Badge.tsx similarity index 58% rename from src/shared/ui/Badge.tsx rename to src/shared/ui/badge/Badge.tsx index 493baaf..8dfbaaf 100644 --- a/src/shared/ui/Badge.tsx +++ b/src/shared/ui/badge/Badge.tsx @@ -1,58 +1,28 @@ -import {tv, type VariantProps} from 'tailwind-variants/lite'; import Correct from '@/assets/svg/correct.svg?react'; import Incorrect from '@/assets/svg/incorrect.svg?react'; import Unsubmitted from '@/assets/svg/unsubmitted.svg?react'; - -const badgeStyles = tv({ - base: 'rounded-full px-3.5 py-1.5 leading-[19px] text-center text-base font-medium border whitespace-nowrap', -}); - -const scheduleBadgeStyles = tv({ - extend: badgeStyles, - variants: { - schedule: { - upcoming: - 'bg-radial-[50%_50%_at_50%_50%] from-[#7D63FF] from-38% to-[#AB9AFF] to-100% text-white', - later: 'bg-[#403D4D] border-[#5C5B7F] text-white', - }, - }, -}); - -const submissionBadgeStyles = tv({ - extend: badgeStyles, - base: 'bg-transparent flex-center gap-2 text-sm', - variants: { - status: { - CORRECT: 'border-primary text-primary', - INCORRECT: 'border-[#FF6F6F] text-[#FF6F6F]', - NOT_SUBMITTED: 'border-light-black text-light-black', - }, - }, -}); - -const indexBadgeStyles = tv({ - extend: badgeStyles, - variants: { - kind: { - unit: 'bg-secondary-black border-secondary-black text-white', - problem: 'bg-light-black border-light-black text-white', - }, - }, -}); +import { + indexBadgeStyles, + scheduleBadgeStyles, + submissionBadgeStyles, + type IndexBadgeVariants, + type ScheduleBadgeVariants, + type SubmissionBadgeVariants, +} from './badge-styles'; type ScheduleBadgeProps = { variant: 'schedule'; children: React.ReactNode; -} & VariantProps; +} & ScheduleBadgeVariants; type SubmissionBadgeProps = { variant: 'submission'; -} & VariantProps; +} & SubmissionBadgeVariants; type IndexBadgeProps = { children: React.ReactNode; variant: 'index'; -} & VariantProps; +} & IndexBadgeVariants; type BadgeProps = ScheduleBadgeProps | SubmissionBadgeProps | IndexBadgeProps; diff --git a/src/shared/ui/badge/badge-styles.ts b/src/shared/ui/badge/badge-styles.ts new file mode 100644 index 0000000..13a0316 --- /dev/null +++ b/src/shared/ui/badge/badge-styles.ts @@ -0,0 +1,43 @@ +import {tv, type VariantProps} from 'tailwind-variants/lite'; +export const badgeStyles = tv({ + base: 'rounded-full px-3.5 py-1.5 leading-[19px] text-center text-base font-medium border whitespace-nowrap', +}); + +export const scheduleBadgeStyles = tv({ + extend: badgeStyles, + variants: { + schedule: { + upcoming: + 'bg-radial-[50%_50%_at_50%_50%] from-[#7D63FF] from-38% to-[#AB9AFF] to-100% text-white', + later: 'bg-[#403D4D] border-[#5C5B7F] text-white', + }, + }, +}); + +export const submissionBadgeStyles = tv({ + extend: badgeStyles, + base: 'bg-transparent flex-center gap-2 text-sm', + variants: { + status: { + CORRECT: 'border-primary text-primary', + INCORRECT: 'border-[#FF6F6F] text-[#FF6F6F]', + NOT_SUBMITTED: 'border-light-black text-light-black', + }, + }, +}); + +export const indexBadgeStyles = tv({ + extend: badgeStyles, + variants: { + kind: { + unit: 'bg-secondary-black border-secondary-black text-white', + problem: 'bg-light-black border-light-black text-white', + }, + }, +}); + +export type ScheduleBadgeVariants = VariantProps; +export type SubmissionBadgeVariants = VariantProps< + typeof submissionBadgeStyles +>; +export type IndexBadgeVariants = VariantProps; diff --git a/src/shared/ui/button/Button.tsx b/src/shared/ui/button/Button.tsx new file mode 100644 index 0000000..b9320f2 --- /dev/null +++ b/src/shared/ui/button/Button.tsx @@ -0,0 +1,36 @@ +import {twMerge} from 'tailwind-merge'; +import {buttonStyles, type ButtonVariants} from './button-styles'; + +interface ButtonProps extends ButtonVariants { + children: React.ReactNode; + className?: string; + type?: 'button' | 'submit'; + disabled?: boolean; + formID?: string; + onClick?: () => void; + onMouseEnter?: () => void; + onMouseLeave?: () => void; +} + +const Button = ({ + children, + onClick, + type = 'button', + disabled = false, + formID, + className, + ...props +}: ButtonProps) => { + return ( + + ); +}; + +export default Button; diff --git a/src/shared/ui/Button.tsx b/src/shared/ui/button/button-styles.ts similarity index 62% rename from src/shared/ui/Button.tsx rename to src/shared/ui/button/button-styles.ts index fb10864..936e10f 100644 --- a/src/shared/ui/Button.tsx +++ b/src/shared/ui/button/button-styles.ts @@ -1,5 +1,4 @@ import {tv, type VariantProps} from 'tailwind-variants/lite'; -import {twMerge} from 'tailwind-merge'; export const buttonStyles = tv({ base: 'cursor-pointer rounded-[10px] border', @@ -35,38 +34,4 @@ export const buttonStyles = tv({ }, }); -type ButtonVariants = VariantProps; - -interface ButtonProps extends ButtonVariants { - children: React.ReactNode; - className?: string; - type?: 'button' | 'submit'; - disabled?: boolean; - formID?: string; - onClick?: () => void; - onMouseEnter?: () => void; - onMouseLeave?: () => void; -} - -const Button = ({ - children, - onClick, - type = 'button', - disabled = false, - formID, - className, - ...props -}: ButtonProps) => { - return ( - - ); -}; - -export default Button; +export type ButtonVariants = VariantProps; diff --git a/src/shared/ui/Checkbox.module.css b/src/shared/ui/checkbox/Checkbox.module.css similarity index 100% rename from src/shared/ui/Checkbox.module.css rename to src/shared/ui/checkbox/Checkbox.module.css diff --git a/src/shared/ui/Checkbox.tsx b/src/shared/ui/checkbox/Checkbox.tsx similarity index 100% rename from src/shared/ui/Checkbox.tsx rename to src/shared/ui/checkbox/Checkbox.tsx diff --git a/src/shared/ui/list-row/ListRow.tsx b/src/shared/ui/list-row/ListRow.tsx new file mode 100644 index 0000000..91316f0 --- /dev/null +++ b/src/shared/ui/list-row/ListRow.tsx @@ -0,0 +1,27 @@ +import {ListRowStyles, type ListRowVariants} from './list-row-styles'; + +interface ListRowProps extends ListRowVariants { + selected?: boolean; + leftIcon?: React.ReactNode; + title: string; + rightIcon?: React.ReactNode; + className?: string; +} + +const ListRow = ({ + selected = false, + leftIcon, + title, + rightIcon, + className, +}: ListRowProps) => { + return ( +
    +
    {leftIcon}
    +

    {title}

    +
    {rightIcon}
    +
    + ); +}; + +export default ListRow; diff --git a/src/shared/ui/list-row/list-row-styles.ts b/src/shared/ui/list-row/list-row-styles.ts new file mode 100644 index 0000000..5b4135f --- /dev/null +++ b/src/shared/ui/list-row/list-row-styles.ts @@ -0,0 +1,16 @@ +import {tv, type VariantProps} from 'tailwind-variants'; + +export const ListRowStyles = tv({ + base: 'cursor-pointer bg-background w-full flex items-center rounded-[9px] pl-4.5 pr-7.5 py-4 gap-4 border', + variants: { + selected: { + true: 'border-primary', + false: 'border-transparent', + }, + }, + defaultVariants: { + selected: false, + }, +}); + +export type ListRowVariants = VariantProps; diff --git a/src/widgets/assignment-form-layout/ui/AssignmentFormLayout.tsx b/src/widgets/assignment-form-layout/ui/AssignmentFormLayout.tsx index 461335a..9c861d8 100644 --- a/src/widgets/assignment-form-layout/ui/AssignmentFormLayout.tsx +++ b/src/widgets/assignment-form-layout/ui/AssignmentFormLayout.tsx @@ -1,4 +1,4 @@ -import Button from '@/shared/ui/Button'; +import Button from '@/shared/ui/button/Button'; import SurfaceCard from '@/shared/ui/SurfaceCard'; type AssignmentFormLayoutProps = { diff --git a/src/widgets/assignment-page-layout/ui/AssignmentPageLayout.tsx b/src/widgets/assignment-page-layout/ui/AssignmentPageLayout.tsx index 213ea1a..6dc960a 100644 --- a/src/widgets/assignment-page-layout/ui/AssignmentPageLayout.tsx +++ b/src/widgets/assignment-page-layout/ui/AssignmentPageLayout.tsx @@ -1,5 +1,5 @@ import SurfaceCard from '@/shared/ui/SurfaceCard'; -import Button from '@/shared/ui/Button'; +import Button from '@/shared/ui/button/Button'; import {CourseSelector} from '@/features/course/filter-course'; interface AssignmentPageLayoutProps { From 2a88f6d070993de122507247603e6fd6f1f8fac9 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 23 Feb 2026 18:03:55 +0900 Subject: [PATCH 78/91] =?UTF-8?q?#44=20chore:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20admin=20=EB=B8=94=EB=A1=9D=20?= =?UTF-8?q?=EB=82=B4=EB=B6=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index a835c1b..f9fe6d3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,7 +12,7 @@ import StudentProfilePage from '@/pages/admin/student/StudentProfilePage'; import KakaoCallbackPage from '@/pages/common/KakaoCallbackPage'; import PrivateRoute from '@/widgets/private-route/ui/PrivateRoute'; import {useSyncUserRole} from '@/features/auth/sync-user-role/model/useSyncUserRole'; -import {UnitEditorPage} from './pages/unit-editor/UnitEditorPage'; +import UnitEditorPage from '@/pages/unit-editor/UnitEditorPage'; const AppRoutes = () => { useSyncUserRole(); @@ -53,8 +53,8 @@ const AppRoutes = () => { path='student/profile/:studentId' element={} /> + } /> - } /> From 0b37ab389bd52fd58f8270da35567c1aacfb2200 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 23 Feb 2026 18:20:11 +0900 Subject: [PATCH 79/91] =?UTF-8?q?#44=20fix:=20unitId=20=ED=83=80=EC=9E=85?= =?UTF-8?q?=20=EB=B0=8F=20dnd-kit=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EB=AA=85=EC=8B=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitApi.ts | 2 +- src/entities/unit/api/unitQueries.ts | 2 +- src/pages/unit-editor/ui/UnitAssignmentList.tsx | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/entities/unit/api/unitApi.ts b/src/entities/unit/api/unitApi.ts index b716386..75ec450 100644 --- a/src/entities/unit/api/unitApi.ts +++ b/src/entities/unit/api/unitApi.ts @@ -13,7 +13,7 @@ export const getAllUnitsByCourseId = async ( // 단일 단원 조회 export const getUnitById = async ( - unitId: number | null + unitId: number ): Promise> => { const response = await privateAxios.get(`/units/${unitId}`); return response.data; diff --git a/src/entities/unit/api/unitQueries.ts b/src/entities/unit/api/unitQueries.ts index ff10576..e71cc5d 100644 --- a/src/entities/unit/api/unitQueries.ts +++ b/src/entities/unit/api/unitQueries.ts @@ -10,7 +10,7 @@ export const unitQueries = { }), // 단일 단원 조회 쿼리 옵션 - getUnitDetails: (unitId: number | null) => + getUnitDetails: (unitId: number) => queryOptions({ queryKey: ['units', 'detail', unitId], queryFn: () => getUnitById(unitId), diff --git a/src/pages/unit-editor/ui/UnitAssignmentList.tsx b/src/pages/unit-editor/ui/UnitAssignmentList.tsx index 842326b..510fc1c 100644 --- a/src/pages/unit-editor/ui/UnitAssignmentList.tsx +++ b/src/pages/unit-editor/ui/UnitAssignmentList.tsx @@ -10,6 +10,8 @@ import { PointerSensor, useSensor, useSensors, + type DragEndEvent, + type UniqueIdentifier, } from '@dnd-kit/core'; import { SortableContext, @@ -28,15 +30,13 @@ export const UnitAssignmentList = ({ const [assignments, setAssignments] = useState(assignmentList); // 과제 인덱스 찾기 - const getAssignmentIndex = (id: number) => { + const getAssignmentIndex = (id: UniqueIdentifier) => { return assignments.findIndex((assignment) => assignment.id === id); }; - const handleDragEnd = (event: any) => { + const handleDragEnd = ({active, over}: DragEndEvent) => { // active: 드래그 중인 아이템, over: 드래그가 끝난 위치의 아이템 - const {active, over} = event; - - if (active.id === over.id) return; // 위치가 바뀌지 않은 경우 + if (!over || active.id === over.id) return; // 위치가 바뀌지 않은 경우 // 위치가 바뀐 경우 - 배열에서 아이템의 위치를 업데이트 setAssignments((assignments) => { @@ -96,7 +96,7 @@ const DraggableAssignmentItem = ({id, title}: Assignment) => { title={title} leftIcon={} rightIcon={} - className={`cursor grab touch-none bg-white shadow-box active:cursor-grabbing ${isDragging ? 'z-10 opacity-50' : ''}`} + className={`cursor-grab touch-none bg-white shadow-box active:cursor-grabbing ${isDragging ? 'z-10 opacity-50' : ''}`} />
  • ); From 324f8c3fa3e8667817823aa60ae93def33e8aee9 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 23 Feb 2026 18:21:16 +0900 Subject: [PATCH 80/91] =?UTF-8?q?#44=20fix:=20=EB=8B=A8=EC=9B=90=20?= =?UTF-8?q?=ED=8F=BC=20id=20unitIndex=20=EA=B8=B0=EB=B0=98=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/unit-editor/ui/UnitForm.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pages/unit-editor/ui/UnitForm.tsx b/src/pages/unit-editor/ui/UnitForm.tsx index d685bd1..921d7d1 100644 --- a/src/pages/unit-editor/ui/UnitForm.tsx +++ b/src/pages/unit-editor/ui/UnitForm.tsx @@ -71,7 +71,7 @@ export const UnitForm = ({
    {/* 단원 편집 폼 */}
    {/* 폼 헤더 */} @@ -148,7 +148,10 @@ export const UnitForm = ({ -
    From 41445624bcc2e07e072555eba521d8ca942a5d69 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 23 Feb 2026 18:21:32 +0900 Subject: [PATCH 81/91] =?UTF-8?q?#44=20chore:=20zod=20import=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=ED=86=B5=EC=9D=BC=20=EB=B0=8F=20=EC=A3=BC=EC=84=9D?= =?UTF-8?q?=20=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/model/types.ts | 2 +- src/pages/unit-editor/ui/UnitList.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/entities/unit/model/types.ts b/src/entities/unit/model/types.ts index e97dfdd..d6b1c63 100644 --- a/src/entities/unit/model/types.ts +++ b/src/entities/unit/model/types.ts @@ -1,4 +1,4 @@ -import z from 'zod'; +import {z} from 'zod'; // 단원 생성/수정 폼 스키마 export const unitFormSchema = z diff --git a/src/pages/unit-editor/ui/UnitList.tsx b/src/pages/unit-editor/ui/UnitList.tsx index c741afd..dab86a7 100644 --- a/src/pages/unit-editor/ui/UnitList.tsx +++ b/src/pages/unit-editor/ui/UnitList.tsx @@ -40,7 +40,7 @@ export const UnitList = ({ onClick={() => handleSelectUnit(id)} key={id} className={`flex flex-col py-5 px-12 gap-2.5 cursor-pointer ${selectedUnitId === id ? 'bg-background' : ''}`}> - {/* 단원 인덱스 배지 */} + {/* 과제 수 배지 */}
    {assignmentCount} From 9742a0975be85d2b842f8e794277e10fd4c3e7b8 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 23 Feb 2026 18:29:43 +0900 Subject: [PATCH 82/91] =?UTF-8?q?#44=20fix:=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/unit-editor/ui/UnitForm.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/unit-editor/ui/UnitForm.tsx b/src/pages/unit-editor/ui/UnitForm.tsx index 921d7d1..66cbec5 100644 --- a/src/pages/unit-editor/ui/UnitForm.tsx +++ b/src/pages/unit-editor/ui/UnitForm.tsx @@ -7,7 +7,7 @@ import {zodResolver} from '@hookform/resolvers/zod'; import {type UnitFormProps} from '../model/types'; import AddIcon from '@/assets/svg/addIcon.svg?react'; import {EmptyState} from '@/shared/ui/EmptyState'; -import {useState} from 'react'; +// import {useState} from 'react'; import { unitFormSchema, type TUnitFormSchema, @@ -21,7 +21,7 @@ export const UnitForm = ({ onUpdateUnit, onDeleteUnit, }: UnitFormProps) => { - const [assignmentIds, setAssignmentIds] = useState([]); + // const [assignmentIds, setAssignmentIds] = useState([]); const { register, From 2548c669dd1bef669b7723d3d55ea1bd411b30c2 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 23 Feb 2026 18:38:21 +0900 Subject: [PATCH 83/91] =?UTF-8?q?#44=20fix:=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/unit/api/unitApi.ts | 2 +- src/entities/unit/api/unitQueries.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/entities/unit/api/unitApi.ts b/src/entities/unit/api/unitApi.ts index 75ec450..b716386 100644 --- a/src/entities/unit/api/unitApi.ts +++ b/src/entities/unit/api/unitApi.ts @@ -13,7 +13,7 @@ export const getAllUnitsByCourseId = async ( // 단일 단원 조회 export const getUnitById = async ( - unitId: number + unitId: number | null ): Promise> => { const response = await privateAxios.get(`/units/${unitId}`); return response.data; diff --git a/src/entities/unit/api/unitQueries.ts b/src/entities/unit/api/unitQueries.ts index e71cc5d..ff10576 100644 --- a/src/entities/unit/api/unitQueries.ts +++ b/src/entities/unit/api/unitQueries.ts @@ -10,7 +10,7 @@ export const unitQueries = { }), // 단일 단원 조회 쿼리 옵션 - getUnitDetails: (unitId: number) => + getUnitDetails: (unitId: number | null) => queryOptions({ queryKey: ['units', 'detail', unitId], queryFn: () => getUnitById(unitId), From 6d7d3ea43f10a61f0e57fe86cbc963f762bba411 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 23 Feb 2026 19:33:53 +0900 Subject: [PATCH 84/91] =?UTF-8?q?#44=20fix:=20pnpm-lock.yaml=20=EA=B0=B1?= =?UTF-8?q?=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pnpm-lock.yaml | 858 +++++++++++++++++++++++++------------------------ 1 file changed, 436 insertions(+), 422 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b73f2ba..4e2cd50 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,10 +19,10 @@ importers: version: 3.2.2(react@19.2.4) '@hookform/resolvers': specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.71.1(react@19.2.4)) + version: 5.2.2(react-hook-form@7.71.2(react@19.2.4)) '@tailwindcss/vite': specifier: ^4.1.11 - version: 4.1.18(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)) + version: 4.2.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)) '@tanstack/react-query': specifier: ^5.90.20 version: 5.90.21(react@19.2.4) @@ -37,19 +37,19 @@ importers: version: 19.2.4(react@19.2.4) react-hook-form: specifier: ^7.71.1 - version: 7.71.1(react@19.2.4) + version: 7.71.2(react@19.2.4) react-router-dom: specifier: ^7.6.3 version: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tailwind-merge: specifier: ^3.4.0 - version: 3.4.0 + version: 3.5.0 tailwind-variants: specifier: ^3.2.2 - version: 3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.18) + version: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.0) tailwindcss: specifier: ^4.1.11 - version: 4.1.18 + version: 4.2.0 zod: specifier: ^4.3.6 version: 4.3.6 @@ -59,19 +59,19 @@ importers: devDependencies: '@commitlint/cli': specifier: ^20.3.0 - version: 20.4.1(@types/node@24.10.13)(typescript@5.8.3) + version: 20.4.2(@types/node@24.10.13)(typescript@5.8.3) '@commitlint/config-conventional': specifier: ^20.3.0 - version: 20.4.1 + version: 20.4.2 '@eslint/js': specifier: ^9.29.0 - version: 9.39.2 + version: 9.39.3 '@feature-sliced/steiger-plugin': specifier: ^0.5.7 version: 0.5.7(typescript@5.8.3) '@tanstack/eslint-plugin-query': specifier: ^5.91.4 - version: 5.91.4(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) + version: 5.91.4(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3) '@types/node': specifier: ^24.2.1 version: 24.10.13 @@ -83,16 +83,16 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^4.5.2 - version: 4.7.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)) + version: 4.7.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)) eslint: specifier: ^9.29.0 - version: 9.39.2(jiti@2.6.1) + version: 9.39.3(jiti@2.6.1) eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.39.2(jiti@2.6.1)) + version: 5.2.0(eslint@9.39.3(jiti@2.6.1)) eslint-plugin-react-refresh: specifier: ^0.4.20 - version: 0.4.26(eslint@9.39.2(jiti@2.6.1)) + version: 0.4.26(eslint@9.39.3(jiti@2.6.1)) globals: specifier: ^16.2.0 version: 16.5.0 @@ -113,16 +113,16 @@ importers: version: 5.8.3 typescript-eslint: specifier: ^8.34.1 - version: 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) + version: 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3) vite: specifier: ^7.0.0 - version: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2) + version: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1) vite-plugin-svgr: specifier: ^4.3.0 - version: 4.5.0(rollup@4.57.1)(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)) + version: 4.5.0(rollup@4.59.0)(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)) + version: 5.1.4(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)) packages: @@ -215,13 +215,13 @@ packages: '@clack/prompts@0.9.1': resolution: {integrity: sha512-JIpyaboYZeWYlyP0H+OoPPxd6nqueG/CmN6ixBiNFsIDHREevjIf0n0Ohh5gr5C8pEDknzgvz+pIJ8dMhzWIeg==} - '@commitlint/cli@20.4.1': - resolution: {integrity: sha512-uuFKKpc7OtQM+6SRqT+a4kV818o1pS+uvv/gsRhyX7g4x495jg+Q7P0+O9VNGyLXBYP0syksS7gMRDJKcekr6A==} + '@commitlint/cli@20.4.2': + resolution: {integrity: sha512-YjYSX2yj/WsVoxh9mNiymfFS2ADbg2EK4+1WAsMuckwKMCqJ5PDG0CJU/8GvmHWcv4VRB2V02KqSiecRksWqZQ==} engines: {node: '>=v18'} hasBin: true - '@commitlint/config-conventional@20.4.1': - resolution: {integrity: sha512-0YUvIeBtpi86XriqrR+TCULVFiyYTIOEPjK7tTRMxjcBm1qlzb+kz7IF2WxL6Fq5DaundG8VO37BNgMkMTBwqA==} + '@commitlint/config-conventional@20.4.2': + resolution: {integrity: sha512-rwkTF55q7Q+6dpSKUmJoScV0f3EpDlWKw2UPzklkLS4o5krMN1tPWAVOgHRtyUTMneIapLeQwaCjn44Td6OzBQ==} engines: {node: '>=v18'} '@commitlint/config-validator@20.4.0': @@ -244,8 +244,8 @@ packages: resolution: {integrity: sha512-In5EO4JR1lNsAv1oOBBO24V9ND1IqdAJDKZiEpdfjDl2HMasAcT7oA+5BKONv1pRoLG380DGPE2W2RIcUwdgLA==} engines: {node: '>=v18'} - '@commitlint/lint@20.4.1': - resolution: {integrity: sha512-g94LrGl/c6UhuhDQqNqU232aslLEN2vzc7MPfQTHzwzM4GHNnEAwVWWnh0zX8S5YXecuLXDwbCsoGwmpAgPWKA==} + '@commitlint/lint@20.4.2': + resolution: {integrity: sha512-buquzNRtFng6xjXvBU1abY/WPEEjCgUipNQrNmIWe8QuJ6LWLtei/LDBAzEe5ASm45+Q9L2Xi3/GVvlj50GAug==} engines: {node: '>=v18'} '@commitlint/load@20.4.0': @@ -268,8 +268,8 @@ packages: resolution: {integrity: sha512-ay1KM8q0t+/OnlpqXJ+7gEFQNlUtSU5Gxr8GEwnVf2TPN3+ywc5DzL3JCxmpucqxfHBTFwfRMXxPRRnR5Ki20g==} engines: {node: '>=v18'} - '@commitlint/rules@20.4.1': - resolution: {integrity: sha512-WtqypKEPbQEuJwJS4aKs0OoJRBKz1HXPBC9wRtzVNH68FLhPWzxXlF09hpUXM9zdYTpm4vAdoTGkWiBgQ/vL0g==} + '@commitlint/rules@20.4.2': + resolution: {integrity: sha512-oz83pnp5Yq6uwwTAabuVQPNlPfeD2Y5ZjMb7Wx8FSUlu4sLYJjbBWt8031Z0osCFPfHzAwSYrjnfDFKtuSMdKg==} engines: {node: '>=v18'} '@commitlint/to-lines@20.0.0': @@ -492,8 +492,8 @@ packages: resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.2': - resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} + '@eslint/js@9.39.3': + resolution: {integrity: sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.7': @@ -571,128 +571,128 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.57.1': - resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} + '@rollup/rollup-android-arm-eabi@4.59.0': + resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.57.1': - resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} + '@rollup/rollup-android-arm64@4.59.0': + resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.57.1': - resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} + '@rollup/rollup-darwin-arm64@4.59.0': + resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.57.1': - resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} + '@rollup/rollup-darwin-x64@4.59.0': + resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.57.1': - resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} + '@rollup/rollup-freebsd-arm64@4.59.0': + resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.57.1': - resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} + '@rollup/rollup-freebsd-x64@4.59.0': + resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.57.1': - resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.57.1': - resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.57.1': - resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} + '@rollup/rollup-linux-arm64-gnu@4.59.0': + resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.57.1': - resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} + '@rollup/rollup-linux-arm64-musl@4.59.0': + resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.57.1': - resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} + '@rollup/rollup-linux-loong64-gnu@4.59.0': + resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-loong64-musl@4.57.1': - resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} + '@rollup/rollup-linux-loong64-musl@4.59.0': + resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.57.1': - resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-ppc64-musl@4.57.1': - resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} + '@rollup/rollup-linux-ppc64-musl@4.59.0': + resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.57.1': - resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.57.1': - resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} + '@rollup/rollup-linux-riscv64-musl@4.59.0': + resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.57.1': - resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} + '@rollup/rollup-linux-s390x-gnu@4.59.0': + resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.57.1': - resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} + '@rollup/rollup-linux-x64-gnu@4.59.0': + resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.57.1': - resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} + '@rollup/rollup-linux-x64-musl@4.59.0': + resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} cpu: [x64] os: [linux] - '@rollup/rollup-openbsd-x64@4.57.1': - resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} + '@rollup/rollup-openbsd-x64@4.59.0': + resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.57.1': - resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} + '@rollup/rollup-openharmony-arm64@4.59.0': + resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.57.1': - resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} + '@rollup/rollup-win32-arm64-msvc@4.59.0': + resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.57.1': - resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} + '@rollup/rollup-win32-ia32-msvc@4.59.0': + resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.57.1': - resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} + '@rollup/rollup-win32-x64-gnu@4.59.0': + resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.57.1': - resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} + '@rollup/rollup-win32-x64-msvc@4.59.0': + resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} cpu: [x64] os: [win32] @@ -771,65 +771,65 @@ packages: peerDependencies: '@svgr/core': '*' - '@tailwindcss/node@4.1.18': - resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} + '@tailwindcss/node@4.2.0': + resolution: {integrity: sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q==} - '@tailwindcss/oxide-android-arm64@4.1.18': - resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-android-arm64@4.2.0': + resolution: {integrity: sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw==} + engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.18': - resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-darwin-arm64@4.2.0': + resolution: {integrity: sha512-I0QylkXsBsJMZ4nkUNSR04p6+UptjcwhcVo3Zu828ikiEqHjVmQL9RuQ6uT/cVIiKpvtVA25msu/eRV97JeNSA==} + engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.18': - resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-darwin-x64@4.2.0': + resolution: {integrity: sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg==} + engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.18': - resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-freebsd-x64@4.2.0': + resolution: {integrity: sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw==} + engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.0': + resolution: {integrity: sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg==} + engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm64-gnu@4.2.0': + resolution: {integrity: sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm64-musl@4.2.0': + resolution: {integrity: sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-x64-gnu@4.2.0': + resolution: {integrity: sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-x64-musl@4.2.0': + resolution: {integrity: sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} + '@tailwindcss/oxide-wasm32-wasi@4.2.0': + resolution: {integrity: sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -840,24 +840,24 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-win32-arm64-msvc@4.2.0': + resolution: {integrity: sha512-2UU/15y1sWDEDNJXxEIrfWKC2Yb4YgIW5Xz2fKFqGzFWfoMHWFlfa1EJlGO2Xzjkq/tvSarh9ZTjvbxqWvLLXA==} + engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-win32-x64-msvc@4.2.0': + resolution: {integrity: sha512-CrFadmFoc+z76EV6LPG1jx6XceDsaCG3lFhyLNo/bV9ByPrE+FnBPckXQVP4XRkN76h3Fjt/a+5Er/oA/nCBvQ==} + engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.18': - resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} - engines: {node: '>= 10'} + '@tailwindcss/oxide@4.2.0': + resolution: {integrity: sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ==} + engines: {node: '>= 20'} - '@tailwindcss/vite@4.1.18': - resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} + '@tailwindcss/vite@4.2.0': + resolution: {integrity: sha512-da9mFCaHpoOgtQiWtDGIikTrSpUFBtIZCG3jy/u2BGV+l/X1/pbxzmIUxNt6JWm19N3WtGi4KlJdSH/Si83WOA==} peerDependencies: vite: ^5.2.0 || ^6 || ^7 @@ -907,63 +907,63 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - '@typescript-eslint/eslint-plugin@8.55.0': - resolution: {integrity: sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ==} + '@typescript-eslint/eslint-plugin@8.56.0': + resolution: {integrity: sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.55.0 - eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/parser': ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.55.0': - resolution: {integrity: sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==} + '@typescript-eslint/parser@8.56.0': + resolution: {integrity: sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.55.0': - resolution: {integrity: sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ==} + '@typescript-eslint/project-service@8.56.0': + resolution: {integrity: sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.55.0': - resolution: {integrity: sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q==} + '@typescript-eslint/scope-manager@8.56.0': + resolution: {integrity: sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.55.0': - resolution: {integrity: sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q==} + '@typescript-eslint/tsconfig-utils@8.56.0': + resolution: {integrity: sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.55.0': - resolution: {integrity: sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g==} + '@typescript-eslint/type-utils@8.56.0': + resolution: {integrity: sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.55.0': - resolution: {integrity: sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==} + '@typescript-eslint/types@8.56.0': + resolution: {integrity: sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.55.0': - resolution: {integrity: sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw==} + '@typescript-eslint/typescript-estree@8.56.0': + resolution: {integrity: sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.55.0': - resolution: {integrity: sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow==} + '@typescript-eslint/utils@8.56.0': + resolution: {integrity: sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.55.0': - resolution: {integrity: sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA==} + '@typescript-eslint/visitor-keys@8.56.0': + resolution: {integrity: sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@vitejs/plugin-react@4.7.0': @@ -992,16 +992,16 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -1030,15 +1030,21 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.9.19: - resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.10.0: + resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + engines: {node: '>=6.0.0'} hasBin: true brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.3: + resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==} + engines: {node: 18 || 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -1061,8 +1067,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001769: - resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} + caniuse-lite@1.0.30001774: + resolution: {integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -1232,8 +1238,8 @@ packages: resolution: {integrity: sha512-QkZboRN28K/iwxigDhlJcI3ux3aNbt8kYGGH/GkqWG0OlGeyuBhb7PdM89Iu+ogV8Lmz16xIlwnXR2UNWI6psg==} engines: {node: '>=11.0.0'} - electron-to-chromium@1.5.286: - resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} + electron-to-chromium@1.5.302: + resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1318,8 +1324,12 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.39.2: - resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.3: + resolution: {integrity: sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -1614,74 +1624,74 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + lightningcss-android-arm64@1.31.1: + resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + lightningcss-darwin-arm64@1.31.1: + resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + lightningcss-darwin-x64@1.31.1: + resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + lightningcss-freebsd-x64@1.31.1: + resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + lightningcss-linux-arm-gnueabihf@1.31.1: + resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + lightningcss-linux-arm64-gnu@1.31.1: + resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + lightningcss-linux-arm64-musl@1.31.1: + resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + lightningcss-linux-x64-gnu@1.31.1: + resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + lightningcss-linux-x64-musl@1.31.1: + resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + lightningcss-win32-arm64-msvc@1.31.1: + resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + lightningcss-win32-x64-msvc@1.31.1: + resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + lightningcss@1.31.1: + resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} engines: {node: '>= 12.0.0'} lines-and-columns@1.2.4: @@ -1752,11 +1762,11 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.3: + resolution: {integrity: sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.6: + resolution: {integrity: sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: @@ -1951,8 +1961,8 @@ packages: peerDependencies: react: ^19.2.4 - react-hook-form@7.71.1: - resolution: {integrity: sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==} + react-hook-form@7.71.2: + resolution: {integrity: sha512-1CHvcDYzuRUNOflt4MOq3ZM46AronNJtQ1S7tnX6YN4y72qhgiUItpacZUAQ0TyWYci3yz1X+rXaSxiuEm86PA==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 @@ -2006,8 +2016,8 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rollup@4.57.1: - resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} + rollup@4.59.0: + resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2086,8 +2096,8 @@ packages: svg-parser@2.0.4: resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} - tailwind-merge@3.4.0: - resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + tailwind-merge@3.5.0: + resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} tailwind-variants@3.2.2: resolution: {integrity: sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==} @@ -2099,8 +2109,8 @@ packages: tailwind-merge: optional: true - tailwindcss@4.1.18: - resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} + tailwindcss@4.2.0: + resolution: {integrity: sha512-yYzTZ4++b7fNYxFfpnberEEKu43w44aqDMNM9MHMmcKuCH7lL8jJ4yJ7LGHv7rSwiqM0nkiobF9I6cLlpS2P7Q==} tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} @@ -2145,11 +2155,11 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.55.0: - resolution: {integrity: sha512-HE4wj+r5lmDVS9gdaN0/+iqNvPZwGfnJ5lZuz7s5vLlg9ODw0bIiiETaios9LvFI1U94/VBXGm3CB2Y5cNFMpw==} + typescript-eslint@8.56.0: + resolution: {integrity: sha512-c7toRLrotJ9oixgdW7liukZpsnq5CZ7PuKztubGYlNppuTqhIoWfhgHo/7EU0v06gS2l/x0i2NEFK1qMIf0rIg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' typescript@5.8.3: @@ -2413,10 +2423,10 @@ snapshots: picocolors: 1.1.1 sisteransi: 1.0.5 - '@commitlint/cli@20.4.1(@types/node@24.10.13)(typescript@5.8.3)': + '@commitlint/cli@20.4.2(@types/node@24.10.13)(typescript@5.8.3)': dependencies: '@commitlint/format': 20.4.0 - '@commitlint/lint': 20.4.1 + '@commitlint/lint': 20.4.2 '@commitlint/load': 20.4.0(@types/node@24.10.13)(typescript@5.8.3) '@commitlint/read': 20.4.0 '@commitlint/types': 20.4.0 @@ -2426,7 +2436,7 @@ snapshots: - '@types/node' - typescript - '@commitlint/config-conventional@20.4.1': + '@commitlint/config-conventional@20.4.2': dependencies: '@commitlint/types': 20.4.0 conventional-changelog-conventionalcommits: 9.1.0 @@ -2434,7 +2444,7 @@ snapshots: '@commitlint/config-validator@20.4.0': dependencies: '@commitlint/types': 20.4.0 - ajv: 8.17.1 + ajv: 8.18.0 '@commitlint/ensure@20.4.1': dependencies: @@ -2457,11 +2467,11 @@ snapshots: '@commitlint/types': 20.4.0 semver: 7.7.4 - '@commitlint/lint@20.4.1': + '@commitlint/lint@20.4.2': dependencies: '@commitlint/is-ignored': 20.4.1 '@commitlint/parse': 20.4.1 - '@commitlint/rules': 20.4.1 + '@commitlint/rules': 20.4.2 '@commitlint/types': 20.4.0 '@commitlint/load@20.4.0(@types/node@24.10.13)(typescript@5.8.3)': @@ -2504,7 +2514,7 @@ snapshots: lodash.mergewith: 4.6.2 resolve-from: 5.0.0 - '@commitlint/rules@20.4.1': + '@commitlint/rules@20.4.2': dependencies: '@commitlint/ensure': 20.4.1 '@commitlint/message': 20.4.0 @@ -2630,9 +2640,9 @@ snapshots: '@esbuild/win32-x64@0.27.3': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.3(jiti@2.6.1))': dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.3(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -2641,7 +2651,7 @@ snapshots: dependencies: '@eslint/object-schema': 2.1.7 debug: 4.4.3 - minimatch: 3.1.2 + minimatch: 3.1.3 transitivePeerDependencies: - supports-color @@ -2655,19 +2665,19 @@ snapshots: '@eslint/eslintrc@3.3.3': dependencies: - ajv: 6.12.6 + ajv: 6.14.0 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 js-yaml: 4.1.1 - minimatch: 3.1.2 + minimatch: 3.1.3 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/js@9.39.2': {} + '@eslint/js@9.39.3': {} '@eslint/object-schema@2.1.7': {} @@ -2692,10 +2702,10 @@ snapshots: - supports-color - typescript - '@hookform/resolvers@5.2.2(react-hook-form@7.71.1(react@19.2.4))': + '@hookform/resolvers@5.2.2(react-hook-form@7.71.2(react@19.2.4))': dependencies: '@standard-schema/utils': 0.3.0 - react-hook-form: 7.71.1(react@19.2.4) + react-hook-form: 7.71.2(react@19.2.4) '@humanfs/core@0.19.1': {} @@ -2741,87 +2751,87 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.27': {} - '@rollup/pluginutils@5.3.0(rollup@4.57.1)': + '@rollup/pluginutils@5.3.0(rollup@4.59.0)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.57.1 + rollup: 4.59.0 - '@rollup/rollup-android-arm-eabi@4.57.1': + '@rollup/rollup-android-arm-eabi@4.59.0': optional: true - '@rollup/rollup-android-arm64@4.57.1': + '@rollup/rollup-android-arm64@4.59.0': optional: true - '@rollup/rollup-darwin-arm64@4.57.1': + '@rollup/rollup-darwin-arm64@4.59.0': optional: true - '@rollup/rollup-darwin-x64@4.57.1': + '@rollup/rollup-darwin-x64@4.59.0': optional: true - '@rollup/rollup-freebsd-arm64@4.57.1': + '@rollup/rollup-freebsd-arm64@4.59.0': optional: true - '@rollup/rollup-freebsd-x64@4.57.1': + '@rollup/rollup-freebsd-x64@4.59.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.57.1': + '@rollup/rollup-linux-arm-musleabihf@4.59.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.57.1': + '@rollup/rollup-linux-arm64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.57.1': + '@rollup/rollup-linux-arm64-musl@4.59.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.57.1': + '@rollup/rollup-linux-loong64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-loong64-musl@4.57.1': + '@rollup/rollup-linux-loong64-musl@4.59.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.57.1': + '@rollup/rollup-linux-ppc64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-ppc64-musl@4.57.1': + '@rollup/rollup-linux-ppc64-musl@4.59.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.57.1': + '@rollup/rollup-linux-riscv64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.57.1': + '@rollup/rollup-linux-riscv64-musl@4.59.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.57.1': + '@rollup/rollup-linux-s390x-gnu@4.59.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.57.1': + '@rollup/rollup-linux-x64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-x64-musl@4.57.1': + '@rollup/rollup-linux-x64-musl@4.59.0': optional: true - '@rollup/rollup-openbsd-x64@4.57.1': + '@rollup/rollup-openbsd-x64@4.59.0': optional: true - '@rollup/rollup-openharmony-arm64@4.57.1': + '@rollup/rollup-openharmony-arm64@4.59.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.57.1': + '@rollup/rollup-win32-arm64-msvc@4.59.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.57.1': + '@rollup/rollup-win32-ia32-msvc@4.59.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.57.1': + '@rollup/rollup-win32-x64-gnu@4.59.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.57.1': + '@rollup/rollup-win32-x64-msvc@4.59.0': optional: true '@sindresorhus/merge-streams@2.3.0': {} @@ -2898,78 +2908,78 @@ snapshots: transitivePeerDependencies: - supports-color - '@tailwindcss/node@4.1.18': + '@tailwindcss/node@4.2.0': dependencies: '@jridgewell/remapping': 2.3.5 enhanced-resolve: 5.19.0 jiti: 2.6.1 - lightningcss: 1.30.2 + lightningcss: 1.31.1 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.1.18 + tailwindcss: 4.2.0 - '@tailwindcss/oxide-android-arm64@4.1.18': + '@tailwindcss/oxide-android-arm64@4.2.0': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.18': + '@tailwindcss/oxide-darwin-arm64@4.2.0': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.18': + '@tailwindcss/oxide-darwin-x64@4.2.0': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.18': + '@tailwindcss/oxide-freebsd-x64@4.2.0': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.0': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + '@tailwindcss/oxide-linux-arm64-gnu@4.2.0': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + '@tailwindcss/oxide-linux-arm64-musl@4.2.0': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + '@tailwindcss/oxide-linux-x64-gnu@4.2.0': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.18': + '@tailwindcss/oxide-linux-x64-musl@4.2.0': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.18': + '@tailwindcss/oxide-wasm32-wasi@4.2.0': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + '@tailwindcss/oxide-win32-arm64-msvc@4.2.0': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + '@tailwindcss/oxide-win32-x64-msvc@4.2.0': optional: true - '@tailwindcss/oxide@4.1.18': + '@tailwindcss/oxide@4.2.0': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-x64': 4.1.18 - '@tailwindcss/oxide-freebsd-x64': 4.1.18 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-x64-musl': 4.1.18 - '@tailwindcss/oxide-wasm32-wasi': 4.1.18 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 - - '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2))': - dependencies: - '@tailwindcss/node': 4.1.18 - '@tailwindcss/oxide': 4.1.18 - tailwindcss: 4.1.18 - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2) - - '@tanstack/eslint-plugin-query@5.91.4(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)': - dependencies: - '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) - eslint: 9.39.2(jiti@2.6.1) + '@tailwindcss/oxide-android-arm64': 4.2.0 + '@tailwindcss/oxide-darwin-arm64': 4.2.0 + '@tailwindcss/oxide-darwin-x64': 4.2.0 + '@tailwindcss/oxide-freebsd-x64': 4.2.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.0 + '@tailwindcss/oxide-linux-x64-musl': 4.2.0 + '@tailwindcss/oxide-wasm32-wasi': 4.2.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.0 + + '@tailwindcss/vite@4.2.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1))': + dependencies: + '@tailwindcss/node': 4.2.0 + '@tailwindcss/oxide': 4.2.0 + tailwindcss: 4.2.0 + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1) + + '@tanstack/eslint-plugin-query@5.91.4(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/utils': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3) + eslint: 9.39.3(jiti@2.6.1) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -3019,15 +3029,15 @@ snapshots: dependencies: csstype: 3.2.3 - '@typescript-eslint/eslint-plugin@8.55.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/scope-manager': 8.55.0 - '@typescript-eslint/type-utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.55.0 - eslint: 9.39.2(jiti@2.6.1) + '@typescript-eslint/parser': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/type-utils': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3) + '@typescript-eslint/utils': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.56.0 + eslint: 9.39.3(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.4.0(typescript@5.8.3) @@ -3035,58 +3045,58 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)': + '@typescript-eslint/parser@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3)': dependencies: - '@typescript-eslint/scope-manager': 8.55.0 - '@typescript-eslint/types': 8.55.0 - '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.55.0 + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.56.0 debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.3(jiti@2.6.1) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.55.0(typescript@5.8.3)': + '@typescript-eslint/project-service@8.56.0(typescript@5.8.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.55.0(typescript@5.8.3) - '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/tsconfig-utils': 8.56.0(typescript@5.8.3) + '@typescript-eslint/types': 8.56.0 debug: 4.4.3 typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.55.0': + '@typescript-eslint/scope-manager@8.56.0': dependencies: - '@typescript-eslint/types': 8.55.0 - '@typescript-eslint/visitor-keys': 8.55.0 + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/visitor-keys': 8.56.0 - '@typescript-eslint/tsconfig-utils@8.55.0(typescript@5.8.3)': + '@typescript-eslint/tsconfig-utils@8.56.0(typescript@5.8.3)': dependencies: typescript: 5.8.3 - '@typescript-eslint/type-utils@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3)': dependencies: - '@typescript-eslint/types': 8.55.0 - '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.8.3) - '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3) debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.3(jiti@2.6.1) ts-api-utils: 2.4.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.55.0': {} + '@typescript-eslint/types@8.56.0': {} - '@typescript-eslint/typescript-estree@8.55.0(typescript@5.8.3)': + '@typescript-eslint/typescript-estree@8.56.0(typescript@5.8.3)': dependencies: - '@typescript-eslint/project-service': 8.55.0(typescript@5.8.3) - '@typescript-eslint/tsconfig-utils': 8.55.0(typescript@5.8.3) - '@typescript-eslint/types': 8.55.0 - '@typescript-eslint/visitor-keys': 8.55.0 + '@typescript-eslint/project-service': 8.56.0(typescript@5.8.3) + '@typescript-eslint/tsconfig-utils': 8.56.0(typescript@5.8.3) + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/visitor-keys': 8.56.0 debug: 4.4.3 - minimatch: 9.0.5 + minimatch: 9.0.6 semver: 7.7.4 tinyglobby: 0.2.15 ts-api-utils: 2.4.0(typescript@5.8.3) @@ -3094,23 +3104,23 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3)': + '@typescript-eslint/utils@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.55.0 - '@typescript-eslint/types': 8.55.0 - '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.8.3) - eslint: 9.39.2(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.8.3) + eslint: 9.39.3(jiti@2.6.1) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.55.0': + '@typescript-eslint/visitor-keys@8.56.0': dependencies: - '@typescript-eslint/types': 8.55.0 - eslint-visitor-keys: 4.2.1 + '@typescript-eslint/types': 8.56.0 + eslint-visitor-keys: 5.0.1 - '@vitejs/plugin-react@4.7.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2))': + '@vitejs/plugin-react@4.7.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -3118,7 +3128,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1) transitivePeerDependencies: - supports-color @@ -3154,20 +3164,20 @@ snapshots: '@vue/shared@3.5.28': {} - acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn@8.15.0: {} + acorn@8.16.0: {} - ajv@6.12.6: + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.17.1: + ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 fast-uri: 3.1.0 @@ -3198,16 +3208,18 @@ snapshots: balanced-match@1.0.2: {} - baseline-browser-mapping@2.9.19: {} + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.10.0: {} brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.2: + brace-expansion@5.0.3: dependencies: - balanced-match: 1.0.2 + balanced-match: 4.0.4 braces@3.0.3: dependencies: @@ -3215,9 +3227,9 @@ snapshots: browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.19 - caniuse-lite: 1.0.30001769 - electron-to-chromium: 1.5.286 + baseline-browser-mapping: 2.10.0 + caniuse-lite: 1.0.30001774 + electron-to-chromium: 1.5.302 node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -3230,7 +3242,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001769: {} + caniuse-lite@1.0.30001774: {} chalk@4.1.2: dependencies: @@ -3363,7 +3375,7 @@ snapshots: detective-typescript@14.0.0(typescript@5.8.3): dependencies: - '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.8.3) ast-module-types: 6.0.1 node-source-walk: 7.0.1 typescript: 5.8.3 @@ -3400,7 +3412,7 @@ snapshots: effector@23.4.4: {} - electron-to-chromium@1.5.286: {} + electron-to-chromium@1.5.302: {} emoji-regex@8.0.0: {} @@ -3477,13 +3489,13 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-plugin-react-hooks@5.2.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-react-hooks@5.2.0(eslint@9.39.3(jiti@2.6.1)): dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.3(jiti@2.6.1) - eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-react-refresh@0.4.26(eslint@9.39.3(jiti@2.6.1)): dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 9.39.3(jiti@2.6.1) eslint-scope@8.4.0: dependencies: @@ -3494,21 +3506,23 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.39.2(jiti@2.6.1): + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.3(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 '@eslint/eslintrc': 3.3.3 - '@eslint/js': 9.39.2 + '@eslint/js': 9.39.3 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 - ajv: 6.12.6 + ajv: 6.14.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 @@ -3527,7 +3541,7 @@ snapshots: is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 3.1.3 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -3537,8 +3551,8 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 esprima@4.0.1: {} @@ -3768,54 +3782,54 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-android-arm64@1.30.2: + lightningcss-android-arm64@1.31.1: optional: true - lightningcss-darwin-arm64@1.30.2: + lightningcss-darwin-arm64@1.31.1: optional: true - lightningcss-darwin-x64@1.30.2: + lightningcss-darwin-x64@1.31.1: optional: true - lightningcss-freebsd-x64@1.30.2: + lightningcss-freebsd-x64@1.31.1: optional: true - lightningcss-linux-arm-gnueabihf@1.30.2: + lightningcss-linux-arm-gnueabihf@1.31.1: optional: true - lightningcss-linux-arm64-gnu@1.30.2: + lightningcss-linux-arm64-gnu@1.31.1: optional: true - lightningcss-linux-arm64-musl@1.30.2: + lightningcss-linux-arm64-musl@1.31.1: optional: true - lightningcss-linux-x64-gnu@1.30.2: + lightningcss-linux-x64-gnu@1.31.1: optional: true - lightningcss-linux-x64-musl@1.30.2: + lightningcss-linux-x64-musl@1.31.1: optional: true - lightningcss-win32-arm64-msvc@1.30.2: + lightningcss-win32-arm64-msvc@1.31.1: optional: true - lightningcss-win32-x64-msvc@1.30.2: + lightningcss-win32-x64-msvc@1.31.1: optional: true - lightningcss@1.30.2: + lightningcss@1.31.1: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 + lightningcss-android-arm64: 1.31.1 + lightningcss-darwin-arm64: 1.31.1 + lightningcss-darwin-x64: 1.31.1 + lightningcss-freebsd-x64: 1.31.1 + lightningcss-linux-arm-gnueabihf: 1.31.1 + lightningcss-linux-arm64-gnu: 1.31.1 + lightningcss-linux-arm64-musl: 1.31.1 + lightningcss-linux-x64-gnu: 1.31.1 + lightningcss-linux-x64-musl: 1.31.1 + lightningcss-win32-arm64-msvc: 1.31.1 + lightningcss-win32-x64-msvc: 1.31.1 lines-and-columns@1.2.4: {} @@ -3870,13 +3884,13 @@ snapshots: dependencies: mime-db: 1.52.0 - minimatch@3.1.2: + minimatch@3.1.3: dependencies: brace-expansion: 1.1.12 - minimatch@9.0.5: + minimatch@9.0.6: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 5.0.3 minimist@1.2.8: {} @@ -4006,7 +4020,7 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 - react-hook-form@7.71.1(react@19.2.4): + react-hook-form@7.71.2(react@19.2.4): dependencies: react: 19.2.4 @@ -4040,35 +4054,35 @@ snapshots: reusify@1.1.0: {} - rollup@4.57.1: + rollup@4.59.0: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.57.1 - '@rollup/rollup-android-arm64': 4.57.1 - '@rollup/rollup-darwin-arm64': 4.57.1 - '@rollup/rollup-darwin-x64': 4.57.1 - '@rollup/rollup-freebsd-arm64': 4.57.1 - '@rollup/rollup-freebsd-x64': 4.57.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 - '@rollup/rollup-linux-arm-musleabihf': 4.57.1 - '@rollup/rollup-linux-arm64-gnu': 4.57.1 - '@rollup/rollup-linux-arm64-musl': 4.57.1 - '@rollup/rollup-linux-loong64-gnu': 4.57.1 - '@rollup/rollup-linux-loong64-musl': 4.57.1 - '@rollup/rollup-linux-ppc64-gnu': 4.57.1 - '@rollup/rollup-linux-ppc64-musl': 4.57.1 - '@rollup/rollup-linux-riscv64-gnu': 4.57.1 - '@rollup/rollup-linux-riscv64-musl': 4.57.1 - '@rollup/rollup-linux-s390x-gnu': 4.57.1 - '@rollup/rollup-linux-x64-gnu': 4.57.1 - '@rollup/rollup-linux-x64-musl': 4.57.1 - '@rollup/rollup-openbsd-x64': 4.57.1 - '@rollup/rollup-openharmony-arm64': 4.57.1 - '@rollup/rollup-win32-arm64-msvc': 4.57.1 - '@rollup/rollup-win32-ia32-msvc': 4.57.1 - '@rollup/rollup-win32-x64-gnu': 4.57.1 - '@rollup/rollup-win32-x64-msvc': 4.57.1 + '@rollup/rollup-android-arm-eabi': 4.59.0 + '@rollup/rollup-android-arm64': 4.59.0 + '@rollup/rollup-darwin-arm64': 4.59.0 + '@rollup/rollup-darwin-x64': 4.59.0 + '@rollup/rollup-freebsd-arm64': 4.59.0 + '@rollup/rollup-freebsd-x64': 4.59.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 + '@rollup/rollup-linux-arm-musleabihf': 4.59.0 + '@rollup/rollup-linux-arm64-gnu': 4.59.0 + '@rollup/rollup-linux-arm64-musl': 4.59.0 + '@rollup/rollup-linux-loong64-gnu': 4.59.0 + '@rollup/rollup-linux-loong64-musl': 4.59.0 + '@rollup/rollup-linux-ppc64-gnu': 4.59.0 + '@rollup/rollup-linux-ppc64-musl': 4.59.0 + '@rollup/rollup-linux-riscv64-gnu': 4.59.0 + '@rollup/rollup-linux-riscv64-musl': 4.59.0 + '@rollup/rollup-linux-s390x-gnu': 4.59.0 + '@rollup/rollup-linux-x64-gnu': 4.59.0 + '@rollup/rollup-linux-x64-musl': 4.59.0 + '@rollup/rollup-openbsd-x64': 4.59.0 + '@rollup/rollup-openharmony-arm64': 4.59.0 + '@rollup/rollup-win32-arm64-msvc': 4.59.0 + '@rollup/rollup-win32-ia32-msvc': 4.59.0 + '@rollup/rollup-win32-x64-gnu': 4.59.0 + '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 run-parallel@1.2.0: @@ -4148,15 +4162,15 @@ snapshots: svg-parser@2.0.4: {} - tailwind-merge@3.4.0: {} + tailwind-merge@3.5.0: {} - tailwind-variants@3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.18): + tailwind-variants@3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.0): dependencies: - tailwindcss: 4.1.18 + tailwindcss: 4.2.0 optionalDependencies: - tailwind-merge: 3.4.0 + tailwind-merge: 3.5.0 - tailwindcss@4.1.18: {} + tailwindcss@4.2.0: {} tapable@2.3.0: {} @@ -4191,13 +4205,13 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3): + typescript-eslint@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.55.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/parser': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) - '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.8.3) - '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.8.3) - eslint: 9.39.2(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.56.0(@typescript-eslint/parser@8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3) + '@typescript-eslint/parser': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.56.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.8.3) + eslint: 9.39.3(jiti@2.6.1) typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -4218,41 +4232,41 @@ snapshots: dependencies: punycode: 2.3.1 - vite-plugin-svgr@4.5.0(rollup@4.57.1)(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)): + vite-plugin-svgr@4.5.0(rollup@4.59.0)(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)): dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.57.1) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) '@svgr/core': 8.1.0(typescript@5.8.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.8.3)) - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)): + vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)): dependencies: debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.8.3) optionalDependencies: - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1) transitivePeerDependencies: - supports-color - typescript - vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2): + vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1): dependencies: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.57.1 + rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.10.13 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.30.2 + lightningcss: 1.31.1 which@2.0.2: dependencies: From 6ffba756a2753113537d2b39e1f5e88236a0718e Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 23 Feb 2026 19:42:21 +0900 Subject: [PATCH 85/91] =?UTF-8?q?#44=20fix:=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC=20=EA=B0=95=EC=A0=9C=20=ED=86=B5=EA=B3=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/unit-editor/ui/UnitForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/unit-editor/ui/UnitForm.tsx b/src/pages/unit-editor/ui/UnitForm.tsx index 66cbec5..d23d472 100644 --- a/src/pages/unit-editor/ui/UnitForm.tsx +++ b/src/pages/unit-editor/ui/UnitForm.tsx @@ -29,7 +29,7 @@ export const UnitForm = ({ reset, formState: {errors, isSubmitting}, } = useForm({ - resolver: zodResolver(unitFormSchema), + resolver: zodResolver(unitFormSchema) as any, values: mode === 'creating' ? { From b16c8d722e57da62e19ddce2c310333c2f6769c0 Mon Sep 17 00:00:00 2001 From: suminb99 Date: Mon, 23 Feb 2026 19:52:21 +0900 Subject: [PATCH 86/91] =?UTF-8?q?#44=20fix:=20zod=20=EB=B2=84=EC=A0=84=20d?= =?UTF-8?q?owngrade?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- pnpm-lock.yaml | 9 ++------- src/pages/unit-editor/ui/UnitForm.tsx | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 520d6f5..1125ed6 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "tailwind-merge": "^3.4.0", "tailwind-variants": "^3.2.2", "tailwindcss": "^4.1.11", - "zod": "^4.3.6", + "zod": "^3.22.0", "zustand": "^5.0.10" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4e2cd50..28d13cc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,8 +51,8 @@ importers: specifier: ^4.1.11 version: 4.2.0 zod: - specifier: ^4.3.6 - version: 4.3.6 + specifier: ^3.22.0 + version: 3.25.76 zustand: specifier: ^5.0.10 version: 5.0.11(@types/react@19.2.14)(immer@10.2.0)(react@19.2.4) @@ -2277,9 +2277,6 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.3.6: - resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} - zustand@5.0.11: resolution: {integrity: sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==} engines: {node: '>=12.20.0'} @@ -4304,8 +4301,6 @@ snapshots: zod@3.25.76: {} - zod@4.3.6: {} - zustand@5.0.11(@types/react@19.2.14)(immer@10.2.0)(react@19.2.4): optionalDependencies: '@types/react': 19.2.14 diff --git a/src/pages/unit-editor/ui/UnitForm.tsx b/src/pages/unit-editor/ui/UnitForm.tsx index d23d472..66cbec5 100644 --- a/src/pages/unit-editor/ui/UnitForm.tsx +++ b/src/pages/unit-editor/ui/UnitForm.tsx @@ -29,7 +29,7 @@ export const UnitForm = ({ reset, formState: {errors, isSubmitting}, } = useForm({ - resolver: zodResolver(unitFormSchema) as any, + resolver: zodResolver(unitFormSchema), values: mode === 'creating' ? { From e024658d313d99482a80fbaa6f2122c62d7022a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 26 Feb 2026 10:31:13 +0900 Subject: [PATCH 87/91] =?UTF-8?q?#55=20ci:=20Vercel=20=EB=B9=8C=EB=93=9C?= =?UTF-8?q?=20=EC=82=AC=EC=A0=84=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 93a0ed7..6e175e2 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -56,3 +56,10 @@ jobs: VITE_KAKAO_REST_API_KEY: ${{ secrets.VITE_KAKAO_REST_API_KEY }} VITE_KAKAO_REDIRECT_URI: ${{ secrets.VITE_KAKAO_REDIRECT_URI }} VITE_API_BASE_URL: ${{ secrets.VITE_API_BASE_URL }} + + - name: Simulate Vercel Build + run: npx vercel build --token=${{ secrets.VERCEL_TOKEN }} + env: + VITE_KAKAO_REST_API_KEY: ${{ secrets.VITE_KAKAO_REST_API_KEY }} + VITE_KAKAO_REDIRECT_URI: ${{ secrets.VITE_KAKAO_REDIRECT_URI }} + VITE_API_BASE_URL: ${{ secrets.VITE_API_BASE_URL }} From fc59a1e54f8e9a3e20bf88ce08cf1c6abdb6189a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 26 Feb 2026 10:52:10 +0900 Subject: [PATCH 88/91] =?UTF-8?q?#55=20ci:=20Vercel=20preview=20=EB=B9=8C?= =?UTF-8?q?=EB=93=9C=20=EC=82=AC=EC=A0=84=20=EA=B2=80=EC=A6=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 6e175e2..99253c5 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -57,6 +57,9 @@ jobs: VITE_KAKAO_REDIRECT_URI: ${{ secrets.VITE_KAKAO_REDIRECT_URI }} VITE_API_BASE_URL: ${{ secrets.VITE_API_BASE_URL }} + - name: Pull Vercel Environment + run: npx vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} + - name: Simulate Vercel Build run: npx vercel build --token=${{ secrets.VERCEL_TOKEN }} env: From 894991cbadab3ed14a1df9696c86a07c224f7828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 26 Feb 2026 11:11:05 +0900 Subject: [PATCH 89/91] =?UTF-8?q?#55=20ci:=20release=20=EB=B8=8C=EB=9E=9C?= =?UTF-8?q?=EC=B9=98=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20=EB=A6=B4?= =?UTF-8?q?=EB=A6=AC=EC=A6=88=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release-drafter.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 92a5687..544a172 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -5,9 +5,6 @@ on: branches: - release/* - main - # PR 이벤트 추가로 자동화 범위 확대 - pull_request: - types: [opened, reopened, synchronize] permissions: contents: write @@ -19,7 +16,7 @@ jobs: steps: # Checkout 단계 제거 (불필요한 작업 생략) - name: Update Draft Release - if: startsWith(github.ref, 'refs/heads/release/') || github.event_name == 'pull_request' + if: startsWith(github.ref, 'refs/heads/release/') uses: release-drafter/release-drafter@v6 with: config-name: template/release-drafter.yml From b79a11847cfa4aa2896cb40610fdbcb9840d9599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 26 Feb 2026 11:12:58 +0900 Subject: [PATCH 90/91] =?UTF-8?q?#55=20ci:=20release=20=EB=B8=8C=EB=9E=9C?= =?UTF-8?q?=EC=B9=98=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20=EB=A6=B4?= =?UTF-8?q?=EB=A6=AC=EC=A6=88=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release-drafter.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 92a5687..544a172 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -5,9 +5,6 @@ on: branches: - release/* - main - # PR 이벤트 추가로 자동화 범위 확대 - pull_request: - types: [opened, reopened, synchronize] permissions: contents: write @@ -19,7 +16,7 @@ jobs: steps: # Checkout 단계 제거 (불필요한 작업 생략) - name: Update Draft Release - if: startsWith(github.ref, 'refs/heads/release/') || github.event_name == 'pull_request' + if: startsWith(github.ref, 'refs/heads/release/') uses: release-drafter/release-drafter@v6 with: config-name: template/release-drafter.yml From 8ac27274c0a49ce64d7d4c77b10365b7a50be39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=98=EC=A7=80=EB=AF=BC?= <163178666+JiiminHa@users.noreply.github.com> Date: Thu, 26 Feb 2026 11:18:49 +0900 Subject: [PATCH 91/91] =?UTF-8?q?Revert=20"#55=20ci:=20release=20=EB=B8=8C?= =?UTF-8?q?=EB=9E=9C=EC=B9=98=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=A6=B4=EB=A6=AC=EC=A6=88=20=EC=83=9D=EC=84=B1=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 894991cbadab3ed14a1df9696c86a07c224f7828. --- .github/workflows/release-drafter.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 544a172..92a5687 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -5,6 +5,9 @@ on: branches: - release/* - main + # PR 이벤트 추가로 자동화 범위 확대 + pull_request: + types: [opened, reopened, synchronize] permissions: contents: write @@ -16,7 +19,7 @@ jobs: steps: # Checkout 단계 제거 (불필요한 작업 생략) - name: Update Draft Release - if: startsWith(github.ref, 'refs/heads/release/') + if: startsWith(github.ref, 'refs/heads/release/') || github.event_name == 'pull_request' uses: release-drafter/release-drafter@v6 with: config-name: template/release-drafter.yml