diff --git a/docs/Project SS 서사형 덱빌딩 게임 시스템 기획서.md b/docs/Project SS 서사형 덱빌딩 게임 시스템 기획서.md new file mode 100644 index 0000000..4e9ebc8 --- /dev/null +++ b/docs/Project SS 서사형 덱빌딩 게임 시스템 기획서.md @@ -0,0 +1,156 @@ + +- 개요 + - 서사형 덱빌딩 게임 + - 출시: 모바일&스팀 +- 코어 루프 + - 시스템 요약: 로그라이크 루프 + 1. **시작:** 무작위 사건(내러티브)과 무작위 지부장이 배치된 채 국장 취임. + 2. **결재 (덱 빌딩):** 스와이프를 통해 토큰을 관리하며, 덱에 [오염 카드]를 밀어 넣거나 [자산 카드]를 챙김. + 3. **위기 (드로우):** 내가 넣은 오염 카드가 튀어나와 목을 조를 때, 어떻게든 [자원 태그] 엔진과 남은 토큰으로 방어. + 4. **엔딩 (결과):** 덱의 상태, 파벌 우호도, 붕괴 게이지의 조합에 따라 수십 가지의 파생 엔딩 중 하나를 수집하고 다음 회차로 루프. +- 시스템 (플레이어 행동 중심 시스템 정리) + - 게임 목표: 모든 엔딩 보기 + - 기본 붕괴 엔딩 + - 사임 (내부 붕괴): [내부 저항] 5단계 도달 시. (수많은 딜레마에서 조직원들을 갈아 넣고 장악력을 잃은 결과) + - 세계 멸망 (외부 붕괴): [엔트로피] 5단계 도달 시. (내러티브 태그 방치 및 오염 카드에서 세상의 타락을 방관한 결과) + - 정치적 탄핵 (윗선 붕괴): 주간 의회 단계에서 적대적 파벌 임원이 2/3(9명 이상)를 넘어 탄핵안이 상정되었으나, 방어 자원(정치적 개입)이 없어 가결될 시. + - 변주된 붕괴 엔딩 + - 기본 붕괴 엔딩 + 특정 자원 태그 + - 기본 붕괴 엔딩 + 특정 토큰 + - 극단적 파라미터 엔딩 + - 특정 파라미터를 극단적으로 비정상적인 상태로 만들었을 때 즉시 발동하는 강제 종료 엔딩 (조기 엔딩) + - 내러티브 연쇄 엔딩 + - 특정 내러티브 엔딩을 순서대로 수집 + - 의회 정치 엔딩 (의회의 수장이 원하는 바를 이룸) + - 탄핵 + 의회의 수장이 보유한 성향에 맞는 조건 달성 + - 자원 + - 토큰: 소모성 자원 + - 예산 토큰 + - 인력 토큰 + - 정보 토큰 + - 자원 태그: 누적 자원, 영구적인 1코스트 할인 효과 + - 재력/자본 태그: 건물 아이콘 + - 무력/조직 태그: 방패 아이콘 + - 감시/언론 태그: 눈동자 아이콘 + - 핵심 속성 파라미터 (명확한 수치화) + - [내부 저항 (Internal Resistance)]: (0~100%) 국장에 대한 조직 내부의 반발력. + - 1단계: ~20% + - 2단계: ~40% + - 3단계: ~60% + - 4단계: ~80% + - 5단계: ~100% + - [엔트로피 (Entropy)]: (0~100%) 세계가 미쳐가는 종말 카운트다운. + - 1단계: ~20% + - 2단계: ~40% + - 3단계: ~60% + - 4단계: ~80% + - 5단계: ~100% + - [위험 수용 계수 (Risk Tolerance)]: (0~100%) 위원회가 국장의 행보를 보고 느끼는 위기감의 척도. (높을수록 위원회가 보수적/강압적으로 변함) + - 1단계: ~20% + - 2단계: ~40% + - 3단계: ~60% + - 4단계: ~80% + - 5단계: ~100% + - [내러티브 태그]: 결재로 얻는 세계의 훼손 상태 (스택형). + - [성향 태그]: 결재로 얻는 국장의 통치 사상 (스택형). + - [임원 우호도]: 13명의 위원이 국장에게 가지는 개별 호감도 (-100 ~ +100). + - 결재 단계: 스와이프 결정 + - 딜레마 선택 + - 일상 딜레마: 어떤 토큰과 어떤 오염 카드를 선택할 것인가? + - 좌: 토큰 획득 + 덱오염 + - 우: 토큰 획득 + 덱오염 + - 위기 딜레마: 덱오염의 대가로 토큰을 얻을 것인가? 토큰을 쓰고 위기를 넘길것인가? + - 좌: 토큰 획득 + 덱오염 + - 우: 토큰 소모 + - 작전: 무료 획득이지만 덱오염을 감수할 것인가? 토큰을 쓰고 더 많은 자원 태그를 얻을 것인가? + - 좌: 자원 태그 획득 + 덱오염 + - 우: 토큰 소모 + 더 많은 자원 태그 획득 + - 극비 프로젝트: 토큰을 소모해 어떤 보상 (자원 태그 or 자산)을 받을 것인가? + - 좌: 토큰 소모 + '자원 태그 획득 or 자산 획득' + - 우: 토큰 소모 + '자원 태그 획득 or 자산 획득' + - 위로: 버리기 + - 위기 강타(오염 카드 - 신화, 조직저항, 이사회의 압박) + - 좌: 토큰 차감 or 자원 태그 차감 + - 우: 위험 단계 (엔트로피, 내부 저항, 위험 수용 계수) 상승 + - 뉴스 이벤트 + - 좌: 보유 '자산' 중 1개 제거 + - 우: 위험 단계 (엔트로피, 내부 저항, 위험 수용 계수) 상승 + - 공통 획득 + - 내러티브 태그: 스토리 전달 + 자원 태그 스택 + - 연대기 시스템 (Chronicle) + - 누적된 내러티브 태그를 터치하면, 플레이어가 지금까지 세상을 어떻게 망치고 구해왔는지 연대기 형태의 히스토리/텍스트로 확인 가능. (플레이어의 목적의식과 내러티브 몰입도 강화) + - 성향 태그: 파벌과의 우호도 변화 + - 덱 오염 (토큰을 마이너스) + - 엔트로피 1~5단계: 신화 카드 추가 + - 적색 보고서: 뉴스 이벤트 + - 내부 저항 1~5단계: 조직 저항 카드 추가 + - 위험 수용 계수 1~5단계: 이사회의 압박 카드 추가 + - 덱압축: 오염카드 제거 + - 자산 + - 성질 변환 (Transformation): 독을 약으로 바꾸기 + - 오염카드를 영구 변환 + - 시한부 격리 (Quarantine): 하이 리스크 하이 리턴 압축 + - 여러장의 카드를 격리하지만 조건에 따라 덱으로 복귀 + - 물리적 영구 소각 (Purge): 정통 덱 압축 + - 조건 없이 깔끔하게 덱의 불순물을 제거하는 가장 기본적이고 강력한 수단 + - 결재권 강제 행사 (Mulligan / Skip): 회피 기동 + - 덱에서 카드가 사라지지는 않지만, 뽑혔을 때 뼈아픈 페널티를 무효화하는 패시브 방어막 + - 자산 슬롯 (무제한 인벤토리) + - 파이프라인 연쇄 반응 + - 연쇄 노드를 구축하면 오염카드 자동처리 + - 입력 + - 변환 + - 출력 + - 주간 의회 단계: 의회의 압박 + - '그림자 위원회' 임원 구성 (총 13명): + - 상임 이사회 (8명): 고정된 이념을 가짐. 국장의 '성향 태그'에 직접적으로 우호도가 변함. + - 글로벌 지부장 (5명): 수많은 현장 책임자 중 5명만 선발되어 합류(게임을 시작할때마다 변경). 이념보다 실리(자원 태그, 자산, 특정 내러티브 태그)에 따라 우호도가 변동함. + - 법안 상정 및 투표 + - 법안 상정 + - 동맹: 이득 규약 법안 상정 (자원 태그 플러스) + - 파국: 표적 규약 법안 상정 (자원 태그 마이너스) + - 예상 표결 + - 동맹: 이득 규약에 투표 - 국장의 개입 불가 + - 우호: 이득 규약에 투표 + - 중립: 알 수 없음 + - 적대: 표적 규약에 투표 + - 파국: 표적 규약에 투표 - 국장의 개입 불가 + - 국장의 개입 + - 매수 액션: + - 소모 비용: [예산 토큰] 대량 소모 (또는 재력 자원 태그 스택 희생) + - ​개입 효과: '중립' 또는 '적대' 성향의 임원 1~2명을 이번 투표에 한하여 '동맹(찬성)'으로 강제 전환합니다. + - ​치명적 리스크: 돈으로 입을 막은 대가로 이사회 내부에 국장의 부패 스캔들이 돌기 시작하며 [위험 수용 계수]가 즉시 1단계(20%) 상승합니다. + - 장부 조작 액션: + - 소모 비용: [정보 토큰] 대량 소모 (또는 감시 자원 태그 스택 희생) + - ​개입 효과: 발의된 법안의 핵심 근거 서류를 위조하여 법안 상정 자체를 무효화하고 다음 주 의회로 이월(Delay)시킵니다. 시간을 벌 수 있는 유일한 수단입니다. + - ​치명적 리스크: 은폐해야 할 외부의 미스터리 관련 기밀 정보를 정치판에 흘린 대가로 [엔트로피]가 즉시 1단계(20%) 상승합니다. + - 내부 감사 액션: + - 소모 비용: [인력 토큰] 대량 소모 (또는 무력 자원 태그 스택 희생) + - ​개입 효과: 가장 강력한 '적대/파국' 임원의 비리를 무력으로 털어, 해당 임원과 그 측근들을 이번 의회에서 '기권(투표권 박탈)' 처리합니다. 탄핵 정족수를 무너뜨릴 때 유용합니다. + - ​치명적 리스크: 요원들을 사적인 정치 싸움에 갈아 넣은 결과로 현장의 불만이 폭발하여 [내부 저항]이 즉시 1단계(20%) 상승합니다. + - 투표 결과 및 법안 통과: 국장의 개입이 반영된 투표 결과 출력 및 법안 통과 + - 탄핵 투표 + - 예상 표결: + - 동맹: 탄핵 반대 - 국장의 개입 불가 + - 우호: 탄핵 반대 + - 중립: 알 수 없음 + - 적대: 탄핵 찬성 + - 파국: 탄핵 찬성 - 국장의 개입 불가 + - 국장의 개입: 매수 액션, 장부 조작 액션, 내부 감사 액션 + - 투표 결과 및 탄핵 심판: 국장의 개입이 반영된 투표 결과 출력 및 탄핵 결과 적용 + - 토큰 경제 (내러티브 태그 누적치에 따라 페이즈 전환) + - 페이즈1: 기본 루프 (어떤 독을 마실 것인가) + - 토큰과 오염 카드 선택 + - 주요 등장 딜레마: 일상 딜레마 + 위기 딜레마 + - 페이즈2: 기회 루프 (드디어 턴이 왔다) + - 토큰 소비와 스택 보상 선택(오염 카드 해결 + 자산, 자원 태그 빌드업) + - 주요 등장 딜레마: 작전 + 극비 프로젝트 + 오염 카드 + - 페이즈3: 압박 루프 (쌓아둔 모래성 무너뜨리기) + - 엔트로피, 내부 저항, 위험 수용 계수는 거의 게임오버 한계에 도달 + - 오염 카드, 뉴스 속보, 표적 규약이 극에 달하는 시기로 토큰이 항상 부족 + - 주요 등장 딜레마: 작전 + 극비 프로젝트 + 오염 카드 + - 스토리 기반 페이징 + - **작동 방식:** 플레이어가 획득한 [내러티브 태그]의 총개수에 따라 파트가 넘어갑니다. + - 태그 0~3개: 페이즈1 (사태 파악 및 은폐의 시작) + - 태그 4~7개: 페이즈2 (프로젝트 가동 및 이사회의 개입 본격화) + - 태그 8개 이상: 페이즈3 (통제 불능의 사태 및 종말의 카운트다운) diff --git a/docs/architecture_design.md b/docs/architecture_design.md new file mode 100644 index 0000000..d31f2f9 --- /dev/null +++ b/docs/architecture_design.md @@ -0,0 +1,105 @@ +# Project SS - 파일 및 컴포넌트 구조 설계 + +본 문서는 **"서사형 덱빌딩 게임 시스템 기획서"** 및 **"스토리 바이블"**을 바탕으로, 기존 단일 HTML 파일을 모던 웹 프레임워크(React + Vite + Tailwind CSS + Zustand) 기반으로 마이그레이션 및 고도화하기 위한 디렉토리 및 컴포넌트 구조를 정의합니다. + +## 📂 1. 전체 디렉토리 구조 (Directory Structure) + +```text +/src + ├── assets/ # 이미지, 폰트, 아이콘 등 정적 파일 + ├── components/ # UI 및 도메인 컴포넌트 + │ ├── common/ # 공통 UI 요소 (버튼, 모달, 툴팁 등) + │ ├── dashboard/ # 상단 상태창 및 파라미터 표시 + │ ├── gameplay/ # 핵심 게임 루프 (카드 스와이프, 자산 관리) + │ └── council/ # 주간 의회 시스템 (투표, 법안, 파벌) + ├── constants/ # 게임 내 상수 (파벌 정보, 테마 컬러, 엔딩 조건 등) + ├── data/ # 초기 데이터 및 시나리오 (CSV/JSON 형식) + ├── hooks/ # 커스텀 훅 (ex. useSwipe, useVoting) + ├── store/ # 전역 상태 관리 (Zustand) + ├── types/ # TypeScript 타입 정의 (Card, Faction, State 등) + ├── utils/ # 헬퍼 함수 (엔트로피 계산, 전투/결과 연산 등) + ├── App.tsx # 루트 컴포넌트 (페이지 라우팅 및 전역 상태 주입) + └── main.tsx # 진입점 +``` + +--- + +## 🧩 2. 상세 컴포넌트 구조 (Components Breakdown) + +### 2.1 공통 UI (`/components/common`) +프리미엄한 관료주의 다크/레트로 UI를 구성하는 기본 요소들입니다. +- `Button.tsx`: 액션 버튼 (결재, 서명 등 텍스처 효과 포함) +- `Modal.tsx`: 미스터리 보드, 법안 확인 등을 위한 공통 팝업 +- `ProgressBar.tsx`: 게이지 바 (엔트로피, 내부 저항 등) +- `AlertToast.tsx`: 패시브 효과 연쇄나 비상 사태를 알리는 시스템 메시지 (우측 하단/상단 노출) + +### 2.2 대시보드 (`/components/dashboard`) +플레이어의 현재 상태(국장실 요약)를 보여줍니다. +- `StatusHeader.tsx`: 현재 주차(Week), 일차(Day), 주간 아젠다 노출 +- `ParameterBoard.tsx`: 3대 핵심 파라미터 게이지 (내부 저항, 엔트로피, 위험 수용 계수) +- `ResourcePanel.tsx`: 3대 토큰(예산, 인력, 정보) 및 자원 태그(재력, 무력, 감시) 현황 +- `FactionDonut.tsx`: 8대 파벌의 의회 지분율 및 우호도를 시각화하는 도넛 차트 + +### 2.3 게임플레이 (`/components/gameplay`) +일일 업무(결재 단계)를 처리하는 핵심 루프 컴포넌트입니다. +- `DeskView.tsx`: 국장실 책상 배경 및 전체 레이아웃 래퍼 +- `CardSwiper.tsx`: 틴더 스타일의 스와이프 인터페이스 (Tinder-like Swipe) + - 좌/우 스와이프에 따른 예측 결과(예상 토큰/파라미터 증감)를 오버레이로 표시 +- `DilemmaCard.tsx`: 개별 딜레마/위기 서류. (제목, 내용, 플레이버 텍스트, 결재/반려 스탬프 이펙트) +- `AssetManager.tsx`: 보유 중인 자산(파이프라인, 성질 변환 등 덱 압축 장치) 관리 모달 + +### 2.4 의회 시스템 (`/components/council`) +매주 5일차 종료 후 진행되는 정치 시스템 컴포넌트입니다. +- `CouncilPhase.tsx`: 주간 의회 화면 메인 컨테이너 +- `BillDisplay.tsx`: 상정된 법안(이득 규약 vs 표적 규약) 비교 UI +- `VotingBoard.tsx`: 13명의 임원(상임 이사 8명 + 글로벌 지부장 5명)의 예상 투표 현황 및 게이지 바 +- `InterventionPanel.tsx`: 국장의 개입 액션 (매수, 장부 조작, 내부 감사) 버튼 및 리스크 안내 패널 + +### 2.5 뷰 / 씬 (Views/Scenes) +- `LoadingScreen.tsx`: 초기 데이터 파싱 및 게임 세팅 화면 +- `GameScreen.tsx`: 인게임 전체 메인 화면 (대시보드 + 게임플레이 결합) +- `EndingScreen.tsx`: 멀티 엔딩 매트릭스에 따른 최종 결과 출력 (위대한 침묵, 신인류의 탄생 등) + +--- + +## 💾 3. 전역 상태 구조 (Global State - Zustand 제안) + +관리가 복잡한 게임 데이터를 효율적으로 다루기 위해 상태를 나눕니다. + +```typescript +interface GameState { + // 시간/페이즈 관리 + week: number; + day: number; + phase: 'DAY_WORK' | 'COUNCIL' | 'ENDING'; + + // 핵심 파라미터 + entropy: number; // 0~100% + internalResistance: number; // 0~100% + riskTolerance: number; // 0~100% + + // 자원 + tokens: { budget: number; personnel: number; info: number; }; + tags: { finance: number; force: number; surveillance: number; }; + + // 덱 및 내러티브 + narrativeTags: string[]; + ideologyTags: string[]; + deck: Card[]; // 섞인 오염카드 및 이벤트 풀 + assets: Asset[]; // 덱 압축 파이프라인 + + // 파벌 및 의회 (13명의 임원 정보 포함) + factions: FactionState[]; + currentBills: Bill[]; +} +``` + +--- + +## 🚀 4. 추천 기술 스택 +- **Framework**: `React` (컴포넌트 분리를 통한 복잡한 UI 관리) +- **Build Tool**: `Vite` (빠른 HMR 및 빌드 속도) +- **Styling**: `Tailwind CSS` (유틸리티 클래스로 빠른 UI 구현) + CSS Animations (스와이프 액션, 팝업 등) +- **State Management**: `Zustand` (가볍고 직관적인 전역 상태 관리) +- **Interactions**: `Framer Motion` 또는 `react-spring` (부드러운 카드 스와이프 액션 및 몰입감 있는 애니메이션) +- **Type Checking**: `TypeScript` (복잡한 자원 계산과 이벤트 분기에 대한 안정성 보장) diff --git a/index.html b/index.html new file mode 100644 index 0000000..26b8e14 --- /dev/null +++ b/index.html @@ -0,0 +1,15 @@ + + + + + + + Project SS - Live DB Edition + + + + +
+ + + diff --git a/package-lock.json b/package-lock.json index 5754c72..324184a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,44 @@ "name": "project-ss", "version": "1.0.0", "license": "ISC", + "dependencies": { + "clsx": "^2.1.1", + "framer-motion": "^12.40.0", + "lucide-react": "^1.17.0", + "papaparse": "^5.5.3", + "react": "^19.2.7", + "react-dom": "^19.2.7", + "tailwind-merge": "^3.6.0", + "zustand": "^5.0.14" + }, "devDependencies": { + "@tailwindcss/postcss": "^4.3.0", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^25.9.2", + "@types/papaparse": "^5.5.2", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.2", + "autoprefixer": "^10.5.0", "electron": "^41.1.1", - "electron-builder": "^26.8.1" + "electron-builder": "^26.8.1", + "postcss": "^8.5.15", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.16" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@develar/schema-utils": { @@ -480,6 +515,40 @@ "node": ">= 10.0.0" } }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -596,6 +665,56 @@ "node": ">=18.0.0" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@malept/cross-spawn-promise": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", @@ -674,6 +793,25 @@ "node": ">= 10.0.0" } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, "node_modules/@npmcli/agent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", @@ -724,6 +862,16 @@ "node": ">=10" } }, + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -735,6 +883,288 @@ "node": ">=14" } }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", @@ -761,6 +1191,315 @@ "node": ">=10" } }, + "node_modules/@tailwindcss/node": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", + "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.21.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz", + "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-x64": "4.3.0", + "@tailwindcss/oxide-freebsd-x64": "4.3.0", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-x64-musl": "4.3.0", + "@tailwindcss/oxide-wasm32-wasi": "4.3.0", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz", + "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz", + "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz", + "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz", + "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz", + "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz", + "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz", + "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz", + "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz", + "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz", + "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", + "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz", + "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.0.tgz", + "integrity": "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.0", + "@tailwindcss/oxide": "4.3.0", + "postcss": "^8.5.10", + "tailwindcss": "4.3.0" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.0.tgz", + "integrity": "sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.3.0", + "@tailwindcss/oxide": "4.3.0", + "tailwindcss": "4.3.0" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -819,13 +1558,23 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.2.tgz", - "integrity": "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==", + "version": "25.9.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.2.tgz", + "integrity": "sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.16.0" + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/papaparse": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.5.2.tgz", + "integrity": "sha512-gFnFp/JMzLHCwRf7tQHrNnfhN4eYBVYYI897CGX4MY1tzY9l2aLkVyx2IlKZ/SAqDbB3I1AOZW5gTMGGsqWliA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" } }, "node_modules/@types/plist": { @@ -840,6 +1589,26 @@ "xmlbuilder": ">=11.0.1" } }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, "node_modules/@types/responselike": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", @@ -869,6 +1638,32 @@ "@types/node": "*" } }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", + "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, "node_modules/@xmldom/xmldom": { "version": "0.8.12", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.12.tgz", @@ -1195,6 +1990,43 @@ "node": ">= 4.0.0" } }, + "node_modules/autoprefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -1226,6 +2058,19 @@ ], "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.34", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.34.tgz", + "integrity": "sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -1260,6 +2105,40 @@ "node": "18 || 20 || >=22" } }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -1508,6 +2387,27 @@ "node": ">= 0.4" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001797", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz", + "integrity": "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1640,6 +2540,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1766,6 +2675,13 @@ "node": ">= 8" } }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -2244,6 +3160,13 @@ "node": ">= 10.0.0" } }, + "node_modules/electron-to-chromium": { + "version": "1.5.370", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.370.tgz", + "integrity": "sha512-D5tSHJReAb/Kf3Hu9F/GO4lJuSWzEWHwvQ/kKSUP7pimNgvxkSKj+gUQhHpKKACwrin7rS3byU7IxreF56rl5g==", + "dev": true, + "license": "ISC" + }, "node_modules/electron-winstaller": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", @@ -2282,6 +3205,23 @@ "node": ">=6 <7 || >=8" } }, + "node_modules/electron/node_modules/@types/node": { + "version": "24.13.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.1.tgz", + "integrity": "sha512-RSpUJGmvsJ1ZeBehQZFhIdpsz+bIpES0nIQXko4Ybq+N+kX6XvOq3Jo+iJ82FWLdblFq85AsMikd3m35jgezYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/electron/node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -2310,6 +3250,20 @@ "once": "^1.4.0" } }, + "node_modules/enhanced-resolve": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.23.0.tgz", + "integrity": "sha512-yJN/BOOLxcOW2aQgeif9mSnaUB8KtvmMMp56oA1kx1CRfBKbhZm2pJ+NBY+3eOboHxix8lfjWpHE0Ei5U8RbSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -2576,6 +3530,47 @@ "node": ">= 6" } }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "12.40.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.40.0.tgz", + "integrity": "sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.40.0", + "motion-utils": "^12.39.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -2611,6 +3606,21 @@ "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -3230,6 +4240,279 @@ "dev": true, "license": "MIT" }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lodash": { "version": "4.18.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", @@ -3277,6 +4560,25 @@ "node": ">=10" } }, + "node_modules/lucide-react": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.17.0.tgz", + "integrity": "sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/make-fetch-happen": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", @@ -3552,6 +4854,21 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/motion-dom": { + "version": "12.40.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.40.0.tgz", + "integrity": "sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3559,6 +4876,25 @@ "dev": true, "license": "MIT" }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -3664,6 +5000,16 @@ "node": ">=10" } }, + "node_modules/node-releases": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/nopt": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", @@ -3800,6 +5146,12 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/papaparse": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.3.tgz", + "integrity": "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==", + "license": "MIT" + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -3901,6 +5253,42 @@ "node": ">=10.4.0" } }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, "node_modules/postject": { "version": "1.0.0-alpha.6", "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", @@ -4011,6 +5399,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.7" + } + }, "node_modules/read-binary-file-arch": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", @@ -4145,6 +5554,40 @@ "node": ">=8.0" } }, + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4193,6 +5636,12 @@ "node": ">=11.0.0" } }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -4351,6 +5800,16 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -4487,6 +5946,37 @@ "node": ">=8" } }, + "node_modules/tailwind-merge": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", + "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz", + "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/tar": { "version": "7.5.13", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", @@ -4599,14 +6089,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -4645,6 +6135,12 @@ "utf8-byte-length": "^1.0.1" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", @@ -4659,10 +6155,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "dev": true, "license": "MIT" }, @@ -4702,6 +6212,37 @@ "node": ">= 4.0.0" } }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -4742,6 +6283,84 @@ "node": ">=0.6.0" } }, + "node_modules/vite": { + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -4891,6 +6510,35 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "5.0.14", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.14.tgz", + "integrity": "sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index 214dc1e..f9bbf23 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,9 @@ "description": "Project SS - Steam App", "main": "main.js", "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", "start": "electron .", "build:win": "electron-builder --win --x64" }, @@ -31,7 +34,29 @@ "author": "", "license": "ISC", "devDependencies": { + "@tailwindcss/postcss": "^4.3.0", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^25.9.2", + "@types/papaparse": "^5.5.2", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.2", + "autoprefixer": "^10.5.0", "electron": "^41.1.1", - "electron-builder": "^26.8.1" + "electron-builder": "^26.8.1", + "postcss": "^8.5.15", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.16" + }, + "dependencies": { + "clsx": "^2.1.1", + "framer-motion": "^12.40.0", + "lucide-react": "^1.17.0", + "papaparse": "^5.5.3", + "react": "^19.2.7", + "react-dom": "^19.2.7", + "tailwind-merge": "^3.6.0", + "zustand": "^5.0.14" } } diff --git a/src/data/agendas.csv b/public/data/agendas.csv similarity index 100% rename from src/data/agendas.csv rename to public/data/agendas.csv diff --git a/src/data/assets.csv b/public/data/assets.csv similarity index 100% rename from src/data/assets.csv rename to public/data/assets.csv diff --git a/src/data/bills.csv b/public/data/bills.csv similarity index 100% rename from src/data/bills.csv rename to public/data/bills.csv diff --git a/src/data/factions.csv b/public/data/factions.csv similarity index 100% rename from src/data/factions.csv rename to public/data/factions.csv diff --git a/src/data/mysteries.csv b/public/data/mysteries.csv similarity index 100% rename from src/data/mysteries.csv rename to public/data/mysteries.csv diff --git a/src/data/quests.csv b/public/data/quests.csv similarity index 100% rename from src/data/quests.csv rename to public/data/quests.csv diff --git a/src/data/scenarios.csv b/public/data/scenarios.csv similarity index 100% rename from src/data/scenarios.csv rename to public/data/scenarios.csv diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..8a556a5 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,58 @@ +import React, { useEffect } from 'react'; +import { initDatabase } from './utils/dataLoader'; +import { useGameStore } from './store/gameState'; +import { Dashboard } from './components/dashboard/Dashboard'; +import { CardView } from './components/gameplay/CardView'; + +function App() { + const { isLoaded, initGame, phase, nextDay } = useGameStore(); + + useEffect(() => { + async function loadData() { + const db = await initDatabase(); + initGame(db); + nextDay(); + } + loadData(); + }, []); + + if (!isLoaded) { + return ( +
+ Loading Data... +
+ ); + } + + return ( +
+ {/* Mobile/Steam Container Setup */} +
+ + + {phase === 'DAY_WORK' && } + + {phase === 'COUNCIL' && ( +
+

Council Phase

+ +
+ )} + + {phase === 'ENDING' && ( +
+

GAME OVER

+

Entropy reached 100%.

+ +
+ )} +
+
+ ); +} + +export default App; diff --git a/src/components/dashboard/Dashboard.tsx b/src/components/dashboard/Dashboard.tsx new file mode 100644 index 0000000..99b5653 --- /dev/null +++ b/src/components/dashboard/Dashboard.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { useGameStore } from '../../store/gameState'; + +export const Dashboard: React.FC = () => { + const { week, day, anomaly, political, trust, entropy } = useGameStore(); + + return ( +
+
+ Week {week} + Day {day} / 5 +
+ +
+
+ Data (Anomaly) + {anomaly} +
+
+ Pol. Capital + {political} +
+
+ +
+
+ Trust + {trust}% +
+
+
+
+ +
+ Entropy + {entropy}% +
+
+
+
+
+
+ ); +}; diff --git a/src/components/gameplay/CardView.tsx b/src/components/gameplay/CardView.tsx new file mode 100644 index 0000000..e9d665d --- /dev/null +++ b/src/components/gameplay/CardView.tsx @@ -0,0 +1,100 @@ +import React, { useState } from 'react'; +import { useGameStore } from '../../store/gameState'; + +export const CardView: React.FC = () => { + const { currentCard, addStat, nextDay, phase } = useGameStore(); + const [hoverDirection, setHoverDirection] = useState<'left' | 'right' | null>(null); + + if (phase !== 'DAY_WORK' || !currentCard) { + return
No active card.
; + } + + const handleDecision = (direction: 'left' | 'right') => { + // Process the decision + if (direction === 'left') { + addStat('anomaly', currentCard.yes_a); + addStat('entropy', currentCard.yes_e); + // TODO: Add narrative tags or specific costs based on 'yes' logic + } else { + addStat('political', currentCard.no_p); + addStat('entropy', currentCard.no_e); + // TODO: Add costs for 'no' logic + } + + // Proceed to next day + nextDay(); + setHoverDirection(null); + }; + + return ( +
+ {/* Grey-box Card container */} +
+
+ {currentCard.dept || 'Department'} + {currentCard.faction || 'Neutral'} +
+ +
+

{currentCard.title || 'Untitled'}

+
+ {currentCard.tags?.map((t, idx) => ( + {t} + ))} +
+
+ +
+ {currentCard.body || 'No content.'} +
+ +
+ "{currentCard.flavor || 'No flavor text'}" +
+
+ + {/* Decision Buttons (Grey-box alternative to swiping) */} +
+ + +
+ + {/* Prediction Overlay for Greybox Testing */} + {hoverDirection && ( +
+
+ Expected Result: {hoverDirection === 'left' ? 'Approve' : 'Reject'} +
+
+ Data (Anomaly): + 0 ? 'text-green-400' : hoverDirection === 'right' && 0 > 0 ? 'text-green-400' : ''}> + {hoverDirection === 'left' ? (currentCard.yes_a > 0 ? `+${currentCard.yes_a}` : currentCard.yes_a) : '0'} + +
+
+ Political Capital: + {hoverDirection === 'right' ? (currentCard.no_p > 0 ? `+${currentCard.no_p}` : currentCard.no_p) : '0'} +
+
+ Entropy: + {hoverDirection === 'left' ? (currentCard.yes_e > 0 ? `+${currentCard.yes_e}` : currentCard.yes_e) : (currentCard.no_e > 0 ? `+${currentCard.no_e}` : currentCard.no_e)} +
+
+ )} +
+ ); +}; diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..3741b93 --- /dev/null +++ b/src/index.css @@ -0,0 +1,31 @@ +@import "tailwindcss"; + +@theme { + --color-bgDark: #1a1a1a; + --color-paper: #e6dec5; + --color-ink: #2b2b2b; + --color-redSeal: #c92a2a; + --color-blueSeal: #1c4f82; + --color-uiBorder: #444; + --font-courier: "Courier Prime", monospace; + --font-nanum: "Nanum Myeongjo", serif; + --font-blackhan: "Black Han Sans", sans-serif; +} + +@layer base { + :root { + --safe-top: env(safe-area-inset-top, 30px); + } + + body { + @apply m-0 p-0 overflow-hidden select-none touch-none; + } +} + +@layer utilities { + .desk-bg { + background: #2d1b14; + background-image: repeating-linear-gradient(45deg, #281812 25%, transparent 25%, transparent 75%, #281812 75%, #281812); + background-size: 20px 20px; + } +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..3d7150d --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' +import './index.css' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/src/store/gameState.ts b/src/store/gameState.ts new file mode 100644 index 0000000..3516f90 --- /dev/null +++ b/src/store/gameState.ts @@ -0,0 +1,139 @@ +import { create } from 'zustand'; +import { Database, CardData, Agenda, Quest, Asset, Mystery, Faction, Bill } from '../types'; + +interface GameState { + isLoaded: boolean; + db: Database | null; + + week: number; + day: number; + phase: 'DAY_WORK' | 'COUNCIL' | 'ENDING'; + + // 파라미터 (0 ~ 100) + anomaly: number; // 데이터 + political: number; // 정치 자본 + trust: number; // 신임도 + entropy: number; // 종말 시계 + + // 상태 + assets: Asset[]; + builtTags: Record; + activeLaws: Bill[]; + activeMysteries: Mystery[]; + + currentAgenda: Agenda | null; + currentQuest: Quest | null; + questProgress: number; + + currentCard: CardData | null; + lockState: 'none' | 'approve' | 'reject'; + + council: { + billA: Bill | null; + billB: Bill | null; + votesA: number; + votesB: number; + supportersA: Faction[]; + supportersB: Faction[]; + }; + + // Actions + initGame: (db: Database) => void; + nextDay: () => void; + processSwipe: (direction: 'left' | 'right') => void; + addStat: (key: 'anomaly' | 'political' | 'trust' | 'entropy', val: number) => void; +} + +export const useGameStore = create((set, get) => ({ + isLoaded: false, + db: null, + + week: 1, + day: 1, + phase: 'DAY_WORK', + + anomaly: 20, + political: 20, + trust: 80, + entropy: 10, + + assets: [], + builtTags: {}, + activeLaws: [], + activeMysteries: [], + + currentAgenda: null, + currentQuest: null, + questProgress: 0, + + currentCard: null, + lockState: 'none', + + council: { + billA: null, + billB: null, + votesA: 50, + votesB: 50, + supportersA: [], + supportersB: [] + }, + + initGame: (db) => set({ + isLoaded: true, + db, + week: 1, + day: 1, + phase: 'DAY_WORK', + anomaly: 20, + political: 20, + trust: 80, + entropy: 10, + assets: [], + builtTags: {}, + activeLaws: [], + activeMysteries: [...db.mysteries], + currentAgenda: db.agendas.length > 0 ? db.agendas[Math.floor(Math.random() * db.agendas.length)] : null, + currentQuest: db.quests.length > 0 ? db.quests[Math.floor(Math.random() * db.quests.length)] : null, + }), + + addStat: (key, val) => set((state) => ({ + [key]: Math.max(0, Math.min(100, state[key] + val)) // Ensure between 0 and 100 for percentage stats, though anomaly/political can go higher + })), + + nextDay: () => { + const state = get(); + if (!state.db) return; + + if (state.day > 5) { + set({ phase: 'COUNCIL' }); + return; + } + + if (state.entropy >= 100) { + set({ phase: 'ENDING' }); + return; + } + + // 파라미터 패널티 적용 등 (기존 로직 이식) + let newEntropy = state.entropy; + state.activeMysteries.forEach(m => { + if (m.penalty_entropy) newEntropy += m.penalty_entropy; + }); + + let pool = state.db.scenarios.filter(s => s.act === state.week); + if (pool.length === 0) pool = state.db.scenarios; + const nextCard = pool[Math.floor(Math.random() * pool.length)]; + + set({ + day: state.day + 1, + entropy: Math.min(100, newEntropy), + currentCard: nextCard, + lockState: 'none' // 추후 활성 법안에 따라 계산 + }); + }, + + processSwipe: (direction) => { + // 스와이프 처리 로직 (기존 로직 이식) + get().nextDay(); + } +})); diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..20c0156 --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,84 @@ +export interface Faction { + id: string; + name: string; + share: number; + like_tag: string; + hate_tag: string; + is_blacklisted?: boolean; + color?: string; +} + +export interface CardData { + id: string | number; + dept: string; + color?: string; + title: string; + body: string; + flavor: string; + faction: string; + tags: string[]; + yes_a: number; // Anomaly (Data) cost/gain + no_p: number; // Political capital cost/gain + yes_e: number; // Entropy change on yes + no_e: number; // Entropy change on no + act?: number; +} + +export interface Agenda { + id: string; + title: string; + desc: string; +} + +export interface Quest { + id: string; + title: string; + reward: string; + penalty: string; +} + +export interface Bill { + id: string; + name: string; + desc: string; + type: string; // 'lock_approve', 'lock_reject', 'buff_tag', 'nullify_tag', etc. + tag: string; + is_buff?: boolean; + target_tag?: string; + buff_tag?: string | null; + nullify_tag?: string | null; +} + +export interface Asset { + id: string; + name: string; + tags: string[]; + passive_effect?: { anomaly?: number; political?: number; entropy?: number }; + holding_risk?: { entropy?: number }; + combo_req?: number; + trigger?: string; + effect_type?: string; + effect_target?: 'anomaly' | 'political' | 'trust' | 'entropy'; + effect_val?: number; + combo_effect_key?: 'anomaly' | 'political' | 'trust' | 'entropy'; + combo_effect_val?: number; +} + +export interface Mystery { + id: string; + title: string; + desc: string; + req_tags: Record; + cost_anomaly: number; + penalty_entropy: number; +} + +export interface Database { + factions: Faction[]; + agendas: Agenda[]; + quests: Quest[]; + bills: Bill[]; + assets: Asset[]; + scenarios: CardData[]; + mysteries: Mystery[]; +} diff --git a/src/utils/dataLoader.ts b/src/utils/dataLoader.ts new file mode 100644 index 0000000..b3e04f8 --- /dev/null +++ b/src/utils/dataLoader.ts @@ -0,0 +1,117 @@ +import Papa from 'papaparse'; +import { Database } from '../types'; + +const SHEET_URLS = { + factions: "/data/factions.csv", + agendas: "/data/agendas.csv", + quests: "/data/quests.csv", + bills: "/data/bills.csv", + assets: "/data/assets.csv", + scenarios: "/data/scenarios.csv", + mysteries: "/data/mysteries.csv" +}; + +function normalizeKey(str: string) { + return String(str).replace(/^\uFEFF/, '').trim().toLowerCase(); +} + +function normalizeValue(val: any) { + return typeof val === 'string' ? val.trim() : val; +} + +function parseCSV(url: string): Promise { + return new Promise((resolve) => { + Papa.parse(url, { + header: true, + skipEmptyLines: true, + download: true, + complete: function(results) { + const data = results.data.map((row: any) => { + let r: any = {}; + for(let k in row) r[normalizeKey(k)] = normalizeValue(row[k]); + return r; + }); + resolve(data as T[]); + }, + error: function() { + resolve([]); + } + }); + }); +} + +export async function initDatabase(): Promise { + const [factionsData, agendasData, questsData, billsData, assetsData, scenariosData, mysteriesData] = await Promise.all([ + parseCSV(SHEET_URLS.factions), + parseCSV(SHEET_URLS.agendas), + parseCSV(SHEET_URLS.quests), + parseCSV(SHEET_URLS.bills), + parseCSV(SHEET_URLS.assets), + parseCSV(SHEET_URLS.scenarios), + parseCSV(SHEET_URLS.mysteries) + ]); + + const factions = factionsData.map(f => ({ + ...f, + share: parseInt(f.share) || 10, + like_tag: f.love_tag || f.like_tag || '', + hate_tag: f.hate_tag || '' + })); + + const bills = billsData.map(b => { + let is_buff = b.type === 'lock_reject' || b.type === 'buff_tag'; + return { + ...b, + is_buff, + target_tag: b.tag, + buff_tag: is_buff ? b.tag : null, + nullify_tag: !is_buff ? b.tag : null + }; + }); + + const assets = assetsData.map(a => ({ + ...a, + tags: a.tags ? a.tags.split(',').map((t: string) => t.trim()) : [], + passive_effect: { anomaly: parseInt(a.passive_eff_val) || 0 }, + holding_risk: { entropy: parseInt(a.risk_eff_val) || 0 }, + combo_req: parseInt(a.combo_req) || 0, + effect_val: parseInt(a.effect_val) || 0, + combo_effect_val: parseInt(a.combo_effect_val) || 0 + })); + + const scenarios = scenariosData.map(s => ({ + ...s, + act: parseInt(s.act) || 1, + tags: s.tags ? s.tags.split(',').map((t: string) => t.trim().replace(/^"|"$/g, '')) : [], + yes_a: parseInt(s.cost) || 0, + no_p: parseInt(s.conflict) || 0, + yes_e: parseInt(s.yes_e) || 0, + no_e: parseInt(s.no_e) || 0, + })); + + const mysteries = mysteriesData.map(m => { + let req_tags: Record = {}; + if (m.req_tags) { + m.req_tags.split(',').forEach((rt: string) => { + let parts = rt.split(':'); + if (parts.length === 2) req_tags[parts[0].trim()] = parseInt(parts[1]); + }); + } + return { + ...m, + req_tags, + cost_anomaly: parseInt(m.cost_anomaly) || 0, + penalty_entropy: parseInt(m.penalty_entropy) || 0 + }; + }); + + return { + factions, + agendas: agendasData, + quests: questsData, + bills, + assets, + scenarios, + mysteries + }; +} diff --git a/docs/Project SS DB.xlsx b/src_old/Project SS DB.xlsx similarity index 100% rename from docs/Project SS DB.xlsx rename to src_old/Project SS DB.xlsx diff --git a/docs/Project SS PRD.md b/src_old/Project SS PRD.md similarity index 100% rename from docs/Project SS PRD.md rename to src_old/Project SS PRD.md diff --git a/docs/Project SS 기획서.md b/src_old/Project SS 기획서.md similarity index 100% rename from docs/Project SS 기획서.md rename to src_old/Project SS 기획서.md diff --git a/src/index.html b/src_old/index.html similarity index 100% rename from src/index.html rename to src_old/index.html diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..6742961 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": true, + + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..42872c5 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..e4bf70d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import tailwindcss from '@tailwindcss/vite'; +import path from 'path'; + +export default defineConfig({ + plugins: [ + tailwindcss(), + react() + ], + resolve: { + alias: { + '@': path.resolve(__dirname, './src') + } + }, + base: './', + server: { + port: 5173 + } +});