From b7be629a61b7a2c0f3445734f50d29cf1be77af3 Mon Sep 17 00:00:00 2001
From: Austin Dang <122927862+austindang67@users.noreply.github.com>
Date: Tue, 9 Sep 2025 22:02:49 -1000
Subject: [PATCH 01/29] 1 Initialize vite-react typescript project
Created the vite-react typescript project
---
client/.gitignore | 24 +
client/README.md | 69 ++
client/eslint.config.js | 23 +
client/index.html | 13 +
client/package.json | 29 +
client/pnpm-lock.yaml | 2082 +++++++++++++++++++++++++++++++++++
client/public/vite.svg | 1 +
client/src/App.css | 42 +
client/src/App.tsx | 35 +
client/src/assets/react.svg | 1 +
client/src/index.css | 68 ++
client/src/main.tsx | 10 +
client/src/vite-env.d.ts | 1 +
client/tsconfig.app.json | 27 +
client/tsconfig.json | 7 +
client/tsconfig.node.json | 25 +
client/vite.config.ts | 7 +
17 files changed, 2464 insertions(+)
create mode 100644 client/.gitignore
create mode 100644 client/README.md
create mode 100644 client/eslint.config.js
create mode 100644 client/index.html
create mode 100644 client/package.json
create mode 100644 client/pnpm-lock.yaml
create mode 100644 client/public/vite.svg
create mode 100644 client/src/App.css
create mode 100644 client/src/App.tsx
create mode 100644 client/src/assets/react.svg
create mode 100644 client/src/index.css
create mode 100644 client/src/main.tsx
create mode 100644 client/src/vite-env.d.ts
create mode 100644 client/tsconfig.app.json
create mode 100644 client/tsconfig.json
create mode 100644 client/tsconfig.node.json
create mode 100644 client/vite.config.ts
diff --git a/client/.gitignore b/client/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/client/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/client/README.md b/client/README.md
new file mode 100644
index 0000000..7959ce4
--- /dev/null
+++ b/client/README.md
@@ -0,0 +1,69 @@
+# React + TypeScript + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
+
+## Expanding the ESLint configuration
+
+If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
+
+```js
+export default tseslint.config([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{ts,tsx}'],
+ extends: [
+ // Other configs...
+
+ // Remove tseslint.configs.recommended and replace with this
+ ...tseslint.configs.recommendedTypeChecked,
+ // Alternatively, use this for stricter rules
+ ...tseslint.configs.strictTypeChecked,
+ // Optionally, add this for stylistic rules
+ ...tseslint.configs.stylisticTypeChecked,
+
+ // Other configs...
+ ],
+ languageOptions: {
+ parserOptions: {
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
+ tsconfigRootDir: import.meta.dirname,
+ },
+ // other options...
+ },
+ },
+])
+```
+
+You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
+
+```js
+// eslint.config.js
+import reactX from 'eslint-plugin-react-x'
+import reactDom from 'eslint-plugin-react-dom'
+
+export default tseslint.config([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{ts,tsx}'],
+ extends: [
+ // Other configs...
+ // Enable lint rules for React
+ reactX.configs['recommended-typescript'],
+ // Enable lint rules for React DOM
+ reactDom.configs.recommended,
+ ],
+ languageOptions: {
+ parserOptions: {
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
+ tsconfigRootDir: import.meta.dirname,
+ },
+ // other options...
+ },
+ },
+])
+```
diff --git a/client/eslint.config.js b/client/eslint.config.js
new file mode 100644
index 0000000..d94e7de
--- /dev/null
+++ b/client/eslint.config.js
@@ -0,0 +1,23 @@
+import js from '@eslint/js'
+import globals from 'globals'
+import reactHooks from 'eslint-plugin-react-hooks'
+import reactRefresh from 'eslint-plugin-react-refresh'
+import tseslint from 'typescript-eslint'
+import { globalIgnores } from 'eslint/config'
+
+export default tseslint.config([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{ts,tsx}'],
+ extends: [
+ js.configs.recommended,
+ tseslint.configs.recommended,
+ reactHooks.configs['recommended-latest'],
+ reactRefresh.configs.vite,
+ ],
+ languageOptions: {
+ ecmaVersion: 2020,
+ globals: globals.browser,
+ },
+ },
+])
diff --git a/client/index.html b/client/index.html
new file mode 100644
index 0000000..e4b78ea
--- /dev/null
+++ b/client/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + React + TS
+
+
+
+
+
+
diff --git a/client/package.json b/client/package.json
new file mode 100644
index 0000000..d540c6a
--- /dev/null
+++ b/client/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "client",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "lint": "eslint .",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "react": "^19.1.1",
+ "react-dom": "^19.1.1"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.33.0",
+ "@types/react": "^19.1.10",
+ "@types/react-dom": "^19.1.7",
+ "@vitejs/plugin-react": "^5.0.0",
+ "eslint": "^9.33.0",
+ "eslint-plugin-react-hooks": "^5.2.0",
+ "eslint-plugin-react-refresh": "^0.4.20",
+ "globals": "^16.3.0",
+ "typescript": "~5.8.3",
+ "typescript-eslint": "^8.39.1",
+ "vite": "^7.1.2"
+ }
+}
diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml
new file mode 100644
index 0000000..13e65e4
--- /dev/null
+++ b/client/pnpm-lock.yaml
@@ -0,0 +1,2082 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ react:
+ specifier: ^19.1.1
+ version: 19.1.1
+ react-dom:
+ specifier: ^19.1.1
+ version: 19.1.1(react@19.1.1)
+ devDependencies:
+ '@eslint/js':
+ specifier: ^9.33.0
+ version: 9.35.0
+ '@types/react':
+ specifier: ^19.1.10
+ version: 19.1.12
+ '@types/react-dom':
+ specifier: ^19.1.7
+ version: 19.1.9(@types/react@19.1.12)
+ '@vitejs/plugin-react':
+ specifier: ^5.0.0
+ version: 5.0.2(vite@7.1.5)
+ eslint:
+ specifier: ^9.33.0
+ version: 9.35.0
+ eslint-plugin-react-hooks:
+ specifier: ^5.2.0
+ version: 5.2.0(eslint@9.35.0)
+ eslint-plugin-react-refresh:
+ specifier: ^0.4.20
+ version: 0.4.20(eslint@9.35.0)
+ globals:
+ specifier: ^16.3.0
+ version: 16.4.0
+ typescript:
+ specifier: ~5.8.3
+ version: 5.8.3
+ typescript-eslint:
+ specifier: ^8.39.1
+ version: 8.43.0(eslint@9.35.0)(typescript@5.8.3)
+ vite:
+ specifier: ^7.1.2
+ version: 7.1.5
+
+packages:
+
+ '@babel/code-frame@7.27.1':
+ resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.28.4':
+ resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.28.4':
+ resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.28.3':
+ resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.27.2':
+ resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
+ 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==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.28.3':
+ resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.27.1':
+ resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
+ 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-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.28.4':
+ resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.28.4':
+ resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1':
+ resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1':
+ resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==}
+ engines: {node: '>=6.9.0'}
+ 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.4':
+ resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.28.4':
+ resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@esbuild/aix-ppc64@0.25.9':
+ resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.25.9':
+ resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.25.9':
+ resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.25.9':
+ resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.25.9':
+ resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.25.9':
+ resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.25.9':
+ resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.25.9':
+ resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.25.9':
+ resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.25.9':
+ resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.25.9':
+ resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.25.9':
+ resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.25.9':
+ resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.25.9':
+ resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.25.9':
+ resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.25.9':
+ resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.25.9':
+ resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-arm64@0.25.9':
+ resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.25.9':
+ resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.25.9':
+ resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.25.9':
+ resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/openharmony-arm64@0.25.9':
+ resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@esbuild/sunos-x64@0.25.9':
+ resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.25.9':
+ resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.25.9':
+ resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.25.9':
+ resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
+ '@eslint-community/eslint-utils@4.9.0':
+ resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==}
+ 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==}
+ 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.1':
+ resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/core@0.15.2':
+ resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/eslintrc@3.3.1':
+ resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/js@9.35.0':
+ resolution: {integrity: sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/object-schema@2.1.6':
+ resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/plugin-kit@0.3.5':
+ resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@humanfs/core@0.19.1':
+ resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
+ engines: {node: '>=18.18.0'}
+
+ '@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.4.3':
+ resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
+ engines: {node: '>=18.18'}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@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.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.30':
+ resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==}
+
+ '@nodelib/fs.scandir@2.1.5':
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.stat@2.0.5':
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.walk@1.2.8':
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+
+ '@rolldown/pluginutils@1.0.0-beta.34':
+ resolution: {integrity: sha512-LyAREkZHP5pMom7c24meKmJCdhf2hEyvam2q0unr3or9ydwDL+DJ8chTF6Av/RFPb3rH8UFBdMzO5MxTZW97oA==}
+
+ '@rollup/rollup-android-arm-eabi@4.50.1':
+ resolution: {integrity: sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.50.1':
+ resolution: {integrity: sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.50.1':
+ resolution: {integrity: sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.50.1':
+ resolution: {integrity: sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.50.1':
+ resolution: {integrity: sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.50.1':
+ resolution: {integrity: sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.50.1':
+ resolution: {integrity: sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.50.1':
+ resolution: {integrity: sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.50.1':
+ resolution: {integrity: sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.50.1':
+ resolution: {integrity: sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.50.1':
+ resolution: {integrity: sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-ppc64-gnu@4.50.1':
+ resolution: {integrity: sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.50.1':
+ resolution: {integrity: sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-musl@4.50.1':
+ resolution: {integrity: sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.50.1':
+ resolution: {integrity: sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.50.1':
+ resolution: {integrity: sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-musl@4.50.1':
+ resolution: {integrity: sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-openharmony-arm64@4.50.1':
+ resolution: {integrity: sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rollup/rollup-win32-arm64-msvc@4.50.1':
+ resolution: {integrity: sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.50.1':
+ resolution: {integrity: sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.50.1':
+ resolution: {integrity: sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@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==}
+
+ '@types/json-schema@7.0.15':
+ resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+
+ '@types/react-dom@19.1.9':
+ resolution: {integrity: sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==}
+ peerDependencies:
+ '@types/react': ^19.0.0
+
+ '@types/react@19.1.12':
+ resolution: {integrity: sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==}
+
+ '@typescript-eslint/eslint-plugin@8.43.0':
+ resolution: {integrity: sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^8.43.0
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/parser@8.43.0':
+ resolution: {integrity: sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/project-service@8.43.0':
+ resolution: {integrity: sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/scope-manager@8.43.0':
+ resolution: {integrity: sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/tsconfig-utils@8.43.0':
+ resolution: {integrity: sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/type-utils@8.43.0':
+ resolution: {integrity: sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/types@8.43.0':
+ resolution: {integrity: sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/typescript-estree@8.43.0':
+ resolution: {integrity: sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/utils@8.43.0':
+ resolution: {integrity: sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/visitor-keys@8.43.0':
+ resolution: {integrity: sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@vitejs/plugin-react@5.0.2':
+ resolution: {integrity: sha512-tmyFgixPZCx2+e6VO9TNITWcCQl8+Nl/E8YbAyPVv85QCc7/A3JrdfG2A8gIzvVhWuzMOVrFW1aReaNxrI6tbw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ peerDependencies:
+ vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+
+ acorn-jsx@5.3.2:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+ acorn@8.15.0:
+ resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ ajv@6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ brace-expansion@1.1.12:
+ resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
+
+ brace-expansion@2.0.2:
+ resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ browserslist@4.25.4:
+ resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ caniuse-lite@1.0.30001741:
+ resolution: {integrity: sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
+ csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+ debug@4.4.1:
+ resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+ electron-to-chromium@1.5.215:
+ resolution: {integrity: sha512-TIvGp57UpeNetj/wV/xpFNpWGb0b/ROw372lHPx5Aafx02gjTBtWnEEcaSX3W2dLM3OSdGGyHX/cHl01JQsLaQ==}
+
+ esbuild@0.25.9:
+ resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ eslint-plugin-react-hooks@5.2.0:
+ resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==}
+ engines: {node: '>=10'}
+ 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==}
+ peerDependencies:
+ eslint: '>=8.40'
+
+ eslint-scope@8.4.0:
+ resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ eslint-visitor-keys@4.2.1:
+ resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint@9.35.0:
+ resolution: {integrity: sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ hasBin: true
+ peerDependencies:
+ jiti: '*'
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+
+ espree@10.4.0:
+ resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ esquery@1.6.0:
+ resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
+ engines: {node: '>=0.10'}
+
+ esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+
+ estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+
+ esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ fast-glob@3.3.3:
+ resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
+ engines: {node: '>=8.6.0'}
+
+ fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+ fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
+ fastq@1.19.1:
+ resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
+
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ file-entry-cache@8.0.0:
+ resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+ engines: {node: '>=16.0.0'}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+
+ flat-cache@4.0.1:
+ resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+ engines: {node: '>=16'}
+
+ flatted@3.3.3:
+ resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+
+ glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+
+ globals@14.0.0:
+ resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
+ engines: {node: '>=18'}
+
+ globals@16.4.0:
+ resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==}
+ engines: {node: '>=18'}
+
+ graphemer@1.4.0:
+ resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ ignore@5.3.2:
+ resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+ engines: {node: '>= 4'}
+
+ ignore@7.0.5:
+ resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
+ engines: {node: '>= 4'}
+
+ import-fresh@3.3.1:
+ resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+ engines: {node: '>=6'}
+
+ imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+ json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+ json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+ levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+
+ locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+
+ lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+
+ minimatch@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+ node-releases@2.0.20:
+ resolution: {integrity: sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA==}
+
+ optionator@0.9.4:
+ resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+ engines: {node: '>= 0.8.0'}
+
+ p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+
+ p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ picomatch@4.0.3:
+ resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
+ engines: {node: '>=12'}
+
+ postcss@8.5.6:
+ resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+
+ punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+
+ queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+ react-dom@19.1.1:
+ resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==}
+ peerDependencies:
+ react: ^19.1.1
+
+ react-refresh@0.17.0:
+ resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
+ engines: {node: '>=0.10.0'}
+
+ react@19.1.1:
+ resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==}
+ engines: {node: '>=0.10.0'}
+
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ reusify@1.1.0:
+ resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+ rollup@4.50.1:
+ resolution: {integrity: sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==}
+ 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==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ semver@7.7.2:
+ resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ tinyglobby@0.2.15:
+ resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
+ engines: {node: '>=12.0.0'}
+
+ to-regex-range@5.0.1:
+ 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'
+
+ type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+
+ typescript-eslint@8.43.0:
+ resolution: {integrity: sha512-FyRGJKUGvcFekRRcBKFBlAhnp4Ng8rhe8tuvvkR9OiU0gfd4vyvTRQHEckO6VDlH57jbeUQem2IpqPq9kLJH+w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.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
+
+ update-browserslist-db@1.1.3:
+ resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+ vite@7.1.5:
+ resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^20.19.0 || >=22.12.0
+ jiti: '>=1.21.0'
+ less: ^4.0.0
+ lightningcss: ^1.21.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
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ word-wrap@1.2.5:
+ resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+ engines: {node: '>=0.10.0'}
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+ yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+
+snapshots:
+
+ '@babel/code-frame@7.27.1':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.27.1
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.28.4': {}
+
+ '@babel/core@7.28.4':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.28.3
+ '@babel/helper-compilation-targets': 7.27.2
+ '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4)
+ '@babel/helpers': 7.28.4
+ '@babel/parser': 7.28.4
+ '@babel/template': 7.27.2
+ '@babel/traverse': 7.28.4
+ '@babel/types': 7.28.4
+ '@jridgewell/remapping': 2.3.5
+ convert-source-map: 2.0.0
+ debug: 4.4.1
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.28.3':
+ dependencies:
+ '@babel/parser': 7.28.4
+ '@babel/types': 7.28.4
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.30
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.27.2':
+ dependencies:
+ '@babel/compat-data': 7.28.4
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.25.4
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-globals@7.28.0': {}
+
+ '@babel/helper-module-imports@7.27.1':
+ dependencies:
+ '@babel/traverse': 7.28.4
+ '@babel/types': 7.28.4
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)':
+ dependencies:
+ '@babel/core': 7.28.4
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+ '@babel/traverse': 7.28.4
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.27.1': {}
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.27.1': {}
+
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.28.4':
+ dependencies:
+ '@babel/template': 7.27.2
+ '@babel/types': 7.28.4
+
+ '@babel/parser@7.28.4':
+ dependencies:
+ '@babel/types': 7.28.4
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)':
+ dependencies:
+ '@babel/core': 7.28.4
+ '@babel/helper-plugin-utils': 7.27.1
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)':
+ dependencies:
+ '@babel/core': 7.28.4
+ '@babel/helper-plugin-utils': 7.27.1
+
+ '@babel/template@7.27.2':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/parser': 7.28.4
+ '@babel/types': 7.28.4
+
+ '@babel/traverse@7.28.4':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.28.3
+ '@babel/helper-globals': 7.28.0
+ '@babel/parser': 7.28.4
+ '@babel/template': 7.27.2
+ '@babel/types': 7.28.4
+ debug: 4.4.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.28.4':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+
+ '@esbuild/aix-ppc64@0.25.9':
+ optional: true
+
+ '@esbuild/android-arm64@0.25.9':
+ optional: true
+
+ '@esbuild/android-arm@0.25.9':
+ optional: true
+
+ '@esbuild/android-x64@0.25.9':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.25.9':
+ optional: true
+
+ '@esbuild/darwin-x64@0.25.9':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.25.9':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.25.9':
+ optional: true
+
+ '@esbuild/linux-arm64@0.25.9':
+ optional: true
+
+ '@esbuild/linux-arm@0.25.9':
+ optional: true
+
+ '@esbuild/linux-ia32@0.25.9':
+ optional: true
+
+ '@esbuild/linux-loong64@0.25.9':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.25.9':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.25.9':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.25.9':
+ optional: true
+
+ '@esbuild/linux-s390x@0.25.9':
+ optional: true
+
+ '@esbuild/linux-x64@0.25.9':
+ optional: true
+
+ '@esbuild/netbsd-arm64@0.25.9':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.25.9':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.25.9':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.25.9':
+ optional: true
+
+ '@esbuild/openharmony-arm64@0.25.9':
+ optional: true
+
+ '@esbuild/sunos-x64@0.25.9':
+ optional: true
+
+ '@esbuild/win32-arm64@0.25.9':
+ optional: true
+
+ '@esbuild/win32-ia32@0.25.9':
+ optional: true
+
+ '@esbuild/win32-x64@0.25.9':
+ optional: true
+
+ '@eslint-community/eslint-utils@4.9.0(eslint@9.35.0)':
+ dependencies:
+ eslint: 9.35.0
+ eslint-visitor-keys: 3.4.3
+
+ '@eslint-community/regexpp@4.12.1': {}
+
+ '@eslint/config-array@0.21.0':
+ dependencies:
+ '@eslint/object-schema': 2.1.6
+ debug: 4.4.1
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/config-helpers@0.3.1': {}
+
+ '@eslint/core@0.15.2':
+ dependencies:
+ '@types/json-schema': 7.0.15
+
+ '@eslint/eslintrc@3.3.1':
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.4.1
+ espree: 10.4.0
+ globals: 14.0.0
+ ignore: 5.3.2
+ import-fresh: 3.3.1
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/js@9.35.0': {}
+
+ '@eslint/object-schema@2.1.6': {}
+
+ '@eslint/plugin-kit@0.3.5':
+ dependencies:
+ '@eslint/core': 0.15.2
+ levn: 0.4.1
+
+ '@humanfs/core@0.19.1': {}
+
+ '@humanfs/node@0.16.7':
+ dependencies:
+ '@humanfs/core': 0.19.1
+ '@humanwhocodes/retry': 0.4.3
+
+ '@humanwhocodes/module-importer@1.0.1': {}
+
+ '@humanwhocodes/retry@0.4.3': {}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.30
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.30
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.30':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@nodelib/fs.scandir@2.1.5':
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+
+ '@nodelib/fs.stat@2.0.5': {}
+
+ '@nodelib/fs.walk@1.2.8':
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.19.1
+
+ '@rolldown/pluginutils@1.0.0-beta.34': {}
+
+ '@rollup/rollup-android-arm-eabi@4.50.1':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.50.1':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.50.1':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.50.1':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.50.1':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.50.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.50.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.50.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.50.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.50.1':
+ optional: true
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.50.1':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-gnu@4.50.1':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.50.1':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.50.1':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.50.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.50.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.50.1':
+ optional: true
+
+ '@rollup/rollup-openharmony-arm64@4.50.1':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.50.1':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.50.1':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.50.1':
+ optional: true
+
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.28.4
+ '@babel/types': 7.28.4
+ '@types/babel__generator': 7.27.0
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.28.0
+
+ '@types/babel__generator@7.27.0':
+ dependencies:
+ '@babel/types': 7.28.4
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.28.4
+ '@babel/types': 7.28.4
+
+ '@types/babel__traverse@7.28.0':
+ dependencies:
+ '@babel/types': 7.28.4
+
+ '@types/estree@1.0.8': {}
+
+ '@types/json-schema@7.0.15': {}
+
+ '@types/react-dom@19.1.9(@types/react@19.1.12)':
+ dependencies:
+ '@types/react': 19.1.12
+
+ '@types/react@19.1.12':
+ dependencies:
+ csstype: 3.1.3
+
+ '@typescript-eslint/eslint-plugin@8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.8.3))(eslint@9.35.0)(typescript@5.8.3)':
+ dependencies:
+ '@eslint-community/regexpp': 4.12.1
+ '@typescript-eslint/parser': 8.43.0(eslint@9.35.0)(typescript@5.8.3)
+ '@typescript-eslint/scope-manager': 8.43.0
+ '@typescript-eslint/type-utils': 8.43.0(eslint@9.35.0)(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.43.0(eslint@9.35.0)(typescript@5.8.3)
+ '@typescript-eslint/visitor-keys': 8.43.0
+ eslint: 9.35.0
+ graphemer: 1.4.0
+ 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.43.0(eslint@9.35.0)(typescript@5.8.3)':
+ dependencies:
+ '@typescript-eslint/scope-manager': 8.43.0
+ '@typescript-eslint/types': 8.43.0
+ '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.8.3)
+ '@typescript-eslint/visitor-keys': 8.43.0
+ debug: 4.4.1
+ eslint: 9.35.0
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/project-service@8.43.0(typescript@5.8.3)':
+ dependencies:
+ '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.8.3)
+ '@typescript-eslint/types': 8.43.0
+ debug: 4.4.1
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/scope-manager@8.43.0':
+ dependencies:
+ '@typescript-eslint/types': 8.43.0
+ '@typescript-eslint/visitor-keys': 8.43.0
+
+ '@typescript-eslint/tsconfig-utils@8.43.0(typescript@5.8.3)':
+ dependencies:
+ typescript: 5.8.3
+
+ '@typescript-eslint/type-utils@8.43.0(eslint@9.35.0)(typescript@5.8.3)':
+ dependencies:
+ '@typescript-eslint/types': 8.43.0
+ '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.43.0(eslint@9.35.0)(typescript@5.8.3)
+ debug: 4.4.1
+ eslint: 9.35.0
+ ts-api-utils: 2.1.0(typescript@5.8.3)
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/types@8.43.0': {}
+
+ '@typescript-eslint/typescript-estree@8.43.0(typescript@5.8.3)':
+ dependencies:
+ '@typescript-eslint/project-service': 8.43.0(typescript@5.8.3)
+ '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.8.3)
+ '@typescript-eslint/types': 8.43.0
+ '@typescript-eslint/visitor-keys': 8.43.0
+ debug: 4.4.1
+ fast-glob: 3.3.3
+ is-glob: 4.0.3
+ minimatch: 9.0.5
+ semver: 7.7.2
+ ts-api-utils: 2.1.0(typescript@5.8.3)
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/utils@8.43.0(eslint@9.35.0)(typescript@5.8.3)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0)
+ '@typescript-eslint/scope-manager': 8.43.0
+ '@typescript-eslint/types': 8.43.0
+ '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.8.3)
+ eslint: 9.35.0
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/visitor-keys@8.43.0':
+ dependencies:
+ '@typescript-eslint/types': 8.43.0
+ eslint-visitor-keys: 4.2.1
+
+ '@vitejs/plugin-react@5.0.2(vite@7.1.5)':
+ dependencies:
+ '@babel/core': 7.28.4
+ '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
+ '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4)
+ '@rolldown/pluginutils': 1.0.0-beta.34
+ '@types/babel__core': 7.20.5
+ react-refresh: 0.17.0
+ vite: 7.1.5
+ transitivePeerDependencies:
+ - supports-color
+
+ acorn-jsx@5.3.2(acorn@8.15.0):
+ dependencies:
+ acorn: 8.15.0
+
+ acorn@8.15.0: {}
+
+ ajv@6.12.6:
+ 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
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ argparse@2.0.1: {}
+
+ balanced-match@1.0.2: {}
+
+ brace-expansion@1.1.12:
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+
+ brace-expansion@2.0.2:
+ dependencies:
+ balanced-match: 1.0.2
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ browserslist@4.25.4:
+ dependencies:
+ caniuse-lite: 1.0.30001741
+ electron-to-chromium: 1.5.215
+ node-releases: 2.0.20
+ update-browserslist-db: 1.1.3(browserslist@4.25.4)
+
+ callsites@3.1.0: {}
+
+ caniuse-lite@1.0.30001741: {}
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ concat-map@0.0.1: {}
+
+ convert-source-map@2.0.0: {}
+
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ csstype@3.1.3: {}
+
+ debug@4.4.1:
+ dependencies:
+ ms: 2.1.3
+
+ deep-is@0.1.4: {}
+
+ electron-to-chromium@1.5.215: {}
+
+ esbuild@0.25.9:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.25.9
+ '@esbuild/android-arm': 0.25.9
+ '@esbuild/android-arm64': 0.25.9
+ '@esbuild/android-x64': 0.25.9
+ '@esbuild/darwin-arm64': 0.25.9
+ '@esbuild/darwin-x64': 0.25.9
+ '@esbuild/freebsd-arm64': 0.25.9
+ '@esbuild/freebsd-x64': 0.25.9
+ '@esbuild/linux-arm': 0.25.9
+ '@esbuild/linux-arm64': 0.25.9
+ '@esbuild/linux-ia32': 0.25.9
+ '@esbuild/linux-loong64': 0.25.9
+ '@esbuild/linux-mips64el': 0.25.9
+ '@esbuild/linux-ppc64': 0.25.9
+ '@esbuild/linux-riscv64': 0.25.9
+ '@esbuild/linux-s390x': 0.25.9
+ '@esbuild/linux-x64': 0.25.9
+ '@esbuild/netbsd-arm64': 0.25.9
+ '@esbuild/netbsd-x64': 0.25.9
+ '@esbuild/openbsd-arm64': 0.25.9
+ '@esbuild/openbsd-x64': 0.25.9
+ '@esbuild/openharmony-arm64': 0.25.9
+ '@esbuild/sunos-x64': 0.25.9
+ '@esbuild/win32-arm64': 0.25.9
+ '@esbuild/win32-ia32': 0.25.9
+ '@esbuild/win32-x64': 0.25.9
+
+ escalade@3.2.0: {}
+
+ escape-string-regexp@4.0.0: {}
+
+ eslint-plugin-react-hooks@5.2.0(eslint@9.35.0):
+ dependencies:
+ eslint: 9.35.0
+
+ eslint-plugin-react-refresh@0.4.20(eslint@9.35.0):
+ dependencies:
+ eslint: 9.35.0
+
+ eslint-scope@8.4.0:
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+
+ eslint-visitor-keys@3.4.3: {}
+
+ eslint-visitor-keys@4.2.1: {}
+
+ eslint@9.35.0:
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0)
+ '@eslint-community/regexpp': 4.12.1
+ '@eslint/config-array': 0.21.0
+ '@eslint/config-helpers': 0.3.1
+ '@eslint/core': 0.15.2
+ '@eslint/eslintrc': 3.3.1
+ '@eslint/js': 9.35.0
+ '@eslint/plugin-kit': 0.3.5
+ '@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
+ 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
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 8.0.0
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ ignore: 5.3.2
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ json-stable-stringify-without-jsonify: 1.0.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.4
+ transitivePeerDependencies:
+ - supports-color
+
+ espree@10.4.0:
+ dependencies:
+ acorn: 8.15.0
+ acorn-jsx: 5.3.2(acorn@8.15.0)
+ eslint-visitor-keys: 4.2.1
+
+ esquery@1.6.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ esrecurse@4.3.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ estraverse@5.3.0: {}
+
+ esutils@2.0.3: {}
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-glob@3.3.3:
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.8
+
+ fast-json-stable-stringify@2.1.0: {}
+
+ fast-levenshtein@2.0.6: {}
+
+ fastq@1.19.1:
+ dependencies:
+ reusify: 1.1.0
+
+ fdir@6.5.0(picomatch@4.0.3):
+ optionalDependencies:
+ picomatch: 4.0.3
+
+ file-entry-cache@8.0.0:
+ dependencies:
+ flat-cache: 4.0.1
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ find-up@5.0.0:
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+
+ flat-cache@4.0.1:
+ dependencies:
+ flatted: 3.3.3
+ keyv: 4.5.4
+
+ flatted@3.3.3: {}
+
+ fsevents@2.3.3:
+ optional: true
+
+ gensync@1.0.0-beta.2: {}
+
+ glob-parent@5.1.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ glob-parent@6.0.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ globals@14.0.0: {}
+
+ globals@16.4.0: {}
+
+ graphemer@1.4.0: {}
+
+ has-flag@4.0.0: {}
+
+ ignore@5.3.2: {}
+
+ ignore@7.0.5: {}
+
+ import-fresh@3.3.1:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ imurmurhash@0.1.4: {}
+
+ is-extglob@2.1.1: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-number@7.0.0: {}
+
+ isexe@2.0.0: {}
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@4.1.0:
+ dependencies:
+ argparse: 2.0.1
+
+ jsesc@3.1.0: {}
+
+ json-buffer@3.0.1: {}
+
+ json-schema-traverse@0.4.1: {}
+
+ json-stable-stringify-without-jsonify@1.0.1: {}
+
+ json5@2.2.3: {}
+
+ keyv@4.5.4:
+ dependencies:
+ json-buffer: 3.0.1
+
+ levn@0.4.1:
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+
+ locate-path@6.0.0:
+ dependencies:
+ p-locate: 5.0.0
+
+ lodash.merge@4.6.2: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ merge2@1.4.1: {}
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ minimatch@3.1.2:
+ dependencies:
+ brace-expansion: 1.1.12
+
+ minimatch@9.0.5:
+ dependencies:
+ brace-expansion: 2.0.2
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.11: {}
+
+ natural-compare@1.4.0: {}
+
+ node-releases@2.0.20: {}
+
+ optionator@0.9.4:
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.5
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
+ p-locate@5.0.0:
+ dependencies:
+ p-limit: 3.1.0
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ path-exists@4.0.0: {}
+
+ path-key@3.1.1: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ picomatch@4.0.3: {}
+
+ postcss@8.5.6:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ prelude-ls@1.2.1: {}
+
+ punycode@2.3.1: {}
+
+ queue-microtask@1.2.3: {}
+
+ react-dom@19.1.1(react@19.1.1):
+ dependencies:
+ react: 19.1.1
+ scheduler: 0.26.0
+
+ react-refresh@0.17.0: {}
+
+ react@19.1.1: {}
+
+ resolve-from@4.0.0: {}
+
+ reusify@1.1.0: {}
+
+ rollup@4.50.1:
+ dependencies:
+ '@types/estree': 1.0.8
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.50.1
+ '@rollup/rollup-android-arm64': 4.50.1
+ '@rollup/rollup-darwin-arm64': 4.50.1
+ '@rollup/rollup-darwin-x64': 4.50.1
+ '@rollup/rollup-freebsd-arm64': 4.50.1
+ '@rollup/rollup-freebsd-x64': 4.50.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.50.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.50.1
+ '@rollup/rollup-linux-arm64-gnu': 4.50.1
+ '@rollup/rollup-linux-arm64-musl': 4.50.1
+ '@rollup/rollup-linux-loongarch64-gnu': 4.50.1
+ '@rollup/rollup-linux-ppc64-gnu': 4.50.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.50.1
+ '@rollup/rollup-linux-riscv64-musl': 4.50.1
+ '@rollup/rollup-linux-s390x-gnu': 4.50.1
+ '@rollup/rollup-linux-x64-gnu': 4.50.1
+ '@rollup/rollup-linux-x64-musl': 4.50.1
+ '@rollup/rollup-openharmony-arm64': 4.50.1
+ '@rollup/rollup-win32-arm64-msvc': 4.50.1
+ '@rollup/rollup-win32-ia32-msvc': 4.50.1
+ '@rollup/rollup-win32-x64-msvc': 4.50.1
+ fsevents: 2.3.3
+
+ run-parallel@1.2.0:
+ dependencies:
+ queue-microtask: 1.2.3
+
+ scheduler@0.26.0: {}
+
+ semver@6.3.1: {}
+
+ semver@7.7.2: {}
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ source-map-js@1.2.1: {}
+
+ strip-json-comments@3.1.1: {}
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ tinyglobby@0.2.15:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ ts-api-utils@2.1.0(typescript@5.8.3):
+ dependencies:
+ typescript: 5.8.3
+
+ type-check@0.4.0:
+ dependencies:
+ prelude-ls: 1.2.1
+
+ typescript-eslint@8.43.0(eslint@9.35.0)(typescript@5.8.3):
+ dependencies:
+ '@typescript-eslint/eslint-plugin': 8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.8.3))(eslint@9.35.0)(typescript@5.8.3)
+ '@typescript-eslint/parser': 8.43.0(eslint@9.35.0)(typescript@5.8.3)
+ '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.43.0(eslint@9.35.0)(typescript@5.8.3)
+ eslint: 9.35.0
+ typescript: 5.8.3
+ transitivePeerDependencies:
+ - supports-color
+
+ typescript@5.8.3: {}
+
+ update-browserslist-db@1.1.3(browserslist@4.25.4):
+ dependencies:
+ browserslist: 4.25.4
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
+
+ vite@7.1.5:
+ dependencies:
+ esbuild: 0.25.9
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+ postcss: 8.5.6
+ rollup: 4.50.1
+ tinyglobby: 0.2.15
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ word-wrap@1.2.5: {}
+
+ yallist@3.1.1: {}
+
+ yocto-queue@0.1.0: {}
diff --git a/client/public/vite.svg b/client/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/client/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/App.css b/client/src/App.css
new file mode 100644
index 0000000..b9d355d
--- /dev/null
+++ b/client/src/App.css
@@ -0,0 +1,42 @@
+#root {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+ transition: filter 300ms;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+ filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ a:nth-of-type(2) .logo {
+ animation: logo-spin infinite 20s linear;
+ }
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
diff --git a/client/src/App.tsx b/client/src/App.tsx
new file mode 100644
index 0000000..3d7ded3
--- /dev/null
+++ b/client/src/App.tsx
@@ -0,0 +1,35 @@
+import { useState } from 'react'
+import reactLogo from './assets/react.svg'
+import viteLogo from '/vite.svg'
+import './App.css'
+
+function App() {
+ const [count, setCount] = useState(0)
+
+ return (
+ <>
+
+ Vite + React
+
+
+
+ Edit src/App.tsx and save to test HMR
+
+
+
+ Click on the Vite and React logos to learn more
+
+ >
+ )
+}
+
+export default App
diff --git a/client/src/assets/react.svg b/client/src/assets/react.svg
new file mode 100644
index 0000000..6c87de9
--- /dev/null
+++ b/client/src/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/index.css b/client/src/index.css
new file mode 100644
index 0000000..08a3ac9
--- /dev/null
+++ b/client/src/index.css
@@ -0,0 +1,68 @@
+:root {
+ font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/client/src/main.tsx b/client/src/main.tsx
new file mode 100644
index 0000000..bef5202
--- /dev/null
+++ b/client/src/main.tsx
@@ -0,0 +1,10 @@
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
+import './index.css'
+import App from './App.tsx'
+
+createRoot(document.getElementById('root')!).render(
+
+
+ ,
+)
diff --git a/client/src/vite-env.d.ts b/client/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/client/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/client/tsconfig.app.json b/client/tsconfig.app.json
new file mode 100644
index 0000000..227a6c6
--- /dev/null
+++ b/client/tsconfig.app.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+ "target": "ES2022",
+ "useDefineForClassFields": true,
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["src"]
+}
diff --git a/client/tsconfig.json b/client/tsconfig.json
new file mode 100644
index 0000000..1ffef60
--- /dev/null
+++ b/client/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
diff --git a/client/tsconfig.node.json b/client/tsconfig.node.json
new file mode 100644
index 0000000..f85a399
--- /dev/null
+++ b/client/tsconfig.node.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "target": "ES2023",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/client/vite.config.ts b/client/vite.config.ts
new file mode 100644
index 0000000..8b0f57b
--- /dev/null
+++ b/client/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [react()],
+})
From a58016f384ed83089d3af5b0a0b4a612fd8f4686 Mon Sep 17 00:00:00 2001
From: austindang67 <122927862+austindang67@users.noreply.github.com>
Date: Wed, 24 Sep 2025 14:06:26 -1000
Subject: [PATCH 02/29] Installed d3.js
---
.idea/.gitignore | 8 +
.idea/kaiaulu_react.iml | 9 ++
.idea/misc.xml | 6 +
.idea/modules.xml | 8 +
.idea/vcs.xml | 6 +
client/package.json | 1 +
client/pnpm-lock.yaml | 324 ++++++++++++++++++++++++++++++++++++++++
7 files changed, 362 insertions(+)
create mode 100644 .idea/.gitignore
create mode 100644 .idea/kaiaulu_react.iml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/modules.xml
create mode 100644 .idea/vcs.xml
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/kaiaulu_react.iml b/.idea/kaiaulu_react.iml
new file mode 100644
index 0000000..d6ebd48
--- /dev/null
+++ b/.idea/kaiaulu_react.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..639900d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..cdedb33
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/package.json b/client/package.json
index d540c6a..795cd07 100644
--- a/client/package.json
+++ b/client/package.json
@@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
+ "d3": "^7.9.0",
"react": "^19.1.1",
"react-dom": "^19.1.1"
},
diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml
index 13e65e4..65bf71d 100644
--- a/client/pnpm-lock.yaml
+++ b/client/pnpm-lock.yaml
@@ -8,6 +8,9 @@ importers:
.:
dependencies:
+ d3:
+ specifier: ^7.9.0
+ version: 7.9.0
react:
specifier: ^19.1.1
version: 19.1.1
@@ -627,6 +630,10 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ commander@7.2.0:
+ resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
+ engines: {node: '>= 10'}
+
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@@ -640,6 +647,133 @@ packages:
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+ d3-array@3.2.4:
+ resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
+ engines: {node: '>=12'}
+
+ d3-axis@3.0.0:
+ resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==}
+ engines: {node: '>=12'}
+
+ d3-brush@3.0.0:
+ resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==}
+ engines: {node: '>=12'}
+
+ d3-chord@3.0.1:
+ resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==}
+ engines: {node: '>=12'}
+
+ d3-color@3.1.0:
+ resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
+ engines: {node: '>=12'}
+
+ d3-contour@4.0.2:
+ resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==}
+ engines: {node: '>=12'}
+
+ d3-delaunay@6.0.4:
+ resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==}
+ engines: {node: '>=12'}
+
+ d3-dispatch@3.0.1:
+ resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==}
+ engines: {node: '>=12'}
+
+ d3-drag@3.0.0:
+ resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==}
+ engines: {node: '>=12'}
+
+ d3-dsv@3.0.1:
+ resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==}
+ engines: {node: '>=12'}
+ hasBin: true
+
+ d3-ease@3.0.1:
+ resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
+ engines: {node: '>=12'}
+
+ d3-fetch@3.0.1:
+ resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==}
+ engines: {node: '>=12'}
+
+ d3-force@3.0.0:
+ resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==}
+ engines: {node: '>=12'}
+
+ d3-format@3.1.0:
+ resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
+ engines: {node: '>=12'}
+
+ d3-geo@3.1.1:
+ resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==}
+ engines: {node: '>=12'}
+
+ d3-hierarchy@3.1.2:
+ resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==}
+ engines: {node: '>=12'}
+
+ d3-interpolate@3.0.1:
+ resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
+ engines: {node: '>=12'}
+
+ d3-path@3.1.0:
+ resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==}
+ engines: {node: '>=12'}
+
+ d3-polygon@3.0.1:
+ resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==}
+ engines: {node: '>=12'}
+
+ d3-quadtree@3.0.1:
+ resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==}
+ engines: {node: '>=12'}
+
+ d3-random@3.0.1:
+ resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==}
+ engines: {node: '>=12'}
+
+ d3-scale-chromatic@3.1.0:
+ resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==}
+ engines: {node: '>=12'}
+
+ d3-scale@4.0.2:
+ resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
+ engines: {node: '>=12'}
+
+ d3-selection@3.0.0:
+ resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==}
+ engines: {node: '>=12'}
+
+ d3-shape@3.2.0:
+ resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
+ engines: {node: '>=12'}
+
+ d3-time-format@4.1.0:
+ resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
+ engines: {node: '>=12'}
+
+ d3-time@3.1.0:
+ resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
+ engines: {node: '>=12'}
+
+ d3-timer@3.0.1:
+ resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
+ engines: {node: '>=12'}
+
+ d3-transition@3.0.1:
+ resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ d3-selection: 2 - 3
+
+ d3-zoom@3.0.0:
+ resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==}
+ engines: {node: '>=12'}
+
+ d3@7.9.0:
+ resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==}
+ engines: {node: '>=12'}
+
debug@4.4.1:
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
engines: {node: '>=6.0'}
@@ -652,6 +786,9 @@ packages:
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+ delaunator@5.0.1:
+ resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==}
+
electron-to-chromium@1.5.215:
resolution: {integrity: sha512-TIvGp57UpeNetj/wV/xpFNpWGb0b/ROw372lHPx5Aafx02gjTBtWnEEcaSX3W2dLM3OSdGGyHX/cHl01JQsLaQ==}
@@ -797,6 +934,10 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
+ iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -813,6 +954,10 @@ packages:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
+ internmap@2.0.3:
+ resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
+ engines: {node: '>=12'}
+
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@@ -971,6 +1116,9 @@ packages:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ robust-predicates@3.0.2:
+ resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==}
+
rollup@4.50.1:
resolution: {integrity: sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@@ -979,6 +1127,12 @@ packages:
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ rw@1.3.3:
+ resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
scheduler@0.26.0:
resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
@@ -1643,6 +1797,8 @@ snapshots:
color-name@1.1.4: {}
+ commander@7.2.0: {}
+
concat-map@0.0.1: {}
convert-source-map@2.0.0: {}
@@ -1655,12 +1811,168 @@ snapshots:
csstype@3.1.3: {}
+ d3-array@3.2.4:
+ dependencies:
+ internmap: 2.0.3
+
+ d3-axis@3.0.0: {}
+
+ d3-brush@3.0.0:
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-drag: 3.0.0
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-transition: 3.0.1(d3-selection@3.0.0)
+
+ d3-chord@3.0.1:
+ dependencies:
+ d3-path: 3.1.0
+
+ d3-color@3.1.0: {}
+
+ d3-contour@4.0.2:
+ dependencies:
+ d3-array: 3.2.4
+
+ d3-delaunay@6.0.4:
+ dependencies:
+ delaunator: 5.0.1
+
+ d3-dispatch@3.0.1: {}
+
+ d3-drag@3.0.0:
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-selection: 3.0.0
+
+ d3-dsv@3.0.1:
+ dependencies:
+ commander: 7.2.0
+ iconv-lite: 0.6.3
+ rw: 1.3.3
+
+ d3-ease@3.0.1: {}
+
+ d3-fetch@3.0.1:
+ dependencies:
+ d3-dsv: 3.0.1
+
+ d3-force@3.0.0:
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-quadtree: 3.0.1
+ d3-timer: 3.0.1
+
+ d3-format@3.1.0: {}
+
+ d3-geo@3.1.1:
+ dependencies:
+ d3-array: 3.2.4
+
+ d3-hierarchy@3.1.2: {}
+
+ d3-interpolate@3.0.1:
+ dependencies:
+ d3-color: 3.1.0
+
+ d3-path@3.1.0: {}
+
+ d3-polygon@3.0.1: {}
+
+ d3-quadtree@3.0.1: {}
+
+ d3-random@3.0.1: {}
+
+ d3-scale-chromatic@3.1.0:
+ dependencies:
+ d3-color: 3.1.0
+ d3-interpolate: 3.0.1
+
+ d3-scale@4.0.2:
+ dependencies:
+ d3-array: 3.2.4
+ d3-format: 3.1.0
+ d3-interpolate: 3.0.1
+ d3-time: 3.1.0
+ d3-time-format: 4.1.0
+
+ d3-selection@3.0.0: {}
+
+ d3-shape@3.2.0:
+ dependencies:
+ d3-path: 3.1.0
+
+ d3-time-format@4.1.0:
+ dependencies:
+ d3-time: 3.1.0
+
+ d3-time@3.1.0:
+ dependencies:
+ d3-array: 3.2.4
+
+ d3-timer@3.0.1: {}
+
+ d3-transition@3.0.1(d3-selection@3.0.0):
+ dependencies:
+ d3-color: 3.1.0
+ d3-dispatch: 3.0.1
+ d3-ease: 3.0.1
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-timer: 3.0.1
+
+ d3-zoom@3.0.0:
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-drag: 3.0.0
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-transition: 3.0.1(d3-selection@3.0.0)
+
+ d3@7.9.0:
+ dependencies:
+ d3-array: 3.2.4
+ d3-axis: 3.0.0
+ d3-brush: 3.0.0
+ d3-chord: 3.0.1
+ d3-color: 3.1.0
+ d3-contour: 4.0.2
+ d3-delaunay: 6.0.4
+ d3-dispatch: 3.0.1
+ d3-drag: 3.0.0
+ d3-dsv: 3.0.1
+ d3-ease: 3.0.1
+ d3-fetch: 3.0.1
+ d3-force: 3.0.0
+ d3-format: 3.1.0
+ d3-geo: 3.1.1
+ d3-hierarchy: 3.1.2
+ d3-interpolate: 3.0.1
+ d3-path: 3.1.0
+ d3-polygon: 3.0.1
+ d3-quadtree: 3.0.1
+ d3-random: 3.0.1
+ d3-scale: 4.0.2
+ d3-scale-chromatic: 3.1.0
+ d3-selection: 3.0.0
+ d3-shape: 3.2.0
+ d3-time: 3.1.0
+ d3-time-format: 4.1.0
+ d3-timer: 3.0.1
+ d3-transition: 3.0.1(d3-selection@3.0.0)
+ d3-zoom: 3.0.0
+
debug@4.4.1:
dependencies:
ms: 2.1.3
deep-is@0.1.4: {}
+ delaunator@5.0.1:
+ dependencies:
+ robust-predicates: 3.0.2
+
electron-to-chromium@1.5.215: {}
esbuild@0.25.9:
@@ -1834,6 +2146,10 @@ snapshots:
has-flag@4.0.0: {}
+ iconv-lite@0.6.3:
+ dependencies:
+ safer-buffer: 2.1.2
+
ignore@5.3.2: {}
ignore@7.0.5: {}
@@ -1845,6 +2161,8 @@ snapshots:
imurmurhash@0.1.4: {}
+ internmap@2.0.3: {}
+
is-extglob@2.1.1: {}
is-glob@4.0.3:
@@ -1969,6 +2287,8 @@ snapshots:
reusify@1.1.0: {}
+ robust-predicates@3.0.2: {}
+
rollup@4.50.1:
dependencies:
'@types/estree': 1.0.8
@@ -2000,6 +2320,10 @@ snapshots:
dependencies:
queue-microtask: 1.2.3
+ rw@1.3.3: {}
+
+ safer-buffer@2.1.2: {}
+
scheduler@0.26.0: {}
semver@6.3.1: {}
From 59b3b8aa9e76bef68ebd0081dc396d7dd5d7f5d5 Mon Sep 17 00:00:00 2001
From: austindang67 <122927862+austindang67@users.noreply.github.com>
Date: Fri, 26 Sep 2025 13:43:55 -1000
Subject: [PATCH 03/29] Established page with working network graph.
---
client/package.json | 1 +
client/pnpm-lock.yaml | 218 ++++++++++++++++++
client/public/sample-data.json | 93 ++++++++
client/src/App.css | 40 ----
client/src/App.tsx | 26 +--
.../components/NetworkGraph/NetworkGraph.css | 3 +
.../components/NetworkGraph/NetworkGraph.tsx | 63 +++++
client/src/components/NetworkGraph/index.ts | 1 +
client/src/hooks/useDummyData.ts | 25 ++
client/src/index.css | 65 ------
10 files changed, 406 insertions(+), 129 deletions(-)
create mode 100644 client/public/sample-data.json
create mode 100644 client/src/components/NetworkGraph/NetworkGraph.css
create mode 100644 client/src/components/NetworkGraph/NetworkGraph.tsx
create mode 100644 client/src/components/NetworkGraph/index.ts
create mode 100644 client/src/hooks/useDummyData.ts
diff --git a/client/package.json b/client/package.json
index 795cd07..a116546 100644
--- a/client/package.json
+++ b/client/package.json
@@ -16,6 +16,7 @@
},
"devDependencies": {
"@eslint/js": "^9.33.0",
+ "@types/d3": "^7.4.3",
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"@vitejs/plugin-react": "^5.0.0",
diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml
index 65bf71d..6265c60 100644
--- a/client/pnpm-lock.yaml
+++ b/client/pnpm-lock.yaml
@@ -21,6 +21,9 @@ importers:
'@eslint/js':
specifier: ^9.33.0
version: 9.35.0
+ '@types/d3':
+ specifier: ^7.4.3
+ version: 7.4.3
'@types/react':
specifier: ^19.1.10
version: 19.1.12
@@ -495,9 +498,105 @@ packages:
'@types/babel__traverse@7.28.0':
resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
+ '@types/d3-array@3.2.2':
+ resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
+
+ '@types/d3-axis@3.0.6':
+ resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==}
+
+ '@types/d3-brush@3.0.6':
+ resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==}
+
+ '@types/d3-chord@3.0.6':
+ resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==}
+
+ '@types/d3-color@3.1.3':
+ resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
+
+ '@types/d3-contour@3.0.6':
+ resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==}
+
+ '@types/d3-delaunay@6.0.4':
+ resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==}
+
+ '@types/d3-dispatch@3.0.7':
+ resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==}
+
+ '@types/d3-drag@3.0.7':
+ resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==}
+
+ '@types/d3-dsv@3.0.7':
+ resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==}
+
+ '@types/d3-ease@3.0.2':
+ resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==}
+
+ '@types/d3-fetch@3.0.7':
+ resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==}
+
+ '@types/d3-force@3.0.10':
+ resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==}
+
+ '@types/d3-format@3.0.4':
+ resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==}
+
+ '@types/d3-geo@3.1.0':
+ resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==}
+
+ '@types/d3-hierarchy@3.1.7':
+ resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==}
+
+ '@types/d3-interpolate@3.0.4':
+ resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
+
+ '@types/d3-path@3.1.1':
+ resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==}
+
+ '@types/d3-polygon@3.0.2':
+ resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==}
+
+ '@types/d3-quadtree@3.0.6':
+ resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==}
+
+ '@types/d3-random@3.0.3':
+ resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==}
+
+ '@types/d3-scale-chromatic@3.1.0':
+ resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==}
+
+ '@types/d3-scale@4.0.9':
+ resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==}
+
+ '@types/d3-selection@3.0.11':
+ resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==}
+
+ '@types/d3-shape@3.1.7':
+ resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==}
+
+ '@types/d3-time-format@4.0.3':
+ resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==}
+
+ '@types/d3-time@3.0.4':
+ resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==}
+
+ '@types/d3-timer@3.0.2':
+ resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
+
+ '@types/d3-transition@3.0.9':
+ resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==}
+
+ '@types/d3-zoom@3.0.8':
+ resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==}
+
+ '@types/d3@7.4.3':
+ resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==}
+
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+ '@types/geojson@7946.0.16':
+ resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==}
+
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@@ -1624,8 +1723,127 @@ snapshots:
dependencies:
'@babel/types': 7.28.4
+ '@types/d3-array@3.2.2': {}
+
+ '@types/d3-axis@3.0.6':
+ dependencies:
+ '@types/d3-selection': 3.0.11
+
+ '@types/d3-brush@3.0.6':
+ dependencies:
+ '@types/d3-selection': 3.0.11
+
+ '@types/d3-chord@3.0.6': {}
+
+ '@types/d3-color@3.1.3': {}
+
+ '@types/d3-contour@3.0.6':
+ dependencies:
+ '@types/d3-array': 3.2.2
+ '@types/geojson': 7946.0.16
+
+ '@types/d3-delaunay@6.0.4': {}
+
+ '@types/d3-dispatch@3.0.7': {}
+
+ '@types/d3-drag@3.0.7':
+ dependencies:
+ '@types/d3-selection': 3.0.11
+
+ '@types/d3-dsv@3.0.7': {}
+
+ '@types/d3-ease@3.0.2': {}
+
+ '@types/d3-fetch@3.0.7':
+ dependencies:
+ '@types/d3-dsv': 3.0.7
+
+ '@types/d3-force@3.0.10': {}
+
+ '@types/d3-format@3.0.4': {}
+
+ '@types/d3-geo@3.1.0':
+ dependencies:
+ '@types/geojson': 7946.0.16
+
+ '@types/d3-hierarchy@3.1.7': {}
+
+ '@types/d3-interpolate@3.0.4':
+ dependencies:
+ '@types/d3-color': 3.1.3
+
+ '@types/d3-path@3.1.1': {}
+
+ '@types/d3-polygon@3.0.2': {}
+
+ '@types/d3-quadtree@3.0.6': {}
+
+ '@types/d3-random@3.0.3': {}
+
+ '@types/d3-scale-chromatic@3.1.0': {}
+
+ '@types/d3-scale@4.0.9':
+ dependencies:
+ '@types/d3-time': 3.0.4
+
+ '@types/d3-selection@3.0.11': {}
+
+ '@types/d3-shape@3.1.7':
+ dependencies:
+ '@types/d3-path': 3.1.1
+
+ '@types/d3-time-format@4.0.3': {}
+
+ '@types/d3-time@3.0.4': {}
+
+ '@types/d3-timer@3.0.2': {}
+
+ '@types/d3-transition@3.0.9':
+ dependencies:
+ '@types/d3-selection': 3.0.11
+
+ '@types/d3-zoom@3.0.8':
+ dependencies:
+ '@types/d3-interpolate': 3.0.4
+ '@types/d3-selection': 3.0.11
+
+ '@types/d3@7.4.3':
+ dependencies:
+ '@types/d3-array': 3.2.2
+ '@types/d3-axis': 3.0.6
+ '@types/d3-brush': 3.0.6
+ '@types/d3-chord': 3.0.6
+ '@types/d3-color': 3.1.3
+ '@types/d3-contour': 3.0.6
+ '@types/d3-delaunay': 6.0.4
+ '@types/d3-dispatch': 3.0.7
+ '@types/d3-drag': 3.0.7
+ '@types/d3-dsv': 3.0.7
+ '@types/d3-ease': 3.0.2
+ '@types/d3-fetch': 3.0.7
+ '@types/d3-force': 3.0.10
+ '@types/d3-format': 3.0.4
+ '@types/d3-geo': 3.1.0
+ '@types/d3-hierarchy': 3.1.7
+ '@types/d3-interpolate': 3.0.4
+ '@types/d3-path': 3.1.1
+ '@types/d3-polygon': 3.0.2
+ '@types/d3-quadtree': 3.0.6
+ '@types/d3-random': 3.0.3
+ '@types/d3-scale': 4.0.9
+ '@types/d3-scale-chromatic': 3.1.0
+ '@types/d3-selection': 3.0.11
+ '@types/d3-shape': 3.1.7
+ '@types/d3-time': 3.0.4
+ '@types/d3-time-format': 4.0.3
+ '@types/d3-timer': 3.0.2
+ '@types/d3-transition': 3.0.9
+ '@types/d3-zoom': 3.0.8
+
'@types/estree@1.0.8': {}
+ '@types/geojson@7946.0.16': {}
+
'@types/json-schema@7.0.15': {}
'@types/react-dom@19.1.9(@types/react@19.1.12)':
diff --git a/client/public/sample-data.json b/client/public/sample-data.json
new file mode 100644
index 0000000..5340d4a
--- /dev/null
+++ b/client/public/sample-data.json
@@ -0,0 +1,93 @@
+{
+ "nodes": [
+ {
+ "id": 1,
+ "name": "A"
+ },
+ {
+ "id": 2,
+ "name": "B"
+ },
+ {
+ "id": 3,
+ "name": "C"
+ },
+ {
+ "id": 4,
+ "name": "D"
+ },
+ {
+ "id": 5,
+ "name": "E"
+ },
+ {
+ "id": 6,
+ "name": "F"
+ },
+ {
+ "id": 7,
+ "name": "G"
+ },
+ {
+ "id": 8,
+ "name": "H"
+ },
+ {
+ "id": 9,
+ "name": "I"
+ },
+ {
+ "id": 10,
+ "name": "J"
+ }
+ ],
+ "links": [
+
+ {
+ "source": 1,
+ "target": 2
+ },
+ {
+ "source": 1,
+ "target": 5
+ },
+ {
+ "source": 1,
+ "target": 6
+ },
+
+ {
+ "source": 2,
+ "target": 3
+ },
+ {
+ "source": 2,
+ "target": 7
+ }
+ ,
+
+ {
+ "source": 3,
+ "target": 4
+ },
+ {
+ "source": 8,
+ "target": 3
+ }
+ ,
+ {
+ "source": 4,
+ "target": 5
+ }
+ ,
+
+ {
+ "source": 4,
+ "target": 9
+ },
+ {
+ "source": 5,
+ "target": 10
+ }
+ ]
+}
\ No newline at end of file
diff --git a/client/src/App.css b/client/src/App.css
index b9d355d..6ffc97a 100644
--- a/client/src/App.css
+++ b/client/src/App.css
@@ -1,42 +1,2 @@
#root {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
- text-align: center;
-}
-
-.logo {
- height: 6em;
- padding: 1.5em;
- will-change: filter;
- transition: filter 300ms;
-}
-.logo:hover {
- filter: drop-shadow(0 0 2em #646cffaa);
-}
-.logo.react:hover {
- filter: drop-shadow(0 0 2em #61dafbaa);
-}
-
-@keyframes logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-
-@media (prefers-reduced-motion: no-preference) {
- a:nth-of-type(2) .logo {
- animation: logo-spin infinite 20s linear;
- }
-}
-
-.card {
- padding: 2em;
-}
-
-.read-the-docs {
- color: #888;
}
diff --git a/client/src/App.tsx b/client/src/App.tsx
index 3d7ded3..5ef47eb 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -1,33 +1,11 @@
-import { useState } from 'react'
-import reactLogo from './assets/react.svg'
-import viteLogo from '/vite.svg'
+import { NetworkGraph } from "./components/NetworkGraph";
import './App.css'
function App() {
- const [count, setCount] = useState(0)
return (
<>
-
- Vite + React
-
-
-
- Edit src/App.tsx and save to test HMR
-
-
-
- Click on the Vite and React logos to learn more
-
+
>
)
}
diff --git a/client/src/components/NetworkGraph/NetworkGraph.css b/client/src/components/NetworkGraph/NetworkGraph.css
new file mode 100644
index 0000000..9edf5ad
--- /dev/null
+++ b/client/src/components/NetworkGraph/NetworkGraph.css
@@ -0,0 +1,3 @@
+.networkGraph {
+
+}
\ No newline at end of file
diff --git a/client/src/components/NetworkGraph/NetworkGraph.tsx b/client/src/components/NetworkGraph/NetworkGraph.tsx
new file mode 100644
index 0000000..36d1217
--- /dev/null
+++ b/client/src/components/NetworkGraph/NetworkGraph.tsx
@@ -0,0 +1,63 @@
+import {useEffect, useRef } from 'react';
+import * as d3 from "d3";
+import { useDummyData } from "../../hooks/useDummyData.ts";
+import './NetworkGraph.css';
+
+export const NetworkGraph = () => {
+ const graphContainer = useRef(null);
+ const { data } = useDummyData();
+
+ useEffect(() => {
+ if (data != null) {
+ if (graphContainer.current) {
+ const svg = d3.select(graphContainer.current)
+ .append("svg")
+ .attr("width", 1500)
+ .attr("height", 1500)
+ .append("g")
+ .attr("transform",
+ "translate(" + 100 + "," + 100 + ")");
+
+
+ var link = svg.selectAll("line")
+ .data(data.links)
+ .enter()
+ .append("line")
+ .style("stroke", "#aaa");
+
+ var node = svg
+ .selectAll("circle")
+ .data(data.nodes)
+ .enter()
+ .append("circle")
+ .attr("r", 20)
+ .style("fill", "#69b3a2");
+
+ var simulation = d3.forceSimulation(data.nodes).force("link", d3.forceLink()
+ .id(function(d) {return d.id; }).links(data.links))
+ .force("charge", d3.forceManyBody().strength(-400))
+ .force("center", d3.forceCenter(750, 750))
+ .on("end", ticked);
+
+ function ticked() {
+ link
+ .attr("x1", function(d) { return d.source.x; })
+ .attr("y1", function(d) { return d.source.y; })
+ .attr("x2", function(d) { return d.target.x; })
+ .attr("y2", function(d) { return d.target.y; });
+
+ node
+ .attr("cx", function (d) { return d.x+6; })
+ .attr("cy", function(d) { return d.y-6; });
+ }
+ }
+ }
+ }, [data]);
+
+ return (
+
+
+
+ )
+
+}
\ No newline at end of file
diff --git a/client/src/components/NetworkGraph/index.ts b/client/src/components/NetworkGraph/index.ts
new file mode 100644
index 0000000..d761ad5
--- /dev/null
+++ b/client/src/components/NetworkGraph/index.ts
@@ -0,0 +1 @@
+export * from './NetworkGraph';
\ No newline at end of file
diff --git a/client/src/hooks/useDummyData.ts b/client/src/hooks/useDummyData.ts
new file mode 100644
index 0000000..0d22a3f
--- /dev/null
+++ b/client/src/hooks/useDummyData.ts
@@ -0,0 +1,25 @@
+import * as d3 from "d3";
+import { useEffect, useState } from "react";
+
+export function useDummyData() {
+ const [data, setData] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ let ignore = false;
+ (async () => {
+ try {
+ const json = await d3.json("/sample-data.json");
+ if (!ignore) setData(json ?? null);
+ } catch (e: any) {
+ if (!ignore) setError(e?.message ?? "Failed to load data");
+ } finally {
+ if (!ignore) setLoading(false);
+ }
+ })();
+ return () => { ignore = true; };
+ }, []);
+
+ return { data, loading, error };
+}
diff --git a/client/src/index.css b/client/src/index.css
index 08a3ac9..5b81229 100644
--- a/client/src/index.css
+++ b/client/src/index.css
@@ -1,68 +1,3 @@
:root {
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
-
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
-}
-a:hover {
- color: #535bf2;
-}
-
-body {
- margin: 0;
display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
-}
-
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
-}
-
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
}
From cb045602a818a3dbd6ccb1c2c3472049494af7db Mon Sep 17 00:00:00 2001
From: austindang67 <122927862+austindang67@users.noreply.github.com>
Date: Fri, 26 Sep 2025 13:57:41 -1000
Subject: [PATCH 04/29] Slight tweaks for presentation purposes
---
client/src/components/NetworkGraph/NetworkGraph.css | 6 ++++--
client/src/components/NetworkGraph/NetworkGraph.tsx | 6 +-----
client/src/index.css | 2 +-
3 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/client/src/components/NetworkGraph/NetworkGraph.css b/client/src/components/NetworkGraph/NetworkGraph.css
index 9edf5ad..3c8ef93 100644
--- a/client/src/components/NetworkGraph/NetworkGraph.css
+++ b/client/src/components/NetworkGraph/NetworkGraph.css
@@ -1,3 +1,5 @@
-.networkGraph {
-
+#networkGraph {
+ display: flex;
+ max-height: 750px;
+ max-width: 1500px;
}
\ No newline at end of file
diff --git a/client/src/components/NetworkGraph/NetworkGraph.tsx b/client/src/components/NetworkGraph/NetworkGraph.tsx
index 36d1217..e8fd556 100644
--- a/client/src/components/NetworkGraph/NetworkGraph.tsx
+++ b/client/src/components/NetworkGraph/NetworkGraph.tsx
@@ -13,10 +13,7 @@ export const NetworkGraph = () => {
const svg = d3.select(graphContainer.current)
.append("svg")
.attr("width", 1500)
- .attr("height", 1500)
- .append("g")
- .attr("transform",
- "translate(" + 100 + "," + 100 + ")");
+ .attr("height",1500);
var link = svg.selectAll("line")
@@ -56,7 +53,6 @@ export const NetworkGraph = () => {
return (
-
)
diff --git a/client/src/index.css b/client/src/index.css
index 5b81229..618efd6 100644
--- a/client/src/index.css
+++ b/client/src/index.css
@@ -1,3 +1,3 @@
:root {
- display: flex;
+ background-color: #242424;
}
From 74aa340e9e53cf0d94b998cd15f040900ec8c281 Mon Sep 17 00:00:00 2001
From: austindang67 <122927862+austindang67@users.noreply.github.com>
Date: Fri, 3 Oct 2025 00:45:06 -1000
Subject: [PATCH 05/29] Added more networks. Improved project structure.
Created app router.
---
client/package.json | 3 +-
client/pnpm-lock.yaml | 45 ++++++++
client/src/App.css | 8 +-
client/src/App.tsx | 14 ++-
client/src/components/Header/Header.css | 7 ++
client/src/components/Header/Header.tsx | 11 ++
client/src/components/Header/index.ts | 1 +
.../components/NetworkGraph/NetworkGraph.css | 10 +-
.../components/NetworkGraph/NetworkGraph.tsx | 108 ++++++++++--------
client/src/components/NetworkGraph/types.ts | 5 +
client/src/data/dummy-data.ts | 42 +++++++
client/src/index.css | 6 +-
client/src/layout/AppLayout.css | 9 ++
client/src/layout/AppLayout.tsx | 14 +++
client/src/main.tsx | 12 +-
client/src/pages/Landing.tsx | 12 ++
client/src/types/network-graph.types.ts | 14 +++
17 files changed, 257 insertions(+), 64 deletions(-)
create mode 100644 client/src/components/Header/Header.css
create mode 100644 client/src/components/Header/Header.tsx
create mode 100644 client/src/components/Header/index.ts
create mode 100644 client/src/components/NetworkGraph/types.ts
create mode 100644 client/src/data/dummy-data.ts
create mode 100644 client/src/layout/AppLayout.css
create mode 100644 client/src/layout/AppLayout.tsx
create mode 100644 client/src/pages/Landing.tsx
create mode 100644 client/src/types/network-graph.types.ts
diff --git a/client/package.json b/client/package.json
index a116546..c7ce3c5 100644
--- a/client/package.json
+++ b/client/package.json
@@ -12,7 +12,8 @@
"dependencies": {
"d3": "^7.9.0",
"react": "^19.1.1",
- "react-dom": "^19.1.1"
+ "react-dom": "^19.1.1",
+ "react-router-dom": "^7.9.3"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml
index 6265c60..385a106 100644
--- a/client/pnpm-lock.yaml
+++ b/client/pnpm-lock.yaml
@@ -17,6 +17,9 @@ importers:
react-dom:
specifier: ^19.1.1
version: 19.1.1(react@19.1.1)
+ react-router-dom:
+ specifier: ^7.9.3
+ version: 7.9.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
devDependencies:
'@eslint/js':
specifier: ^9.33.0
@@ -739,6 +742,10 @@ packages:
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+ cookie@1.0.2:
+ resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
+ engines: {node: '>=18'}
+
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@@ -1203,6 +1210,23 @@ packages:
resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
engines: {node: '>=0.10.0'}
+ react-router-dom@7.9.3:
+ resolution: {integrity: sha512-1QSbA0TGGFKTAc/aWjpfW/zoEukYfU4dc1dLkT/vvf54JoGMkW+fNA+3oyo2gWVW1GM7BxjJVHz5GnPJv40rvg==}
+ engines: {node: '>=20.0.0'}
+ peerDependencies:
+ react: '>=18'
+ react-dom: '>=18'
+
+ react-router@7.9.3:
+ resolution: {integrity: sha512-4o2iWCFIwhI/eYAIL43+cjORXYn/aRQPgtFRRZb3VzoyQ5Uej0Bmqj7437L97N9NJW4wnicSwLOLS+yCXfAPgg==}
+ engines: {node: '>=20.0.0'}
+ peerDependencies:
+ react: '>=18'
+ react-dom: '>=18'
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+
react@19.1.1:
resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==}
engines: {node: '>=0.10.0'}
@@ -1244,6 +1268,9 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ set-cookie-parser@2.7.1:
+ resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
+
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@@ -2021,6 +2048,8 @@ snapshots:
convert-source-map@2.0.0: {}
+ cookie@1.0.2: {}
+
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
@@ -2499,6 +2528,20 @@ snapshots:
react-refresh@0.17.0: {}
+ react-router-dom@7.9.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
+ dependencies:
+ react: 19.1.1
+ react-dom: 19.1.1(react@19.1.1)
+ react-router: 7.9.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+
+ react-router@7.9.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
+ dependencies:
+ cookie: 1.0.2
+ react: 19.1.1
+ set-cookie-parser: 2.7.1
+ optionalDependencies:
+ react-dom: 19.1.1(react@19.1.1)
+
react@19.1.1: {}
resolve-from@4.0.0: {}
@@ -2548,6 +2591,8 @@ snapshots:
semver@7.7.2: {}
+ set-cookie-parser@2.7.1: {}
+
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
diff --git a/client/src/App.css b/client/src/App.css
index 6ffc97a..639cb8d 100644
--- a/client/src/App.css
+++ b/client/src/App.css
@@ -1,2 +1,8 @@
-#root {
+html, body, #root {
+ height: 100%;
+}
+
+html, body {
+ margin: 0; /* kills the 8px white border */
+ padding: 0;
}
diff --git a/client/src/App.tsx b/client/src/App.tsx
index 5ef47eb..14c9967 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -1,11 +1,21 @@
-import { NetworkGraph } from "./components/NetworkGraph";
+import { lazy, Suspense } from "react";
+import { Route, Routes } from "react-router-dom";
import './App.css'
+import AppLayout from "./layout/AppLayout.tsx";
+
+const Landing = lazy(() => import("./pages/Landing"));
function App() {
return (
<>
-
+
+
+ }>
+ } />
+
+
+
>
)
}
diff --git a/client/src/components/Header/Header.css b/client/src/components/Header/Header.css
new file mode 100644
index 0000000..0ebb239
--- /dev/null
+++ b/client/src/components/Header/Header.css
@@ -0,0 +1,7 @@
+#header {
+ font-size: 50px;
+ justify-content: center;
+ min-height: 15vh;
+ display: flex;
+ align-items: center;
+}
\ No newline at end of file
diff --git a/client/src/components/Header/Header.tsx b/client/src/components/Header/Header.tsx
new file mode 100644
index 0000000..35eeaac
--- /dev/null
+++ b/client/src/components/Header/Header.tsx
@@ -0,0 +1,11 @@
+import "./Header.css";
+
+export const Header = () => {
+ return (
+ <>
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/client/src/components/Header/index.ts b/client/src/components/Header/index.ts
new file mode 100644
index 0000000..64f7c87
--- /dev/null
+++ b/client/src/components/Header/index.ts
@@ -0,0 +1 @@
+export * from './Header';
\ No newline at end of file
diff --git a/client/src/components/NetworkGraph/NetworkGraph.css b/client/src/components/NetworkGraph/NetworkGraph.css
index 3c8ef93..09832bd 100644
--- a/client/src/components/NetworkGraph/NetworkGraph.css
+++ b/client/src/components/NetworkGraph/NetworkGraph.css
@@ -1,5 +1,9 @@
#networkGraph {
display: flex;
- max-height: 750px;
- max-width: 1500px;
-}
\ No newline at end of file
+ justify-content: center;
+ overflow: auto;
+}
+
+#graphCanvas {
+ display: block;
+}
diff --git a/client/src/components/NetworkGraph/NetworkGraph.tsx b/client/src/components/NetworkGraph/NetworkGraph.tsx
index e8fd556..e93df7b 100644
--- a/client/src/components/NetworkGraph/NetworkGraph.tsx
+++ b/client/src/components/NetworkGraph/NetworkGraph.tsx
@@ -1,59 +1,67 @@
-import {useEffect, useRef } from 'react';
-import * as d3 from "d3";
-import { useDummyData } from "../../hooks/useDummyData.ts";
+import { useRef, useEffect } from 'react';
import './NetworkGraph.css';
+import * as d3 from "d3";
+import type { Link, Node } from "../../types/network-graph.types.ts";
+import type { NetworkGraphProps } from "./types.ts";
+
+export const NetworkGraph = ({ data } : NetworkGraphProps ) => {
+ const canvasRef = useRef(null);
+ const links: Link[] = data.links.map((d) => ({ ...d }));
+ const nodes: Node[] = data.nodes.map((d) => ({ ...d }));
-export const NetworkGraph = () => {
- const graphContainer = useRef(null);
- const { data } = useDummyData();
+ const width = 400;
+ const height = 400;
+ const radius = 10;
useEffect(() => {
- if (data != null) {
- if (graphContainer.current) {
- const svg = d3.select(graphContainer.current)
- .append("svg")
- .attr("width", 1500)
- .attr("height",1500);
-
-
- var link = svg.selectAll("line")
- .data(data.links)
- .enter()
- .append("line")
- .style("stroke", "#aaa");
-
- var node = svg
- .selectAll("circle")
- .data(data.nodes)
- .enter()
- .append("circle")
- .attr("r", 20)
- .style("fill", "#69b3a2");
-
- var simulation = d3.forceSimulation(data.nodes).force("link", d3.forceLink()
- .id(function(d) {return d.id; }).links(data.links))
- .force("charge", d3.forceManyBody().strength(-400))
- .force("center", d3.forceCenter(750, 750))
- .on("end", ticked);
-
- function ticked() {
- link
- .attr("x1", function(d) { return d.source.x; })
- .attr("y1", function(d) { return d.source.y; })
- .attr("x2", function(d) { return d.target.x; })
- .attr("y2", function(d) { return d.target.y; });
-
- node
- .attr("cx", function (d) { return d.x+6; })
- .attr("cy", function(d) { return d.y-6; });
- }
- }
+ const canvas = canvasRef.current;
+ const context = canvas?.getContext("2d");
+
+ if (!context) {
+ return;
}
- }, [data]);
+
+ // run d3-force to find the position of nodes on the canvas
+ d3.forceSimulation(nodes)
+
+ // list of forces we apply to get node positions
+ .force(
+ 'link',
+ d3.forceLink(links).id((d) => d.id)
+ )
+ .force('collide', d3.forceCollide().radius(radius))
+ .force('charge', d3.forceManyBody())
+ .force('center', d3.forceCenter(width / 2, height / 2))
+
+ // at each iteration of the simulation, draw the network diagram with the new node positions
+ .on('tick', () => {
+ context.clearRect(0, 0, width, height);
+
+ links.forEach((link) => {
+ context.beginPath();
+ context.moveTo(link.source.x, link.source.y);
+ context.lineTo(link.target.x, link.target.y);
+ context.stroke();
+ context.strokeStyle = "white";
+ });
+
+ nodes.forEach((node) => {
+ if (!node.x || !node.y) {
+ return;
+ }
+
+ context.beginPath();
+ context.moveTo(node.x + radius, node.y);
+ context.arc(node.x, node.y, radius, 0, 2 * Math.PI);
+ context.fillStyle = 'white';
+ context.fill();
+ });
+ });
+ }, [nodes, links])
return (
-
-
+
+
+
)
-
}
\ No newline at end of file
diff --git a/client/src/components/NetworkGraph/types.ts b/client/src/components/NetworkGraph/types.ts
new file mode 100644
index 0000000..0208b9f
--- /dev/null
+++ b/client/src/components/NetworkGraph/types.ts
@@ -0,0 +1,5 @@
+import type { NetworkGraphData } from "../../types/network-graph.types.ts";
+
+export type NetworkGraphProps = {
+ data: NetworkGraphData;
+};
\ No newline at end of file
diff --git a/client/src/data/dummy-data.ts b/client/src/data/dummy-data.ts
new file mode 100644
index 0000000..1d03e24
--- /dev/null
+++ b/client/src/data/dummy-data.ts
@@ -0,0 +1,42 @@
+export const data = {
+ nodes: [
+ { id: 'Myriel', group: 'team1' },
+ { id: 'Anne', group: 'team1' },
+ { id: 'Gabriel', group: 'team1' },
+ { id: 'Mel', group: 'team1' },
+ { id: 'Yan', group: 'team2' },
+ { id: 'Tom', group: 'team2' },
+ { id: 'Cyril', group: 'team2' },
+ { id: 'Tuck', group: 'team2' },
+ { id: 'Antoine', group: 'team3' },
+ { id: 'Rob', group: 'team3' },
+ { id: 'Napoleon', group: 'team3' },
+ { id: 'Toto', group: 'team4' },
+ { id: 'Tutu', group: 'team4' },
+ { id: 'Titi', group: 'team4' },
+ { id: 'Tata', group: 'team4' },
+ { id: 'Turlututu', group: 'team4' },
+ { id: 'Tita', group: 'team4' },
+ ],
+ links: [
+ { source: 'Anne', target: 'Myriel', value: 1 },
+ { source: 'Napoleon', target: 'Myriel', value: 1 },
+ { source: 'Gabriel', target: 'Myriel', value: 1 },
+ { source: 'Mel', target: 'Myriel', value: 1 },
+ { source: 'Yan', target: 'Tom', value: 1 },
+ { source: 'Tom', target: 'Cyril', value: 1 },
+ { source: 'Tuck', target: 'Myriel', value: 1 },
+ { source: 'Tuck', target: 'Mel', value: 1 },
+ { source: 'Tuck', target: 'Myriel', value: 1 },
+ { source: 'Mel', target: 'Myriel', value: 1 },
+ { source: 'Rob', target: 'Antoine', value: 1 },
+ { source: 'Tata', target: 'Tutu', value: 1 },
+ { source: 'Tata', target: 'Titi', value: 1 },
+ { source: 'Tata', target: 'Toto', value: 1 },
+ { source: 'Tata', target: 'Tita', value: 1 },
+ { source: 'Tita', target: 'Toto', value: 1 },
+ { source: 'Tita', target: 'Titi', value: 1 },
+ { source: 'Tita', target: 'Turlututu', value: 1 },
+ { source: 'Rob', target: 'Turlututu', value: 1 },
+ ],
+};
\ No newline at end of file
diff --git a/client/src/index.css b/client/src/index.css
index 618efd6..b8252fb 100644
--- a/client/src/index.css
+++ b/client/src/index.css
@@ -1,3 +1,5 @@
-:root {
- background-color: #242424;
+#root {
+ display: flex;
+ flex-direction: column;
+ background-color: #242424;
}
diff --git a/client/src/layout/AppLayout.css b/client/src/layout/AppLayout.css
new file mode 100644
index 0000000..1253008
--- /dev/null
+++ b/client/src/layout/AppLayout.css
@@ -0,0 +1,9 @@
+#appContainer {
+ min-height: 100dvh; /* use dvh to avoid mobile 100vh bugs */
+ width: 100vw;
+ overflow: hidden; /* optional: hide scrollbars for full-bleed canvases */
+ display: flex; /* if you have header/footer layout */
+ flex-direction: column;
+ background-color: black;
+ color: white;
+}
\ No newline at end of file
diff --git a/client/src/layout/AppLayout.tsx b/client/src/layout/AppLayout.tsx
new file mode 100644
index 0000000..3f04eb3
--- /dev/null
+++ b/client/src/layout/AppLayout.tsx
@@ -0,0 +1,14 @@
+import { Outlet } from "react-router-dom";
+import { Header } from "../components/Header";
+import "./AppLayout.css";
+
+const AppLayout = () => {
+ return (
+
+
+
+
+ )
+}
+
+export default AppLayout;
\ No newline at end of file
diff --git a/client/src/main.tsx b/client/src/main.tsx
index bef5202..0bc4718 100644
--- a/client/src/main.tsx
+++ b/client/src/main.tsx
@@ -1,10 +1,12 @@
-import { StrictMode } from 'react'
-import { createRoot } from 'react-dom/client'
-import './index.css'
-import App from './App.tsx'
+import { StrictMode } from 'react';
+import { createRoot } from 'react-dom/client';
+import { BrowserRouter } from 'react-router-dom';
+import App from './App.tsx';
createRoot(document.getElementById('root')!).render(
-
+
+
+
,
)
diff --git a/client/src/pages/Landing.tsx b/client/src/pages/Landing.tsx
new file mode 100644
index 0000000..e5be076
--- /dev/null
+++ b/client/src/pages/Landing.tsx
@@ -0,0 +1,12 @@
+import { NetworkGraph} from "../components/NetworkGraph";
+import { data } from "../data/dummy-data.ts";
+
+const Landing = () => {
+ return (
+
+
+
+ )
+}
+
+export default Landing;
\ No newline at end of file
diff --git a/client/src/types/network-graph.types.ts b/client/src/types/network-graph.types.ts
new file mode 100644
index 0000000..edcbae2
--- /dev/null
+++ b/client/src/types/network-graph.types.ts
@@ -0,0 +1,14 @@
+import type { SimulationNodeDatum, SimulationLinkDatum } from "d3";
+
+export interface Node extends SimulationNodeDatum {
+ id: string;
+}
+
+export type Link = SimulationLinkDatum & {
+ value: number;
+};
+
+export type NetworkGraphData = {
+ nodes: Node[];
+ links: Link[];
+};
\ No newline at end of file
From 5e7bb9d71fd9a810ad508ac2d1c78a8c8867f7b8 Mon Sep 17 00:00:00 2001
From: austindang67 <122927862+austindang67@users.noreply.github.com>
Date: Fri, 3 Oct 2025 12:41:46 -1000
Subject: [PATCH 06/29] Implemented drag functionality for nodes
Nodes can now be dragged around.
---
client/public/kaiaulu_logo.png | Bin 0 -> 116342 bytes
client/src/components/Header/Header.css | 2 +-
client/src/components/Header/Header.tsx | 2 +-
.../components/NetworkGraph/NetworkGraph.tsx | 61 ++++++++++++++++--
client/src/layout/AppLayout.css | 2 +-
5 files changed, 58 insertions(+), 9 deletions(-)
create mode 100644 client/public/kaiaulu_logo.png
diff --git a/client/public/kaiaulu_logo.png b/client/public/kaiaulu_logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..d9127272ee6c89007123d0302be6b7544447883e
GIT binary patch
literal 116342
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