diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..1b8fc7a
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,4 @@
+node_modules
+dist
+npm-debug.log
+.DS_Store
diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz
index 5168102..4cce521 100644
Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ
diff --git a/Dockerfile b/Dockerfile
index bcea430..e8cec5c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -5,43 +5,19 @@ FROM node:22-bullseye AS builder
ARG API_BASE_URL="https://navigolabs.com/api"
-# Enable Corepack and Yarn 4
-RUN corepack enable && corepack prepare yarn@4.9.2 --activate
-
WORKDIR /app
-# Copy Yarn 4 files
-COPY package.json yarn.lock .yarnrc.yml ./
-COPY .yarn .yarn
+# Copy package.json and package-lock.json
+COPY package*.json ./
-# Install dependencies (immutable to match lockfile)
-RUN yarn install --immutable
+# Install ALL dependencies (including devDependencies)
+RUN npm install
-# Copy all source files
+# Copy source files
COPY . .
# Pass API URL to Vite
ENV VITE_API_BASE_URL=$API_BASE_URL
# Build the app
-RUN yarn build
-
-
-# ------------------------
-# Production stage
-# ------------------------
-FROM node:22-alpine AS production
-
-WORKDIR /app
-
-# Copy built files from builder stage
-COPY --from=builder /app/dist ./dist
-
-# Install a lightweight static server
-RUN npm install -g serve@14
-
-# Expose port (optional but recommended)
-EXPOSE 3000
-
-# Start the static server
-CMD ["serve", "-s", "dist", "-l", "3000"]
+RUN npm run build
diff --git a/package-lock.json b/package-lock.json
index 0d9481d..44423f3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,8 +8,15 @@
"name": "thekalawati",
"version": "0.0.0",
"dependencies": {
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.1",
+ "@mui/icons-material": "^7.3.2",
+ "@mui/material": "^7.3.2",
"react": "^19.1.1",
- "react-dom": "^19.1.1"
+ "react-dom": "^19.1.1",
+ "react-dropzone": "^14.3.8",
+ "react-intersection-observer": "^9.16.0",
+ "react-router-dom": "^7.8.2"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
@@ -32,7 +39,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.27.1",
@@ -88,7 +94,6 @@
"version": "7.28.3",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz",
"integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.28.3",
@@ -122,7 +127,6 @@
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -132,7 +136,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
"integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.27.1",
@@ -174,7 +177,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -184,7 +186,6 @@
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -218,7 +219,6 @@
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
"integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.28.4"
@@ -262,11 +262,19 @@
"@babel/core": "^7.0.0-0"
}
},
+ "node_modules/@babel/runtime": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
+ "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/template": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
@@ -281,7 +289,6 @@
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz",
"integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
@@ -300,7 +307,6 @@
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
"integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
@@ -310,6 +316,158 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@emotion/babel-plugin": {
+ "version": "11.13.5",
+ "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
+ "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.16.7",
+ "@babel/runtime": "^7.18.3",
+ "@emotion/hash": "^0.9.2",
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/serialize": "^1.3.3",
+ "babel-plugin-macros": "^3.1.0",
+ "convert-source-map": "^1.5.0",
+ "escape-string-regexp": "^4.0.0",
+ "find-root": "^1.1.0",
+ "source-map": "^0.5.7",
+ "stylis": "4.2.0"
+ }
+ },
+ "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/cache": {
+ "version": "11.14.0",
+ "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz",
+ "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/sheet": "^1.4.0",
+ "@emotion/utils": "^1.4.2",
+ "@emotion/weak-memoize": "^0.4.0",
+ "stylis": "4.2.0"
+ }
+ },
+ "node_modules/@emotion/hash": {
+ "version": "0.9.2",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
+ "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/is-prop-valid": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz",
+ "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.9.0"
+ }
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
+ "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/react": {
+ "version": "11.14.0",
+ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
+ "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.13.5",
+ "@emotion/cache": "^11.14.0",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
+ "@emotion/utils": "^1.4.2",
+ "@emotion/weak-memoize": "^0.4.0",
+ "hoist-non-react-statics": "^3.3.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@emotion/serialize": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
+ "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/hash": "^0.9.2",
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/unitless": "^0.10.0",
+ "@emotion/utils": "^1.4.2",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@emotion/sheet": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
+ "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/styled": {
+ "version": "11.14.1",
+ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
+ "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.13.5",
+ "@emotion/is-prop-valid": "^1.3.0",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
+ "@emotion/utils": "^1.4.2"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.0.0-rc.0",
+ "react": ">=16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@emotion/unitless": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
+ "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/use-insertion-effect-with-fallbacks": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz",
+ "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@emotion/utils": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz",
+ "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/weak-memoize": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
+ "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
+ "license": "MIT"
+ },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
@@ -962,7 +1120,6 @@
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
@@ -984,7 +1141,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -994,20 +1150,263 @@
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
- "dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.30",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz",
"integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@mui/core-downloads-tracker": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.5.tgz",
+ "integrity": "sha512-kOLwlcDPnVz2QMhiBv0OQ8le8hTCqKM9cRXlfVPL91l3RGeOsxrIhNRsUt3Xb8wb+pTVUolW+JXKym93vRKxCw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ }
+ },
+ "node_modules/@mui/icons-material": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.5.tgz",
+ "integrity": "sha512-LciL1GLMZ+VlzyHAALSVAR22t8IST4LCXmljcUSx2NOutgO2XnxdIp8ilFbeNf9wpo0iUFbAuoQcB7h+HHIf3A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@mui/material": "^7.3.5",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/material": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.5.tgz",
+ "integrity": "sha512-8VVxFmp1GIm9PpmnQoCoYo0UWHoOrdA57tDL62vkpzEgvb/d71Wsbv4FRg7r1Gyx7PuSo0tflH34cdl/NvfHNQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4",
+ "@mui/core-downloads-tracker": "^7.3.5",
+ "@mui/system": "^7.3.5",
+ "@mui/types": "^7.4.8",
+ "@mui/utils": "^7.3.5",
+ "@popperjs/core": "^2.11.8",
+ "@types/react-transition-group": "^4.4.12",
+ "clsx": "^2.1.1",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1",
+ "react-is": "^19.2.0",
+ "react-transition-group": "^4.4.5"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@mui/material-pigment-css": "^7.3.5",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@mui/material-pigment-css": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/material/node_modules/react-is": {
+ "version": "19.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz",
+ "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==",
+ "license": "MIT"
+ },
+ "node_modules/@mui/private-theming": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.5.tgz",
+ "integrity": "sha512-cTx584W2qrLonwhZLbEN7P5pAUu0nZblg8cLBlTrZQ4sIiw8Fbvg7GvuphQaSHxPxrCpa7FDwJKtXdbl2TSmrA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4",
+ "@mui/utils": "^7.3.5",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/styled-engine": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.5.tgz",
+ "integrity": "sha512-zbsZ0uYYPndFCCPp2+V3RLcAN6+fv4C8pdwRx6OS3BwDkRCN8WBehqks7hWyF3vj1kdQLIWrpdv/5Y0jHRxYXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4",
+ "@emotion/cache": "^11.14.0",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/sheet": "^1.4.0",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.4.1",
+ "@emotion/styled": "^11.3.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/system": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.5.tgz",
+ "integrity": "sha512-yPaf5+gY3v80HNkJcPi6WT+r9ebeM4eJzrREXPxMt7pNTV/1eahyODO4fbH3Qvd8irNxDFYn5RQ3idHW55rA6g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4",
+ "@mui/private-theming": "^7.3.5",
+ "@mui/styled-engine": "^7.3.5",
+ "@mui/types": "^7.4.8",
+ "@mui/utils": "^7.3.5",
+ "clsx": "^2.1.1",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/types": {
+ "version": "7.4.8",
+ "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.8.tgz",
+ "integrity": "sha512-ZNXLBjkPV6ftLCmmRCafak3XmSn8YV0tKE/ZOhzKys7TZXUiE0mZxlH8zKDo6j6TTUaDnuij68gIG+0Ucm7Xhw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/utils": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.5.tgz",
+ "integrity": "sha512-jisvFsEC3sgjUjcPnR4mYfhzjCDIudttSGSbe1o/IXFNu0kZuR+7vqQI0jg8qtcVZBHWrwTfvAZj9MNMumcq1g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4",
+ "@mui/types": "^7.4.8",
+ "@types/prop-types": "^15.7.15",
+ "clsx": "^2.1.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^19.2.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/utils/node_modules/react-is": {
+ "version": "19.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz",
+ "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==",
+ "license": "MIT"
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1046,6 +1445,16 @@
"node": ">= 8"
}
},
+ "node_modules/@popperjs/core": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.34",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.34.tgz",
@@ -1406,11 +1815,22 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/parse-json": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
+ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/prop-types": {
+ "version": "15.7.15",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
+ "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
+ "license": "MIT"
+ },
"node_modules/@types/react": {
"version": "19.1.12",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz",
"integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"csstype": "^3.0.2"
@@ -1426,6 +1846,15 @@
"@types/react": "^19.0.0"
}
},
+ "node_modules/@types/react-transition-group": {
+ "version": "4.4.12",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
+ "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.43.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.43.0.tgz",
@@ -1929,6 +2358,15 @@
"node": ">= 0.4"
}
},
+ "node_modules/attr-accept": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz",
+ "integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -1945,6 +2383,41 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/babel-plugin-macros": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
+ "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "cosmiconfig": "^7.0.0",
+ "resolve": "^1.19.0"
+ },
+ "engines": {
+ "node": ">=10",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/babel-plugin-macros/node_modules/resolve": {
+ "version": "1.22.11",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
+ "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.16.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -2063,7 +2536,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -2107,6 +2579,15 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -2141,6 +2622,40 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/cookie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/cosmiconfig": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
+ "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/cosmiconfig/node_modules/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -2160,7 +2675,6 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true,
"license": "MIT"
},
"node_modules/data-view-buffer": {
@@ -2221,7 +2735,6 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -2291,6 +2804,16 @@
"node": ">=0.10.0"
}
},
+ "node_modules/dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
+ }
+ },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -2313,6 +2836,15 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/error-ex": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
+ "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
"node_modules/es-abstract": {
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz",
@@ -2546,7 +3078,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -2840,6 +3371,18 @@
"node": ">=16.0.0"
}
},
+ "node_modules/file-selector": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.2.tgz",
+ "integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.7.0"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -2853,6 +3396,12 @@
"node": ">=8"
}
},
+ "node_modules/find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
+ "license": "MIT"
+ },
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -2926,7 +3475,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -3178,7 +3726,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -3187,6 +3734,15 @@
"node": ">= 0.4"
}
},
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -3201,7 +3757,6 @@
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
@@ -3257,6 +3812,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "license": "MIT"
+ },
"node_modules/is-async-function": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
@@ -3327,7 +3888,6 @@
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
@@ -3666,7 +4226,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/js-yaml": {
@@ -3686,7 +4245,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
- "dev": true,
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
@@ -3702,6 +4260,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "license": "MIT"
+ },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -3769,6 +4333,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "license": "MIT"
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -3796,7 +4366,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
"license": "MIT",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
@@ -3866,7 +4435,6 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
@@ -3906,7 +4474,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -4082,7 +4649,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
@@ -4091,6 +4657,24 @@
"node": ">=6"
}
},
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -4115,14 +4699,21 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
@@ -4191,7 +4782,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
@@ -4251,11 +4841,42 @@
"react": "^19.1.1"
}
},
+ "node_modules/react-dropzone": {
+ "version": "14.3.8",
+ "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.3.8.tgz",
+ "integrity": "sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==",
+ "license": "MIT",
+ "dependencies": {
+ "attr-accept": "^2.2.4",
+ "file-selector": "^2.1.0",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">= 10.13"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8 || 18.0.0"
+ }
+ },
+ "node_modules/react-intersection-observer": {
+ "version": "9.16.0",
+ "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz",
+ "integrity": "sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/react-refresh": {
@@ -4268,6 +4889,60 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "7.9.6",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.6.tgz",
+ "integrity": "sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.9.6",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.6.tgz",
+ "integrity": "sha512-2MkC2XSXq6HjGcihnx1s0DBWQETI4mlis4Ux7YTLvP67xnGxCvq+BcCQSO81qQHVUTM1V53tl4iVVaY5sReCOA==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.9.6"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.6.0",
+ "react-dom": ">=16.6.0"
+ }
+ },
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -4334,7 +5009,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -4487,6 +5161,12 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
+ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
+ "license": "MIT"
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -4635,6 +5315,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -4770,6 +5459,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/stylis": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
+ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
+ "license": "MIT"
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -4787,7 +5482,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -4870,6 +5564,12 @@
"typescript": ">=4.8.4"
}
},
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -5287,6 +5987,21 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/yaml": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
+ "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "peer": true,
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14.6"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/package.json b/package.json
index fc29be0..ae89934 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"@mui/material": "^7.3.2",
"react": "^19.1.1",
"react-dom": "^19.1.1",
+ "react-dropzone": "^14.3.8",
"react-intersection-observer": "^9.16.0",
"react-router-dom": "^7.8.2"
},
diff --git a/src/App.tsx b/src/App.tsx
index 13c4381..681138a 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -3,6 +3,8 @@ import "./App.css";
import VintageComingSoonPage from "./components/comingsoon/comingsoon";
import DarkProductShowcase from "./components/product/product";
import BlogPage from "./components/blogs/BlogPage";
+import BlogCard from "./components/blogs/BlogCard";
+import WeddingGallery from "./WeddingGallery/WeddingGallery";
// import OtherPage from "./pages/OtherPage"; // example if you add more pages
function App() {
@@ -10,12 +12,15 @@ function App() {
{/* Default route */}
- } />
+ {/* } /> */}
+ } />
{/* Example extra routes */}
- } />
- } />
- {/* } /> */}
+ {/* } />
+ } /> */}
+ } />
+
+ {/* } /> */}
);
diff --git a/src/WeddingGallery/Gallery.tsx b/src/WeddingGallery/Gallery.tsx
new file mode 100644
index 0000000..480d761
--- /dev/null
+++ b/src/WeddingGallery/Gallery.tsx
@@ -0,0 +1,43 @@
+// Gallery.tsx
+import React from 'react';
+import SafeGrid from './SafeGrid';
+import { WeddingPhoto } from './types';
+import { Box, Card, CardContent, CardMedia, Chip, IconButton, Typography } from '@mui/material';
+import { Download } from '@mui/icons-material';
+
+type Props = {
+ photos: WeddingPhoto[];
+ onDownload?: (url: string, title?: string) => void;
+};
+
+const Gallery: React.FC = ({ photos, onDownload }) => {
+ return (
+
+ {photos.map((p) => (
+
+
+
+
+
+ onDownload?.(p.url, p.title)} sx={{ color: 'white', bgcolor: 'rgba(0,0,0,0.6)' }}>
+
+
+
+
+
+ {p.title || 'Untitled'}
+
+
+
+ {p.created_at ? new Date(p.created_at).toLocaleDateString() : p.date ? new Date(p.date).toLocaleDateString() : ''}
+
+
+
+
+
+ ))}
+
+ );
+};
+
+export default Gallery;
diff --git a/src/WeddingGallery/LightboxModal.tsx b/src/WeddingGallery/LightboxModal.tsx
new file mode 100644
index 0000000..b84aa52
--- /dev/null
+++ b/src/WeddingGallery/LightboxModal.tsx
@@ -0,0 +1,215 @@
+// LightboxModal.tsx
+import React, { useEffect, useRef, useState } from 'react';
+import {
+ Dialog,
+ IconButton,
+ Box,
+ Typography,
+ useTheme,
+} from '@mui/material';
+import CloseIcon from '@mui/icons-material/Close';
+import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew';
+import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
+import DownloadIcon from '@mui/icons-material/Download';
+
+export type LightboxPhoto = {
+ id: number | string;
+ url: string;
+ title?: string;
+ filename?: string;
+ created_at?: string;
+};
+
+type Props = {
+ open: boolean;
+ photos: LightboxPhoto[];
+ startIndex?: number;
+ onClose: () => void;
+ startIndexCallback?: (idx: number) => void; // optional: inform parent when slide changes
+};
+
+const SWIPE_THRESHOLD = 40; // pixels
+
+export default function LightboxModal({ open, photos, startIndex = 0, onClose, startIndexCallback }: Props) {
+ const [index, setIndex] = useState(startIndex);
+ const theme = useTheme();
+ const touchStartX = useRef(null);
+ const touchDeltaX = useRef(0);
+
+ useEffect(() => {
+ setIndex(startIndex);
+ }, [startIndex, open]);
+
+ useEffect(() => {
+ function onKey(e: KeyboardEvent) {
+ if (!open) return;
+ if (e.key === 'Escape') onClose();
+ if (e.key === 'ArrowLeft') prev();
+ if (e.key === 'ArrowRight') next();
+ }
+ window.addEventListener('keydown', onKey);
+ return () => window.removeEventListener('keydown', onKey);
+ }, [open, index]);
+
+ useEffect(() => {
+ // inform parent if needed
+ startIndexCallback?.(index);
+ }, [index]);
+
+ const prev = () => setIndex((i) => (i - 1 + photos.length) % photos.length);
+ const next = () => setIndex((i) => (i + 1) % photos.length);
+
+ // Preload neighbors
+ useEffect(() => {
+ if (!photos || photos.length === 0) return;
+ const prevIdx = (index - 1 + photos.length) % photos.length;
+ const nextIdx = (index + 1) % photos.length;
+ const p1 = new Image();
+ p1.src = photos[prevIdx]?.url;
+ const p2 = new Image();
+ p2.src = photos[nextIdx]?.url;
+ }, [index, photos]);
+
+ // Touch handlers for swipe
+ const onTouchStart = (e: React.TouchEvent) => {
+ touchDeltaX.current = 0;
+ touchStartX.current = e.touches?.[0]?.clientX ?? null;
+ };
+ const onTouchMove = (e: React.TouchEvent) => {
+ if (touchStartX.current == null) return;
+ const x = e.touches?.[0]?.clientX ?? 0;
+ touchDeltaX.current = x - (touchStartX.current ?? 0);
+ };
+ const onTouchEnd = () => {
+ const delta = touchDeltaX.current;
+ if (Math.abs(delta) > SWIPE_THRESHOLD) {
+ if (delta < 0) next();
+ else prev();
+ }
+ touchStartX.current = null;
+ touchDeltaX.current = 0;
+ };
+
+ if (!photos || photos.length === 0) return null;
+
+ const photo = photos[index];
+
+ return (
+
+ );
+}
diff --git a/src/WeddingGallery/PreviewTester.tsx b/src/WeddingGallery/PreviewTester.tsx
new file mode 100644
index 0000000..4ce8246
--- /dev/null
+++ b/src/WeddingGallery/PreviewTester.tsx
@@ -0,0 +1,55 @@
+// PreviewTester.tsx
+import React, { useCallback, useEffect, useState } from 'react';
+import { Box, Button, Card, CardMedia, CardContent, Typography } from '@mui/material';
+import { useDropzone } from 'react-dropzone';
+
+type Item = { id: string; file: File; previewUrl: string };
+
+export default function PreviewTester() {
+ const [items, setItems] = useState- ([]);
+
+ const onDrop = useCallback((acceptedFiles: File[]) => {
+ console.log('onDrop called, acceptedFiles:', acceptedFiles);
+ const now = Date.now();
+ const newItems = acceptedFiles.map((f, i) => ({
+ id: `${now}-${i}-${f.name}`,
+ file: f,
+ previewUrl: URL.createObjectURL(f),
+ }));
+ setItems((prev) => [...newItems, ...prev]);
+ }, []);
+
+ const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, multiple: true, accept: { 'image/*': [] } });
+
+ useEffect(() => {
+ return () => {
+ items.forEach((it) => {
+ try { URL.revokeObjectURL(it.previewUrl); } catch { }
+ });
+ };
+ }, [items]);
+
+ return (
+
+
+
+ {isDragActive ? 'Drop images here' : 'Drag & drop images (PreviewTester)'}
+
+
+
+ {items.map((it) => (
+
+
+
+ {it.file.name}
+
+
+ ))}
+
+
+
+
+
+
+ );
+}
diff --git a/src/WeddingGallery/SafeGrid.tsx b/src/WeddingGallery/SafeGrid.tsx
new file mode 100644
index 0000000..63d50ea
--- /dev/null
+++ b/src/WeddingGallery/SafeGrid.tsx
@@ -0,0 +1,4 @@
+// SafeGrid.tsx
+import Grid from '@mui/material/Grid';
+const SafeGrid = Grid as any;
+export default SafeGrid;
diff --git a/src/WeddingGallery/UploadQueue.tsx b/src/WeddingGallery/UploadQueue.tsx
new file mode 100644
index 0000000..173834a
--- /dev/null
+++ b/src/WeddingGallery/UploadQueue.tsx
@@ -0,0 +1,98 @@
+// UploadQueue.tsx
+import React, { useCallback } from 'react';
+import { Box, Button, Card, CardContent, CardMedia, IconButton, LinearProgress, Typography } from '@mui/material';
+import { Delete, Replay } from '@mui/icons-material';
+import { FileQueueItem, WeddingPhoto } from './types';
+import { uploadFileXHR, toAbsoluteUrl } from './apis';
+
+type Props = {
+ queue: FileQueueItem[];
+ setQueue: React.Dispatch>;
+ newPhotoTitle?: string;
+ onUploaded?: (photo: WeddingPhoto) => void;
+};
+
+const UploadQueue: React.FC = ({ queue, setQueue, newPhotoTitle, onUploaded }) => {
+ const uploadSingle = useCallback(
+ async (item: FileQueueItem) => {
+ setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, status: 'uploading', progress: 0, error: undefined } : q)));
+ const res = await uploadFileXHR(
+ item.file,
+ (pct) => setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, progress: pct } : q))),
+ newPhotoTitle
+ );
+ if (res.success) {
+ const it = res.data;
+ const uploadedPhoto: WeddingPhoto = {
+ id: it.id ?? it._id,
+ url: toAbsoluteUrl(it.path ?? it.url),
+ title: it.title ?? it.filename ?? item.file.name,
+ date: it.created_at ?? it.createdAt,
+ filename: it.filename,
+ path: it.path,
+ created_at: it.created_at ?? it.createdAt,
+ };
+ setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, status: 'done', progress: 100, uploadedPhoto } : q)));
+ onUploaded?.(uploadedPhoto);
+ return true;
+ } else {
+ setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, status: 'error', error: res.error } : q)));
+ return false;
+ }
+ },
+ [newPhotoTitle, setQueue, onUploaded]
+ );
+
+ const uploadAll = useCallback(async () => {
+ for (const item of queue.filter((q) => q.status === 'pending' || q.status === 'error')) {
+ // eslint-disable-next-line no-await-in-loop
+ await uploadSingle(item);
+ }
+ }, [queue, uploadSingle]);
+
+ const retryOne = (id: string) => {
+ const item = queue.find((q) => q.id === id);
+ if (item) uploadSingle(item);
+ };
+
+ const removeOne = (id: string) => {
+ const item = queue.find((q) => q.id === id);
+ if (item) URL.revokeObjectURL(item.previewUrl);
+ setQueue((prev) => prev.filter((q) => q.id !== id));
+ };
+
+ return (
+
+
+
+
+
+
+ {queue.map((q) => (
+
+
+
+
+ {q.file.name}
+
+
+ {q.status === 'uploading' && Uploading — {q.progress}%}
+ {q.status === 'pending' && Pending}
+ {q.status === 'done' && Uploaded}
+ {q.status === 'error' && {q.error ?? 'Upload failed'}}
+
+
+ {q.status === 'error' && retryOne(q.id)}>}
+ removeOne(q.id)}>
+
+
+
+ ))}
+
+
+ );
+};
+
+export default UploadQueue;
diff --git a/src/WeddingGallery/UploadTester.tsx b/src/WeddingGallery/UploadTester.tsx
new file mode 100644
index 0000000..2208f70
--- /dev/null
+++ b/src/WeddingGallery/UploadTester.tsx
@@ -0,0 +1,55 @@
+// UploadTester.tsx
+import React, { useState } from 'react';
+import { Box, Button, Input, Typography } from '@mui/material';
+
+export default function UploadTester() {
+ const [file, setFile] = useState(null);
+ function UploadTester() {
+ const [file, setFile] = useState(null);
+
+ const onFileChange = (e: React.ChangeEvent) => {
+ setFile(e.target.files?.[0] ?? null);
+ };
+
+ return ;
+ }
+
+ const handleUpload = async () => {
+ if (!file) return alert('Choose a file first');
+
+ const fd = new FormData();
+ fd.append('file', file, file.name);
+ fd.append('title', 'test-upload');
+
+ try {
+ const res = await fetch('https://mfs-api.midastix.com/image-upload/single', {
+ method: 'POST',
+ body: fd,
+ // DO NOT set Content-Type — browser will set multipart boundary
+ });
+ const text = await res.text();
+ console.log('UploadTester: status', res.status, 'body:', text);
+ alert(`Status: ${res.status} — see console for body`);
+ } catch (err) {
+ console.error('UploadTester error', err);
+ alert('Upload failed — see console');
+ }
+ };
+
+ return (
+
+ Upload Tester (one file)
+ {
+ const input = e.target as HTMLInputElement;
+ const f = input.files && input.files[0];
+ setFile(f ?? null);
+ }}
+ />
+
+
+
+
+ );
+}
diff --git a/src/WeddingGallery/WeddingGallery.tsx b/src/WeddingGallery/WeddingGallery.tsx
new file mode 100644
index 0000000..5fce8e9
--- /dev/null
+++ b/src/WeddingGallery/WeddingGallery.tsx
@@ -0,0 +1,624 @@
+// WeddingGallery.tsx
+import React, { JSX, useCallback, useEffect, useState } from 'react';
+import {
+ AppBar,
+ Alert,
+ Box,
+ Button,
+ Card,
+ CardContent,
+ CardMedia,
+ Chip,
+ CircularProgress,
+ Container,
+ CssBaseline,
+ Grid,
+ IconButton,
+ LinearProgress,
+ Paper,
+ Snackbar,
+ TextField,
+ ThemeProvider,
+ Toolbar,
+ Typography,
+ createTheme,
+ Dialog,
+ DialogTitle,
+ DialogContent,
+ DialogActions,
+} from '@mui/material';
+import {
+ CameraAlt,
+ CloudUpload,
+ Delete as DeleteIcon,
+ Download,
+ Replay,
+ Favorite,
+} from '@mui/icons-material';
+import { useDropzone } from 'react-dropzone';
+import LightboxModal from './LightboxModal';
+
+type WeddingPhoto = {
+ id: number | string;
+ url: string;
+ title?: string;
+ filename?: string;
+ created_at?: string;
+ date?: string;
+ path?: string;
+};
+
+type FileQueueItem = {
+ id: string;
+ file: File;
+ previewUrl: string;
+ progress: number;
+ status: 'pending' | 'uploading' | 'done' | 'error';
+ error?: string;
+ uploadedPhoto?: WeddingPhoto;
+};
+
+type FolderInfo = {
+ title: string;
+ count: number;
+ thumb?: string;
+};
+
+/* ============================
+ Config
+ ============================ */
+const MFS_API_BASE = 'https://mfs-api.midastix.com';
+const MAX_FILE_SIZE = 10 * 1024 * 1024;
+const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
+const MAX_QUEUE_FILES = 30;
+
+/* ============================
+ Helpers / API functions
+ ============================ */
+const toAbsoluteUrl = (path?: string) => {
+ if (!path) return '';
+ if (path.startsWith('http://') || path.startsWith('https://')) return path;
+ return `${MFS_API_BASE}${path}`;
+};
+
+const uploadFileXHR = (
+ file: File,
+ onProgress: (pct: number) => void,
+ title?: string
+): Promise<{ success: boolean; data?: any; error?: string }> =>
+ new Promise((resolve) => {
+ try {
+ const xhr = new XMLHttpRequest();
+ const url = `${MFS_API_BASE}/image-upload/single`;
+ xhr.open('POST', url, true);
+ xhr.setRequestHeader('Accept', 'application/json');
+
+ xhr.upload.onprogress = (ev) => {
+ if (!ev.lengthComputable) return;
+ const pct = Math.round((ev.loaded / ev.total) * 100);
+ onProgress(pct);
+ };
+
+ xhr.onload = () => {
+ if (xhr.status >= 200 && xhr.status < 300) {
+ try {
+ const json = JSON.parse(xhr.responseText);
+ resolve({ success: true, data: json });
+ } catch (e) {
+ resolve({ success: true, data: xhr.responseText });
+ }
+ } else {
+ const txt = xhr.responseText || `HTTP ${xhr.status}`;
+ resolve({ success: false, error: txt });
+ }
+ };
+
+ xhr.onerror = () => resolve({ success: false, error: 'Network error' });
+
+ const fd = new FormData();
+ fd.append('file', file, file.name);
+ if (title) fd.append('title', title);
+
+ xhr.send(fd);
+ } catch (err: any) {
+ resolve({ success: false, error: err?.message ?? String(err) });
+ }
+ });
+
+const fetchImagesApi = async (title = ''): Promise => {
+ const url =
+ title && title.trim() !== '' ? `${MFS_API_BASE}/image-upload?title=${encodeURIComponent(title)}` : `${MFS_API_BASE}/image-upload`;
+ const res = await fetch(url, { headers: { accept: 'application/json' } });
+ if (!res.ok) {
+ const txt = await res.text();
+ throw new Error(txt || `HTTP ${res.status}`);
+ }
+ const body = await res.json();
+ let imagesArray: any[] = [];
+ if (Array.isArray(body)) imagesArray = body;
+ else if (Array.isArray(body.images)) imagesArray = body.images;
+ else if (body.data && Array.isArray(body.data.images)) imagesArray = body.data.images;
+ else {
+ const firstArray = Object.values(body).find((v) => Array.isArray(v));
+ if (Array.isArray(firstArray)) imagesArray = firstArray as any[];
+ }
+ return imagesArray.map((it: any) => ({
+ id: it.id ?? it._id ?? `${it.filename ?? Math.random()}`,
+ url: toAbsoluteUrl(it.path ?? it.url),
+ title: it.title ?? it.filename ?? '',
+ filename: it.filename,
+ created_at: it.created_at ?? it.createdAt,
+ date: it.date,
+ path: it.path,
+ }));
+};
+
+const deletePhotoApi = async (id: number | string) => {
+ const url = `${MFS_API_BASE}/image-upload/${id}`;
+ const res = await fetch(url, { method: 'DELETE', headers: { accept: 'application/json' } });
+ const txt = await res.text();
+ if (!res.ok) throw new Error(txt || `HTTP ${res.status}`);
+ return txt || 'deleted';
+};
+
+const deleteFolderApi = async (title: string) => {
+ const url = `${MFS_API_BASE}/image-upload/folder?title=${encodeURIComponent(title)}`;
+ const res = await fetch(url, { method: 'DELETE', headers: { accept: 'application/json' } });
+ const txt = await res.text();
+ if (!res.ok) throw new Error(txt || `HTTP ${res.status}`);
+ return txt || 'folder deleted';
+};
+
+/* ============================
+ Theme & SafeGrid
+ ============================ */
+const theme = createTheme({
+ palette: {
+ primary: { main: '#0f766e', light: '#2dd4bf' },
+ secondary: { main: '#d4af37' },
+ background: { default: '#fbfdfb' },
+ },
+ typography: { fontFamily: '"Inter", "Roboto", sans-serif' },
+});
+
+const SafeGrid = Grid as any;
+
+/* ============================
+ Component
+ ============================ */
+export default function WeddingGallery(): JSX.Element {
+ const [photosAll, setPhotosAll] = useState([]);
+ const [folders, setFolders] = useState([]);
+ const [folderOpenTitle, setFolderOpenTitle] = useState(null);
+ const [folderPhotos, setFolderPhotos] = useState([]);
+ const [folderModalOpen, setFolderModalOpen] = useState(false);
+
+ const [queue, setQueue] = useState([]);
+ const [commonTitle, setCommonTitle] = useState('');
+ const [snackbar, setSnackbar] = useState<{ open: boolean; severity?: 'success' | 'error' | 'info'; message: string }>({
+ open: false,
+ severity: 'info',
+ message: '',
+ });
+
+ const [deletingId, setDeletingId] = useState(null);
+ const [deletingFolder, setDeletingFolder] = useState(null);
+
+ // lightbox state
+ const [lightboxOpen, setLightboxOpen] = useState(false);
+ const [lightboxStartIndex, setLightboxStartIndex] = useState(0);
+
+ const loadAll = useCallback(async () => {
+ try {
+ const items = await fetchImagesApi('');
+ setPhotosAll(items);
+ const map = new Map();
+ items.forEach((it) => {
+ const title = it.title ?? 'untitled';
+ if (!map.has(title)) map.set(title, { title, count: 0, thumb: it.url });
+ const entry = map.get(title)!;
+ entry.count += 1;
+ if (!entry.thumb) entry.thumb = it.url;
+ });
+ setFolders(Array.from(map.values()).sort((a, b) => b.count - a.count));
+ } catch (err: any) {
+ console.error('loadAll error', err);
+ setFolders([]);
+ setSnackbar({ open: true, severity: 'error', message: `Failed to load: ${err?.message || err}` });
+ }
+ }, []);
+
+ useEffect(() => {
+ loadAll();
+ return () => {
+ queue.forEach((q) => {
+ try {
+ URL.revokeObjectURL(q.previewUrl);
+ } catch { }
+ });
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ /* ============================
+ Drop — enforce MAX_QUEUE_FILES
+ ============================ */
+ const onDrop = useCallback((acceptedFiles: File[]) => {
+ if (!acceptedFiles || acceptedFiles.length === 0) return;
+
+ const currentCount = queue.length;
+ const available = Math.max(0, MAX_QUEUE_FILES - currentCount);
+
+ if (available <= 0) {
+ setSnackbar({ open: true, severity: 'error', message: `Queue full — maximum ${MAX_QUEUE_FILES} files allowed.` });
+ return;
+ }
+
+ const acceptedToAdd = acceptedFiles.slice(0, available);
+ const rejectedCount = acceptedFiles.length - acceptedToAdd.length;
+
+ const now = Date.now();
+ const items: FileQueueItem[] = acceptedToAdd.map((f, i) => {
+ const id = `${now}-${currentCount + i}-${f.name}`;
+ const tooLarge = f.size > MAX_FILE_SIZE;
+ const invalidType = ALLOWED_TYPES.length > 0 && !ALLOWED_TYPES.includes(f.type);
+ return {
+ id,
+ file: f,
+ previewUrl: URL.createObjectURL(f),
+ progress: 0,
+ status: tooLarge || invalidType ? 'error' : 'pending',
+ error: tooLarge ? `File too large ${(f.size / (1024 * 1024)).toFixed(1)}MB` : invalidType ? 'Invalid type' : undefined,
+ } as FileQueueItem;
+ });
+
+ setQueue((prev) => [...items, ...prev]);
+
+ if (rejectedCount > 0) {
+ setSnackbar({
+ open: true,
+ severity: 'info',
+ message: `Accepted ${acceptedToAdd.length} file(s). Rejected ${rejectedCount} file(s) due to the ${MAX_QUEUE_FILES}-file limit.`,
+ });
+ } else {
+ setSnackbar({ open: true, severity: 'success', message: `Added ${acceptedToAdd.length} file(s) to the queue.` });
+ }
+ }, [queue.length]);
+
+ const { getRootProps, getInputProps, isDragActive } = useDropzone({
+ onDrop,
+ multiple: true,
+ maxSize: MAX_FILE_SIZE,
+ accept: ALLOWED_TYPES.length ? ALLOWED_TYPES.reduce((acc, t) => ({ ...acc, [t]: [] }), {} as any) : undefined,
+ });
+
+ /* ============================
+ Upload logic
+ ============================ */
+ const uploadSingle = useCallback(
+ async (item: FileQueueItem) => {
+ setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, status: 'uploading', progress: 0, error: undefined } : q)));
+ const res = await uploadFileXHR(item.file, (pct) => {
+ setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, progress: pct } : q)));
+ }, commonTitle || undefined);
+
+ if (res.success) {
+ const it = res.data;
+ const uploadedPhoto: WeddingPhoto = {
+ id: it.id ?? it._id,
+ url: toAbsoluteUrl(it.path ?? it.url),
+ title: it.title ?? it.filename ?? commonTitle ?? '',
+ filename: it.filename,
+ created_at: it.created_at ?? it.createdAt,
+ path: it.path,
+ };
+ setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, status: 'done', progress: 100, uploadedPhoto } : q)));
+ setPhotosAll((prev) => [uploadedPhoto, ...prev]);
+ await loadAll();
+ return true;
+ } else {
+ setQueue((prev) => prev.map((q) => (q.id === item.id ? { ...q, status: 'error', error: res.error } : q)));
+ console.error('upload failed', res.error);
+ return false;
+ }
+ },
+ [commonTitle, loadAll]
+ );
+
+ const uploadAll = useCallback(async () => {
+ const pending = queue.filter((q) => q.status === 'pending' || q.status === 'error');
+ if (!pending.length) {
+ setSnackbar({ open: true, severity: 'info', message: 'No files to upload' });
+ return;
+ }
+ for (const item of pending) {
+ // eslint-disable-next-line no-await-in-loop
+ await uploadSingle(item);
+ }
+ setSnackbar({ open: true, severity: 'success', message: 'Uploads complete' });
+ setQueue((prev) => prev.filter((q) => q.status !== 'done'));
+ }, [queue, uploadSingle]);
+
+ const retryOne = (id: string) => {
+ const item = queue.find((q) => q.id === id);
+ if (item) uploadSingle(item);
+ };
+
+ const removeOne = (id: string) => {
+ const item = queue.find((q) => q.id === id);
+ if (item) {
+ try {
+ URL.revokeObjectURL(item.previewUrl);
+ } catch { }
+ }
+ setQueue((prev) => prev.filter((q) => q.id !== id));
+ };
+
+ /* ============================
+ Folder / modal management + lightbox hookup
+ ============================ */
+ const openFolder = async (title: string) => {
+ setFolderOpenTitle(title);
+ try {
+ const items = await fetchImagesApi(title);
+ setFolderPhotos(items);
+ setFolderModalOpen(true);
+ } catch (err: any) {
+ console.error('openFolder error', err);
+ setSnackbar({ open: true, severity: 'error', message: `Failed to load folder: ${err?.message || err}` });
+ }
+ };
+
+ const handleDeletePhoto = async (id: number | string) => {
+ if (!confirm('Delete this photo? This action cannot be undone.')) return;
+ setDeletingId(id);
+ try {
+ await deletePhotoApi(id);
+ setFolderPhotos((prev) => prev.filter((p) => p.id !== id));
+ setPhotosAll((prev) => prev.filter((p) => p.id !== id));
+ setSnackbar({ open: true, severity: 'success', message: 'Photo deleted' });
+ await loadAll();
+ } catch (err: any) {
+ console.error('deletePhoto error', err);
+ setSnackbar({ open: true, severity: 'error', message: `Failed to delete: ${err?.message || err}` });
+ } finally {
+ setDeletingId(null);
+ }
+ };
+
+ const handleDeleteFolder = async (title: string) => {
+ if (!confirm(`Delete entire folder "${title}" and all its photos? This is irreversible.`)) return;
+ setDeletingFolder(title);
+ try {
+ await deleteFolderApi(title);
+ setSnackbar({ open: true, severity: 'success', message: `Folder "${title}" deleted` });
+ await loadAll();
+ setFolderModalOpen(false);
+ } catch (err: any) {
+ console.error('deleteFolder error', err);
+ setSnackbar({ open: true, severity: 'error', message: `Failed to delete folder: ${err?.message || err}` });
+ } finally {
+ setDeletingFolder(null);
+ }
+ };
+
+ useEffect(() => {
+ const map = new Map();
+ photosAll.forEach((it) => {
+ const title = it.title ?? 'untitled';
+ if (!map.has(title)) map.set(title, { title, count: 0, thumb: it.url });
+ const e = map.get(title)!;
+ e.count += 1;
+ if (!e.thumb) e.thumb = it.url;
+ });
+ setFolders(Array.from(map.values()).sort((a, b) => b.count - a.count));
+ }, [photosAll]);
+
+ /* ============================
+ UI
+ ============================ */
+ return (
+
+
+
+
+
+
+ Wedding Gallery — Folders
+
+ } label="Events" sx={{ bgcolor: 'secondary.main', color: '#111' }} />
+
+
+
+
+
+ Events (Folders)
+
+ Only folders are shown here. Click a folder to manage photos inside.
+
+
+ Queue: {queue.length}/{MAX_QUEUE_FILES}
+
+
+
+
+
+
+
+
+
+ {isDragActive ? 'Drop images here' : 'Drag & drop images here, or click to select'}
+
+ Max {(MAX_FILE_SIZE / (1024 * 1024)).toFixed(0)}MB per file. Allowed: jpg, png, gif, webp. Max {MAX_QUEUE_FILES} files in queue.
+
+
+
+
+
+
+ setCommonTitle(e.target.value)} />
+
+
+
+
+
+ {/* Queue preview thumbnails */}
+
+ {queue.map((q) => (
+
+
+
+ {q.file.name}
+
+ {q.status === 'uploading' ? : q.status === 'done' ? Done : q.status === 'error' ? Err : Pending}
+ retryOne(q.id)} disabled={q.status !== 'error'}>
+ removeOne(q.id)}>
+
+
+
+
+ ))}
+
+
+
+
+
+
+ {/* Folders */}
+
+ {folders.length === 0 ? (
+
+ No events found
+ Upload photos to create events (folders)
+
+ ) : (
+
+ {folders.map((f) => (
+
+
+ openFolder(f.title)}>
+
+
+
+
+
+
+ {f.title}
+ {f.count} photos
+
+
+ { e.stopPropagation(); await handleDeleteFolder(f.title); }}>
+
+
+
+
+
+
+
+
+ ))}
+
+ )}
+
+
+
+ {/* Folder modal */}
+
+
+ {/* Lightbox */}
+ setLightboxOpen(false)}
+ />
+
+ setSnackbar((s) => ({ ...s, open: false }))}>
+ setSnackbar((s) => ({ ...s, open: false }))}>
+ {snackbar.message}
+
+
+
+ );
+}
diff --git a/src/WeddingGallery/apis.ts b/src/WeddingGallery/apis.ts
new file mode 100644
index 0000000..d1fe5de
--- /dev/null
+++ b/src/WeddingGallery/apis.ts
@@ -0,0 +1,102 @@
+// apis.ts
+const MFS_API_BASE = 'https://mfs-api.midastix.com';
+
+export const toAbsoluteUrl = (path?: string) => {
+ if (!path) return '';
+ if (path.startsWith('http://') || path.startsWith('https://')) return path;
+ return `${MFS_API_BASE}${path}`;
+};
+
+/**
+ * uploadFileXHR(file, onProgress, title?)
+ * returns { success, data?, error? }
+ */
+export const uploadFileXHR = (
+ file: File,
+ onProgress: (pct: number) => void,
+ title?: string
+): Promise<{ success: boolean; data?: any; error?: string }> =>
+ new Promise((resolve) => {
+ try {
+ const xhr = new XMLHttpRequest();
+ const url = `${MFS_API_BASE}/image-upload/single`;
+ xhr.open('POST', url, true);
+ xhr.setRequestHeader('Accept', 'application/json');
+
+ xhr.upload.onprogress = (ev) => {
+ if (!ev.lengthComputable) return;
+ const pct = Math.round((ev.loaded / ev.total) * 100);
+ onProgress(pct);
+ };
+
+ xhr.onload = () => {
+ if (xhr.status >= 200 && xhr.status < 300) {
+ try {
+ const json = JSON.parse(xhr.responseText);
+ resolve({ success: true, data: json });
+ } catch (e) {
+ resolve({ success: true, data: xhr.responseText });
+ }
+ } else {
+ const txt = xhr.responseText || `HTTP ${xhr.status}`;
+ resolve({ success: false, error: txt });
+ }
+ };
+
+ xhr.onerror = () => resolve({ success: false, error: 'Network error' });
+
+ const fd = new FormData();
+ fd.append('file', file, file.name);
+ if (title) fd.append('title', title);
+ xhr.send(fd);
+ } catch (err: any) {
+ resolve({ success: false, error: err?.message ?? String(err) });
+ }
+ });
+
+/* tolerant fetchImages mapping */
+export const fetchImagesApi = async (title = '') => {
+ const url =
+ title && title.trim() !== '' ? `${MFS_API_BASE}/image-upload?title=${encodeURIComponent(title)}` : `${MFS_API_BASE}/image-upload`;
+ const res = await fetch(url, { headers: { accept: 'application/json' } });
+ if (!res.ok) {
+ const txt = await res.text();
+ throw new Error(txt || `HTTP ${res.status}`);
+ }
+ const body = await res.json();
+ let imagesArray: any[] = [];
+ if (Array.isArray(body)) imagesArray = body;
+ else if (Array.isArray(body.images)) imagesArray = body.images;
+ else if (body.data && Array.isArray(body.data.images)) imagesArray = body.data.images;
+ else {
+ const firstArray = Object.values(body).find((v) => Array.isArray(v));
+ if (Array.isArray(firstArray)) imagesArray = firstArray as any[];
+ }
+ return imagesArray.map((it: any) => ({
+ id: it.id ?? it._id ?? `${it.filename ?? Math.random()}`,
+ url: toAbsoluteUrl(it.path ?? it.url),
+ title: it.title ?? it.filename ?? '',
+ date: it.created_at ?? it.createdAt ?? it.date ?? '',
+ filename: it.filename,
+ path: it.path,
+ created_at: it.created_at ?? it.createdAt,
+ }));
+};
+
+/* Delete photo (by id) */
+export const deletePhotoApi = async (id: number | string) => {
+ const url = `${MFS_API_BASE}/image-upload/${id}`;
+ const res = await fetch(url, { method: 'DELETE', headers: { accept: 'application/json' } });
+ const text = await res.text();
+ if (!res.ok) throw new Error(text || `HTTP ${res.status}`);
+ return text || 'deleted';
+};
+
+/* Delete folder by title (assumed endpoint) */
+export const deleteFolderApi = async (title: string) => {
+ const url = `${MFS_API_BASE}/image-upload/folder?title=${encodeURIComponent(title)}`;
+ const res = await fetch(url, { method: 'DELETE', headers: { accept: 'application/json' } });
+ const text = await res.text();
+ if (!res.ok) throw new Error(text || `HTTP ${res.status}`);
+ return text || 'folder deleted';
+};
diff --git a/src/WeddingGallery/folderModel.tsx b/src/WeddingGallery/folderModel.tsx
new file mode 100644
index 0000000..c31bfc3
--- /dev/null
+++ b/src/WeddingGallery/folderModel.tsx
@@ -0,0 +1,53 @@
+// FolderModal.tsx
+import React from 'react';
+import { Box, Dialog, DialogTitle, DialogContent, DialogActions, Button, Grid, Card, CardMedia, IconButton, Typography } from '@mui/material';
+import DeleteIcon from '@mui/icons-material/Delete';
+import { WeddingPhoto } from './types';
+
+type Props = {
+ open: boolean;
+ onClose: () => void;
+ photos: WeddingPhoto[];
+ onDeletePhoto: (id: number | string) => Promise;
+ deletingId?: number | string | null;
+};
+
+const FolderModal: React.FC = ({ open, onClose, photos, onDeletePhoto, deletingId }) => {
+ return (
+
+ );
+};
+
+export default FolderModal;
diff --git a/src/WeddingGallery/foldergrid.tsx b/src/WeddingGallery/foldergrid.tsx
new file mode 100644
index 0000000..cb84ea0
--- /dev/null
+++ b/src/WeddingGallery/foldergrid.tsx
@@ -0,0 +1,54 @@
+// FolderGrid.tsx
+import React from 'react';
+import SafeGrid from './SafeGrid';
+import { FolderInfo } from './types';
+import { Box, Card, CardContent, CardMedia, IconButton, Paper, Typography } from '@mui/material';
+import DeleteIcon from '@mui/icons-material/Delete';
+
+type Props = {
+ folders: FolderInfo[];
+ onOpen: (title: string) => void;
+ onDeleteFolder: (title: string) => void;
+};
+
+const FolderGrid: React.FC = ({ folders, onOpen, onDeleteFolder }) => {
+ if (!folders.length) {
+ return (
+
+ No events found
+ Upload photos to create events (folders).
+
+ );
+ }
+
+ return (
+
+ {folders.map((f) => (
+
+
+ onOpen(f.title)}>
+
+
+
+
+
+
+ {f.title}
+ {f.count} photos
+
+
+ { e.stopPropagation(); onDeleteFolder(f.title); }}>
+
+
+
+
+
+
+
+
+ ))}
+
+ );
+};
+
+export default FolderGrid;
diff --git a/src/WeddingGallery/types.tsx b/src/WeddingGallery/types.tsx
new file mode 100644
index 0000000..15ea034
--- /dev/null
+++ b/src/WeddingGallery/types.tsx
@@ -0,0 +1,26 @@
+// types.ts
+export type WeddingPhoto = {
+ id: number | string;
+ url: string;
+ title?: string;
+ date?: string;
+ filename?: string;
+ path?: string;
+ created_at?: string;
+};
+
+export type FileQueueItem = {
+ id: string;
+ file: File;
+ previewUrl: string;
+ progress: number;
+ status: 'pending' | 'uploading' | 'done' | 'error';
+ error?: string;
+ uploadedPhoto?: WeddingPhoto;
+};
+
+export type FolderInfo = {
+ title: string;
+ count: number;
+ thumb?: string;
+};
diff --git a/src/components/blogs/BlogPage.tsx b/src/components/blogs/BlogPage.tsx
index d1b8a99..f7405f0 100644
--- a/src/components/blogs/BlogPage.tsx
+++ b/src/components/blogs/BlogPage.tsx
@@ -1,5 +1,9 @@
import React, { useState, useMemo } from 'react';
-import { Box, Container, Grid, Typography, TextField, Chip, IconButton, InputAdornment } from '@mui/material';
+import {
+ Box, Container, Grid, Typography, TextField, Chip, IconButton,
+ InputAdornment, Card, CardContent, CardMedia, Button, Avatar,
+ useTheme, useMediaQuery
+} from '@mui/material';
import { useInView } from 'react-intersection-observer';
import InstagramIcon from '@mui/icons-material/Instagram';
import FacebookIcon from '@mui/icons-material/Facebook';
@@ -7,10 +11,34 @@ import TwitterIcon from '@mui/icons-material/Twitter';
import SearchIcon from '@mui/icons-material/Search';
import { keyframes } from '@emotion/react';
import { styled } from '@mui/system';
-import BlogCard from '../blogs/BlogCard';
-import { BlogData, BlogPost } from '../../types/blogs';
+import { useNavigate } from 'react-router-dom';
-// Use your existing color palette
+// Define TypeScript interfaces
+interface Author {
+ name: string;
+ avatar: string;
+ role: string;
+}
+
+interface BlogPost {
+ id: string;
+ title: string;
+ excerpt: string;
+ content: string;
+ image: string;
+ author: Author;
+ date: string;
+ readTime: string;
+ tags: string[];
+ category: string;
+}
+
+interface BlogCardProps {
+ post: BlogPost;
+ index: number;
+}
+
+// Color palette
const colors = {
paper: '#F5F5EF',
ink: '#1A2526',
@@ -22,9 +50,26 @@ const colors = {
};
// Animations
+const fadeInUp = keyframes`
+ from {
+ opacity: 0;
+ transform: translateY(30px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+`;
+
const fadeIn = keyframes`
- from { opacity: 0; transform: translateY(20px); }
- to { opacity: 1; transform: translateY(0); }
+ from { opacity: 0; }
+ to { opacity: 1; }
+`;
+
+const float = keyframes`
+ 0% { transform: translateY(0px); }
+ 50% { transform: translateY(-8px); }
+ 100% { transform: translateY(0px); }
`;
const drawUnderline = keyframes`
@@ -32,6 +77,25 @@ const drawUnderline = keyframes`
100% { width: 100%; }
`;
+const pulse = keyframes`
+ 0% { transform: scale(1); }
+ 50% { transform: scale(1.05); }
+ 100% { transform: scale(1); }
+`;
+
+// Styled Components
+interface AnimatedSectionProps {
+ delay?: string;
+}
+
+const AnimatedSection = styled(Box, {
+ shouldForwardProp: (prop) => prop !== 'delay',
+})(({ delay = '0s' }) => ({
+ opacity: 0,
+ animation: `${fadeInUp} 0.8s forwards`,
+ animationDelay: delay,
+}));
+
const VintageUnderline = styled(Box)({
position: 'relative',
display: 'inline-block',
@@ -48,106 +112,343 @@ const VintageUnderline = styled(Box)({
},
});
-const AnimatedSection = styled(Box)({
- opacity: 0,
- transform: 'translateY(20px)',
- animation: `${fadeIn} 0.8s forwards`,
+const FloatingElement = styled(Box)({
+ animation: `${float} 6s ease-in-out infinite`,
});
-// Mock data - in real app, this would be imported from JSON
-const blogData: BlogData = {
- posts: [
- {
- id: "1",
- title: "The Art of Hand Block Printing",
- excerpt: "Discover the ancient technique of hand block printing that has been passed down through generations of Indian artisans.",
- content: "Full content would be here...",
- image: "https://images.pexels.com/photos/6011599/pexels-photo-6011599.jpeg?auto=compress&cs=tinysrgb&w=500",
- author: {
- name: "Priya Sharma",
- avatar: "https://images.pexels.com/photos/3762800/pexels-photo-3762800.jpeg?auto=compress&cs=tinysrgb&w=500",
- role: "Textile Conservationist"
- },
- date: "2023-10-15",
- readTime: "5 min read",
- tags: ["Textiles", "Craft", "Heritage"],
- category: "Artisan Techniques"
- },
- {
- id: "2",
- title: "Natural Dyes: Colors from Nature",
- excerpt: "Explore how traditional Indian artisans extract vibrant colors from plants, minerals, and other natural sources.",
- content: "Full content would be here...",
- image: "https://images.pexels.com/photos/1375736/pexels-photo-1375736.jpeg?auto=compress&cs=tinysrgb&w=500",
- author: {
- name: "Rajiv Mehta",
- avatar: "https://images.pexels.com/photos/2379004/pexels-photo-2379004.jpeg?auto=compress&cs=tinysrgb&w=500",
- role: "Natural Dye Expert"
- },
- date: "2023-09-22",
- readTime: "7 min read",
- tags: ["Eco-friendly", "Sustainability", "Natural"],
- category: "Sustainable Practices"
- },
- {
- id: "3",
- title: "The Weavers of Varanasi",
- excerpt: "A journey into the world of Varanasi's master weavers who create the exquisite Banarasi silk sarees.",
- content: "Full content would be here...",
- image: "https://images.pexels.com/photos/942803/pexels-photo-942803.jpeg?auto=compress&cs=tinysrgb&w=500",
- author: {
- name: "Anjali Patel",
- avatar: "https://images.pexels.com/photos/3785077/pexels-photo-3785077.jpeg?auto=compress&cs=tinysrgb&w=500",
- role: "Textile Historian"
- },
- date: "2023-08-30",
- readTime: "8 min read",
- tags: ["Weaving", "Silk", "Heritage"],
- category: "Artisan Stories"
- },
- {
- id: "4",
- title: "Reviving Ancient Embroidery Techniques",
- excerpt: "How contemporary designers are working with artisans to preserve and modernize traditional embroidery methods.",
- content: "Full content would be here...",
- image: "https://images.pexels.com/photos/6347892/pexels-photo-6347892.jpeg?auto=compress&cs=tinysrgb&w=500",
- author: {
- name: "Sanjay Kumar",
- avatar: "https://images.pexels.com/photos/2182970/pexels-photo-2182970.jpeg?auto=compress&cs=tinysrgb&w=500",
- role: "Fashion Designer"
- },
- date: "2023-08-15",
- readTime: "6 min read",
- tags: ["Embroidery", "Design", "Revival"],
- category: "Design Innovation"
- }
- ],
- categories: [
- "Artisan Techniques",
- "Sustainable Practices",
- "Artisan Stories",
- "Design Innovation",
- "Cultural Heritage"
- ],
- tags: [
- "Textiles",
- "Craft",
- "Heritage",
- "Eco-friendly",
- "Sustainability",
- "Natural",
- "Weaving",
- "Silk",
- "Embroidery",
- "Design",
- "Revival"
- ]
+// BlogCard Component
+const BlogCard: React.FC = ({ post, index }) => {
+ const navigate = useNavigate();
+ const [ref, inView] = useInView({ threshold: 0.2, triggerOnce: true });
+ const theme = useTheme();
+ const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
+
+ const handleReadMore = () => {
+ navigate(`/blog/${post.id}`);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {post.author.name}
+
+
+ {post.author.role}
+
+
+
+
+
+ {post.title}
+
+
+
+ {post.excerpt}
+
+
+
+
+ {post.date} • {post.readTime}
+
+
+
+
+
+
+ {post.tags.map((tag: string, i: number) => (
+
+ ))}
+
+
+
+ );
};
+// BlogPage Component
const BlogPage: React.FC = () => {
- const [selectedCategory, setSelectedCategory] = useState('all');
- const [searchQuery, setSearchQuery] = useState('');
+ const [selectedCategory, setSelectedCategory] = useState('all');
+ const [searchQuery, setSearchQuery] = useState('');
const [heroRef, heroInView] = useInView({ threshold: 0.1, triggerOnce: true });
+ const theme = useTheme();
+ const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
+
+ // Mock data
+ const blogData = {
+ posts: [
+ {
+ id: "1",
+ title: "The Art of Hand Block Printing",
+ excerpt: "Discover the ancient technique of hand block printing that has been passed down through generations of Indian artisans.",
+ content: "Full content would be here...",
+ image: "https://images.pexels.com/photos/6011599/pexels-photo-6011599.jpeg?auto=compress&cs=tinysrgb&w=500",
+ author: {
+ name: "Priya Sharma",
+ avatar: "https://images.pexels.com/photos/3762800/pexels-photo-3762800.jpeg?auto=compress&cs=tinysrgb&w=500",
+ role: "Textile Conservationist"
+ },
+ date: "2023-10-15",
+ readTime: "5 min read",
+ tags: ["Textiles", "Craft", "Heritage"],
+ category: "Artisan Techniques"
+ },
+ {
+ id: "2",
+ title: "Natural Dyes: Colors from Nature",
+ excerpt: "Explore how traditional Indian artisans extract vibrant colors from plants, minerals, and other natural sources.",
+ content: "Full content would be here...",
+ image: "https://images.pexels.com/photos/1375736/pexels-photo-1375736.jpeg?auto=compress&cs=tinysrgb&w=500",
+ author: {
+ name: "Rajiv Mehta",
+ avatar: "https://images.pexels.com/photos/2379004/pexels-photo-2379004.jpeg?auto=compress&cs=tinysrgb&w=500",
+ role: "Natural Dye Expert"
+ },
+ date: "2023-09-22",
+ readTime: "7 min read",
+ tags: ["Eco-friendly", "Sustainability", "Natural"],
+ category: "Sustainable Practices"
+ },
+ {
+ id: "3",
+ title: "The Weavers of Varanasi",
+ excerpt: "A journey into the world of Varanasi's master weavers who create the exquisite Banarasi silk sarees.",
+ content: "Full content would be here...",
+ image: "https://images.pexels.com/photos/942803/pexels-photo-942803.jpeg?auto=compress&cs=tinysrgb&w=500",
+ author: {
+ name: "Anjali Patel",
+ avatar: "https://images.pexels.com/photos/3785077/pexels-photo-3785077.jpeg?auto=compress&cs=tinysrgb&w=500",
+ role: "Textile Historian"
+ },
+ date: "2023-08-30",
+ readTime: "8 min read",
+ tags: ["Weaving", "Silk", "Heritage"],
+ category: "Artisan Stories"
+ },
+ {
+ id: "4",
+ title: "Reviving Ancient Embroidery Techniques",
+ excerpt: "How contemporary designers are working with artisans to preserve and modernize traditional embroidery methods.",
+ content: "Full content would be here...",
+ image: "https://images.pexels.com/photos/6347892/pexels-photo-6347892.jpeg?auto=compress&cs=tinysrgb&w=500",
+ author: {
+ name: "Sanjay Kumar",
+ avatar: "https://images.pexels.com/photos/2182970/pexels-photo-2182970.jpeg?auto=compress&cs=tinysrgb&w=500",
+ role: "Fashion Designer"
+ },
+ date: "2023-08-15",
+ readTime: "6 min read",
+ tags: ["Embroidery", "Design", "Revival"],
+ category: "Design Innovation"
+ },
+ {
+ id: "5",
+ title: "Pottery Traditions of Rajasthan",
+ excerpt: "Exploring the centuries-old pottery techniques that continue to thrive in the desert state.",
+ content: "Full content would be here...",
+ image: "https://images.pexels.com/photos/4110012/pexels-photo-4110012.jpeg?auto=compress&cs=tinysrgb&w=500",
+ author: {
+ name: "Vikram Singh",
+ avatar: "https://images.pexels.com/photos/220453/pexels-photo-220453.jpeg?auto=compress&cs=tinysrgb&w=500",
+ role: "Cultural Anthropologist"
+ },
+ date: "2023-07-28",
+ readTime: "9 min read",
+ tags: ["Pottery", "Tradition", "Rajasthan"],
+ category: "Cultural Heritage"
+ },
+ {
+ id: "6",
+ title: "Sustainable Fashion Revolution",
+ excerpt: "How traditional Indian textiles are leading the way in sustainable fashion practices worldwide.",
+ content: "Full content would be here...",
+ image: "https://images.pexels.com/photos/4947734/pexels-photo-4947734.jpeg?auto=compress&cs=tinysrgb&w=500",
+ author: {
+ name: "Meera Desai",
+ avatar: "https://images.pexels.com/photos/3756678/pexels-photo-3756678.jpeg?auto=compress&cs=tinysrgb&w=500",
+ role: "Fashion Entrepreneur"
+ },
+ date: "2023-07-10",
+ readTime: "7 min read",
+ tags: ["Fashion", "Sustainability", "Innovation"],
+ category: "Sustainable Practices"
+ }
+ ],
+ categories: [
+ "Artisan Techniques",
+ "Sustainable Practices",
+ "Artisan Stories",
+ "Design Innovation",
+ "Cultural Heritage"
+ ],
+ tags: [
+ "Textiles",
+ "Craft",
+ "Heritage",
+ "Eco-friendly",
+ "Sustainability",
+ "Natural",
+ "Weaving",
+ "Silk",
+ "Embroidery",
+ "Design",
+ "Revival"
+ ]
+ };
const filteredPosts = useMemo(() => {
return blogData.posts.filter(post => {
@@ -166,48 +467,65 @@ const BlogPage: React.FC = () => {
minHeight: '100vh',
background: colors.paper,
color: colors.ink,
+ pt: isMobile ? 4 : 0,
}}>
{/* Header Section */}
-
-
-
- Journal
-
-
- Stories of Craft, Culture & Heritage
-
+
+
+
+
+
+ Journal
+
+
+
+ Stories of Craft, Culture & Heritage
+
+
-
-
+
+
+
@@ -218,7 +536,11 @@ const BlogPage: React.FC = () => {
target="_blank"
sx={{
color: colors.secondary,
- '&:hover': { color: colors.accent, transform: 'scale(1.1)' },
+ '&:hover': {
+ color: colors.accent,
+ transform: 'scale(1.1)',
+ background: `${colors.highlight}80`
+ },
transition: 'all 0.3s ease'
}}
>
@@ -229,7 +551,11 @@ const BlogPage: React.FC = () => {
target="_blank"
sx={{
color: colors.secondary,
- '&:hover': { color: colors.accent, transform: 'scale(1.1)' },
+ '&:hover': {
+ color: colors.accent,
+ transform: 'scale(1.1)',
+ background: `${colors.highlight}80`
+ },
transition: 'all 0.3s ease'
}}
>
@@ -239,7 +565,7 @@ const BlogPage: React.FC = () => {
-
+
{
/>
-
-
+
+
setSelectedCategory('all')}
@@ -281,9 +612,12 @@ const BlogPage: React.FC = () => {
backgroundColor: selectedCategory === 'all' ? colors.accent : 'transparent',
borderColor: colors.border,
fontFamily: '"Cormorant Garamond", serif',
+ '&:hover': {
+ backgroundColor: selectedCategory === 'all' ? colors.accent : `${colors.highlight}80`
+ }
}}
/>
- {blogData.categories.map((category) => (
+ {blogData.categories.map((category: string) => (
{
backgroundColor: selectedCategory === category ? colors.accent : 'transparent',
borderColor: colors.border,
fontFamily: '"Cormorant Garamond", serif',
+ '&:hover': {
+ backgroundColor: selectedCategory === category ? colors.accent : `${colors.highlight}80`
+ }
}}
/>
))}
@@ -303,9 +640,9 @@ const BlogPage: React.FC = () => {
{/* Blog Posts Grid */}
-
-
- {filteredPosts.map((post, index) => (
+
+
+ {filteredPosts.map((post: BlogPost, index: number) => (
@@ -320,9 +657,19 @@ const BlogPage: React.FC = () => {
color: colors.secondary,
fontFamily: '"Cormorant Garamond", serif',
fontStyle: 'italic',
+ mb: 2
}}
>
- No articles found matching your criteria
+ No articles found
+
+
+ Try a different search or category
)}
@@ -332,11 +679,12 @@ const BlogPage: React.FC = () => {
-
+
{
target="_blank"
sx={{
color: colors.secondary,
- '&:hover': { color: colors.accent, transform: 'scale(1.1)' },
+ '&:hover': {
+ color: colors.accent,
+ transform: 'scale(1.1)',
+ background: `${colors.highlight}80`
+ },
transition: 'all 0.3s ease'
}}
>
@@ -381,7 +733,11 @@ const BlogPage: React.FC = () => {
target="_blank"
sx={{
color: colors.secondary,
- '&:hover': { color: colors.accent, transform: 'scale(1.1)' },
+ '&:hover': {
+ color: colors.accent,
+ transform: 'scale(1.1)',
+ background: `${colors.highlight}80`
+ },
transition: 'all 0.3s ease'
}}
>
@@ -392,7 +748,11 @@ const BlogPage: React.FC = () => {
target="_blank"
sx={{
color: colors.secondary,
- '&:hover': { color: colors.accent, transform: 'scale(1.1)' },
+ '&:hover': {
+ color: colors.accent,
+ transform: 'scale(1.1)',
+ background: `${colors.highlight}80`
+ },
transition: 'all 0.3s ease'
}}
>
diff --git a/yarn.lock b/yarn.lock
index f3e8ab3..2ac6d7b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -173,7 +173,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.28.3, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7":
+"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.28.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7":
version: 7.28.4
resolution: "@babel/runtime@npm:7.28.4"
checksum: 10c0/792ce7af9750fb9b93879cc9d1db175701c4689da890e6ced242ea0207c9da411ccf16dc04e689cc01158b28d7898c40d75598f4559109f761c12ce01e959bf7
@@ -661,6 +661,22 @@ __metadata:
languageName: node
linkType: hard
+"@isaacs/balanced-match@npm:^4.0.1":
+ version: 4.0.1
+ resolution: "@isaacs/balanced-match@npm:4.0.1"
+ checksum: 10c0/7da011805b259ec5c955f01cee903da72ad97c5e6f01ca96197267d3f33103d5b2f8a1af192140f3aa64526c593c8d098ae366c2b11f7f17645d12387c2fd420
+ languageName: node
+ linkType: hard
+
+"@isaacs/brace-expansion@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "@isaacs/brace-expansion@npm:5.0.0"
+ dependencies:
+ "@isaacs/balanced-match": "npm:^4.0.1"
+ checksum: 10c0/b4d4812f4be53afc2c5b6c545001ff7a4659af68d4484804e9d514e183d20269bb81def8682c01a22b17c4d6aed14292c8494f7d2ac664e547101c1a905aa977
+ languageName: node
+ linkType: hard
+
"@isaacs/cliui@npm:^8.0.2":
version: 8.0.2
resolution: "@isaacs/cliui@npm:8.0.2"
@@ -728,49 +744,49 @@ __metadata:
languageName: node
linkType: hard
-"@mui/core-downloads-tracker@npm:^7.3.2":
- version: 7.3.2
- resolution: "@mui/core-downloads-tracker@npm:7.3.2"
- checksum: 10c0/8549ac661e07926e1c1de2664ad50f68fb4f3f6050f3cfe7bf2e8a7ceaefde99c1615f4ab5185dff22a7d72874d1dcc5fdc3651d08ed4eb1abfb798629f3991f
+"@mui/core-downloads-tracker@npm:^7.3.5":
+ version: 7.3.5
+ resolution: "@mui/core-downloads-tracker@npm:7.3.5"
+ checksum: 10c0/72c71d43b3609ccd5eab5b3bfc5bfc2232b79cfb210cb64a66298de0b2effccb1843aa8cdb6e062bc6f5df91c02d70de84984bb6fab9745ffdf00e81a574dc9b
languageName: node
linkType: hard
"@mui/icons-material@npm:^7.3.2":
- version: 7.3.2
- resolution: "@mui/icons-material@npm:7.3.2"
+ version: 7.3.5
+ resolution: "@mui/icons-material@npm:7.3.5"
dependencies:
- "@babel/runtime": "npm:^7.28.3"
+ "@babel/runtime": "npm:^7.28.4"
peerDependencies:
- "@mui/material": ^7.3.2
+ "@mui/material": ^7.3.5
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
react: ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta:
"@types/react":
optional: true
- checksum: 10c0/25d1f0dcbbb4a35f320aac03317657b15631f9d5b9d48d07e34850d61253a2b4d8dd5e5ca624d76f44b5ceda471ea57d2611f6627fec1eef9fce78855ec01cbf
+ checksum: 10c0/5fa551acabc8eddf30113a45a7c7b9923ec0f520608442cb914345493208aaa5b4ba852ad4b766ab58c547a2eb498ab4d6c1a3ebf5d4055a006c2327e397f88c
languageName: node
linkType: hard
"@mui/material@npm:^7.3.2":
- version: 7.3.2
- resolution: "@mui/material@npm:7.3.2"
+ version: 7.3.5
+ resolution: "@mui/material@npm:7.3.5"
dependencies:
- "@babel/runtime": "npm:^7.28.3"
- "@mui/core-downloads-tracker": "npm:^7.3.2"
- "@mui/system": "npm:^7.3.2"
- "@mui/types": "npm:^7.4.6"
- "@mui/utils": "npm:^7.3.2"
+ "@babel/runtime": "npm:^7.28.4"
+ "@mui/core-downloads-tracker": "npm:^7.3.5"
+ "@mui/system": "npm:^7.3.5"
+ "@mui/types": "npm:^7.4.8"
+ "@mui/utils": "npm:^7.3.5"
"@popperjs/core": "npm:^2.11.8"
"@types/react-transition-group": "npm:^4.4.12"
clsx: "npm:^2.1.1"
csstype: "npm:^3.1.3"
prop-types: "npm:^15.8.1"
- react-is: "npm:^19.1.1"
+ react-is: "npm:^19.2.0"
react-transition-group: "npm:^4.4.5"
peerDependencies:
"@emotion/react": ^11.5.0
"@emotion/styled": ^11.3.0
- "@mui/material-pigment-css": ^7.3.2
+ "@mui/material-pigment-css": ^7.3.5
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
react: ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -783,16 +799,16 @@ __metadata:
optional: true
"@types/react":
optional: true
- checksum: 10c0/4b82a65af93fe9517991f45c2f9dc127728199921f5c4c5cd7a8cd48e1c89ba17799011440f1b7e32993871c13b3044878a3170ddd9ce0e7cfe5ca0e7e3613f2
+ checksum: 10c0/363ff79d0eaf8044510529bf8d143d7e6f5298297dcfbd0816c5caf49e9514bde6b187b0e135cc1d73ac2ecfec1b06d3fea3bba952e7d8d0bfc997d0510fff8a
languageName: node
linkType: hard
-"@mui/private-theming@npm:^7.3.2":
- version: 7.3.2
- resolution: "@mui/private-theming@npm:7.3.2"
+"@mui/private-theming@npm:^7.3.5":
+ version: 7.3.5
+ resolution: "@mui/private-theming@npm:7.3.5"
dependencies:
- "@babel/runtime": "npm:^7.28.3"
- "@mui/utils": "npm:^7.3.2"
+ "@babel/runtime": "npm:^7.28.4"
+ "@mui/utils": "npm:^7.3.5"
prop-types: "npm:^15.8.1"
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -800,15 +816,15 @@ __metadata:
peerDependenciesMeta:
"@types/react":
optional: true
- checksum: 10c0/fb6067e92a1bc02d4b2b49fa58901200ccf4b79760a0227bf2859bd2cb99c46ba0f43ece9494eaa220710703eaf309a7c6e732daf4176520c0a16e1407846399
+ checksum: 10c0/1347cf2a1ec1ae93d26134143c20314d53dac61fe5c8c7aa00ab37d9e89f5e6245f787dee9b0bf3d34fc614c9a5da1f5d45759fcd2520ddef4c10e755c4abc5e
languageName: node
linkType: hard
-"@mui/styled-engine@npm:^7.3.2":
- version: 7.3.2
- resolution: "@mui/styled-engine@npm:7.3.2"
+"@mui/styled-engine@npm:^7.3.5":
+ version: 7.3.5
+ resolution: "@mui/styled-engine@npm:7.3.5"
dependencies:
- "@babel/runtime": "npm:^7.28.3"
+ "@babel/runtime": "npm:^7.28.4"
"@emotion/cache": "npm:^11.14.0"
"@emotion/serialize": "npm:^1.3.3"
"@emotion/sheet": "npm:^1.4.0"
@@ -823,19 +839,19 @@ __metadata:
optional: true
"@emotion/styled":
optional: true
- checksum: 10c0/d5644b40269a70a1c86844f7301aa6865289994e7835b471f3503e67795010d5334362cfd21d8804f54e8b71d6c9c932ca78bafc2325767e3abbe037f9e8e10b
+ checksum: 10c0/01dc8aefde58d5257564b7fd40f37de0f76d79e6bc6b52738cf41c333a053623baf2648f0557fb4b5ded306fd2b98e94797d7e48ad1c1f297747d2a265e22ad0
languageName: node
linkType: hard
-"@mui/system@npm:^7.3.2":
- version: 7.3.2
- resolution: "@mui/system@npm:7.3.2"
+"@mui/system@npm:^7.3.5":
+ version: 7.3.5
+ resolution: "@mui/system@npm:7.3.5"
dependencies:
- "@babel/runtime": "npm:^7.28.3"
- "@mui/private-theming": "npm:^7.3.2"
- "@mui/styled-engine": "npm:^7.3.2"
- "@mui/types": "npm:^7.4.6"
- "@mui/utils": "npm:^7.3.2"
+ "@babel/runtime": "npm:^7.28.4"
+ "@mui/private-theming": "npm:^7.3.5"
+ "@mui/styled-engine": "npm:^7.3.5"
+ "@mui/types": "npm:^7.4.8"
+ "@mui/utils": "npm:^7.3.5"
clsx: "npm:^2.1.1"
csstype: "npm:^3.1.3"
prop-types: "npm:^15.8.1"
@@ -851,41 +867,41 @@ __metadata:
optional: true
"@types/react":
optional: true
- checksum: 10c0/ed385c37f29a8d4b57bc1c59f8bc06a3e4cc393d86a6e0059229eacc7c96bcb11ae80369de0e459971bde24bdd33078f5578f152f0ac2e796222b269a80833ed
+ checksum: 10c0/12ed6e0f4770848c91c066b6ffb315f2cd31d6281ff12780f8d994d5b677750277812491ba502831601bbe66cbc48812268ae08b7bbc10120e7faf5616807489
languageName: node
linkType: hard
-"@mui/types@npm:^7.4.6":
- version: 7.4.6
- resolution: "@mui/types@npm:7.4.6"
+"@mui/types@npm:^7.4.8":
+ version: 7.4.8
+ resolution: "@mui/types@npm:7.4.8"
dependencies:
- "@babel/runtime": "npm:^7.28.3"
+ "@babel/runtime": "npm:^7.28.4"
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta:
"@types/react":
optional: true
- checksum: 10c0/baa901e410591d0216b3f959cdbf5a1ee2ce560726d2fba1c700b40f64c1be3e63bd799f1b30a7d0bc8cc45a46d782928ea28d9906d64438f21e305884c48a99
+ checksum: 10c0/dfdca47c894da372236f7c209544abd2998a77af646baf28d97a49313064b293b2fb434e45f9e5331e3123f9f8863f7b3e1db8542d7bde2d4f1e5f030d85f0c1
languageName: node
linkType: hard
-"@mui/utils@npm:^7.3.2":
- version: 7.3.2
- resolution: "@mui/utils@npm:7.3.2"
+"@mui/utils@npm:^7.3.5":
+ version: 7.3.5
+ resolution: "@mui/utils@npm:7.3.5"
dependencies:
- "@babel/runtime": "npm:^7.28.3"
- "@mui/types": "npm:^7.4.6"
+ "@babel/runtime": "npm:^7.28.4"
+ "@mui/types": "npm:^7.4.8"
"@types/prop-types": "npm:^15.7.15"
clsx: "npm:^2.1.1"
prop-types: "npm:^15.8.1"
- react-is: "npm:^19.1.1"
+ react-is: "npm:^19.2.0"
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
react: ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta:
"@types/react":
optional: true
- checksum: 10c0/5a88ff08a823b976421f8d61098d56d527d95c222800d5b3f71acff795e7b0db6b02e40228773a6ed7ee22d8eaa607d816215b5a4b6497c21aaa9668c2699b56
+ checksum: 10c0/c9f9ce12a5053d7aeafd0c390e7d17d331e0366dec9d993c9ad860f78c1d9410e5a33c40601afa039f4120ea299d2a59e76eff705359c7d96fb09ce636ba72b9
languageName: node
linkType: hard
@@ -916,16 +932,16 @@ __metadata:
languageName: node
linkType: hard
-"@npmcli/agent@npm:^3.0.0":
- version: 3.0.0
- resolution: "@npmcli/agent@npm:3.0.0"
+"@npmcli/agent@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "@npmcli/agent@npm:4.0.0"
dependencies:
agent-base: "npm:^7.1.0"
http-proxy-agent: "npm:^7.0.0"
https-proxy-agent: "npm:^7.0.1"
- lru-cache: "npm:^10.0.1"
+ lru-cache: "npm:^11.2.1"
socks-proxy-agent: "npm:^8.0.3"
- checksum: 10c0/efe37b982f30740ee77696a80c196912c274ecd2cb243bc6ae7053a50c733ce0f6c09fda085145f33ecf453be19654acca74b69e81eaad4c90f00ccffe2f9271
+ checksum: 10c0/f7b5ce0f3dd42c3f8c6546e8433573d8049f67ef11ec22aa4704bc41483122f68bf97752e06302c455ead667af5cb753e6a09bff06632bc465c1cfd4c4b75a53
languageName: node
linkType: hard
@@ -938,13 +954,6 @@ __metadata:
languageName: node
linkType: hard
-"@pkgjs/parseargs@npm:^0.11.0":
- version: 0.11.0
- resolution: "@pkgjs/parseargs@npm:0.11.0"
- checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd
- languageName: node
- linkType: hard
-
"@popperjs/core@npm:^2.11.8":
version: 2.11.8
resolution: "@popperjs/core@npm:2.11.8"
@@ -1355,10 +1364,10 @@ __metadata:
languageName: node
linkType: hard
-"abbrev@npm:^3.0.0":
- version: 3.0.1
- resolution: "abbrev@npm:3.0.1"
- checksum: 10c0/21ba8f574ea57a3106d6d35623f2c4a9111d9ee3e9a5be47baed46ec2457d2eac46e07a5c4a60186f88cb98abbe3e24f2d4cca70bc2b12f1692523e2209a9ccf
+"abbrev@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "abbrev@npm:4.0.0"
+ checksum: 10c0/b4cc16935235e80702fc90192e349e32f8ef0ed151ef506aa78c81a7c455ec18375c4125414b99f84b2e055199d66383e787675f0bcd87da7a4dbd59f9eac1d5
languageName: node
linkType: hard
@@ -1535,6 +1544,13 @@ __metadata:
languageName: node
linkType: hard
+"attr-accept@npm:^2.2.4":
+ version: 2.2.5
+ resolution: "attr-accept@npm:2.2.5"
+ checksum: 10c0/9b4cb82213925cab2d568f71b3f1c7a7778f9192829aac39a281e5418cd00c04a88f873eb89f187e0bf786fa34f8d52936f178e62cbefb9254d57ecd88ada99b
+ languageName: node
+ linkType: hard
+
"available-typed-arrays@npm:^1.0.7":
version: 1.0.7
resolution: "available-typed-arrays@npm:1.0.7"
@@ -1604,23 +1620,22 @@ __metadata:
languageName: node
linkType: hard
-"cacache@npm:^19.0.1":
- version: 19.0.1
- resolution: "cacache@npm:19.0.1"
+"cacache@npm:^20.0.1":
+ version: 20.0.1
+ resolution: "cacache@npm:20.0.1"
dependencies:
"@npmcli/fs": "npm:^4.0.0"
fs-minipass: "npm:^3.0.0"
- glob: "npm:^10.2.2"
- lru-cache: "npm:^10.0.1"
+ glob: "npm:^11.0.3"
+ lru-cache: "npm:^11.1.0"
minipass: "npm:^7.0.3"
minipass-collect: "npm:^2.0.1"
minipass-flush: "npm:^1.0.5"
minipass-pipeline: "npm:^1.2.4"
p-map: "npm:^7.0.2"
ssri: "npm:^12.0.0"
- tar: "npm:^7.4.3"
unique-filename: "npm:^4.0.0"
- checksum: 10c0/01f2134e1bd7d3ab68be851df96c8d63b492b1853b67f2eecb2c37bb682d37cb70bb858a16f2f0554d3c0071be6dfe21456a1ff6fa4b7eed996570d6a25ffe9c
+ checksum: 10c0/e3efcf3af1c984e6e59e03372d9289861736a572e6e05b620606b87a67e71d04cff6dbc99607801cb21bcaae1fb4fb84d4cc8e3fda725e95881329ef03dac602
languageName: node
linkType: hard
@@ -1802,7 +1817,19 @@ __metadata:
languageName: node
linkType: hard
-"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4":
+"debug@npm:4":
+ version: 4.4.3
+ resolution: "debug@npm:4.4.3"
+ dependencies:
+ ms: "npm:^2.1.3"
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6
+ languageName: node
+ linkType: hard
+
+"debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4":
version: 4.4.1
resolution: "debug@npm:4.4.1"
dependencies:
@@ -1925,11 +1952,11 @@ __metadata:
linkType: hard
"error-ex@npm:^1.3.1":
- version: 1.3.2
- resolution: "error-ex@npm:1.3.2"
+ version: 1.3.4
+ resolution: "error-ex@npm:1.3.4"
dependencies:
is-arrayish: "npm:^0.2.1"
- checksum: 10c0/ba827f89369b4c93382cfca5a264d059dfefdaa56ecc5e338ffa58a6471f5ed93b71a20add1d52290a4873d92381174382658c885ac1a2305f7baca363ce9cce
+ checksum: 10c0/b9e34ff4778b8f3b31a8377e1c654456f4c41aeaa3d10a1138c3b7635d8b7b2e03eb2475d46d8ae055c1f180a1063e100bffabf64ea7e7388b37735df5328664
languageName: node
linkType: hard
@@ -2341,9 +2368,9 @@ __metadata:
linkType: hard
"exponential-backoff@npm:^3.1.1":
- version: 3.1.2
- resolution: "exponential-backoff@npm:3.1.2"
- checksum: 10c0/d9d3e1eafa21b78464297df91f1776f7fbaa3d5e3f7f0995648ca5b89c069d17055033817348d9f4a43d1c20b0eab84f75af6991751e839df53e4dfd6f22e844
+ version: 3.1.3
+ resolution: "exponential-backoff@npm:3.1.3"
+ checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267
languageName: node
linkType: hard
@@ -2411,6 +2438,15 @@ __metadata:
languageName: node
linkType: hard
+"file-selector@npm:^2.1.0":
+ version: 2.1.2
+ resolution: "file-selector@npm:2.1.2"
+ dependencies:
+ tslib: "npm:^2.7.0"
+ checksum: 10c0/fe827e0e95410aacfcc3eabc38c29cc36055257f03c1c06b631a2b5af9730c142ad2c52f5d64724d02231709617bda984701f52bd1f4b7aca50fb6585a27c1d2
+ languageName: node
+ linkType: hard
+
"fill-range@npm:^7.1.1":
version: 7.1.1
resolution: "fill-range@npm:7.1.1"
@@ -2463,7 +2499,7 @@ __metadata:
languageName: node
linkType: hard
-"foreground-child@npm:^3.1.0":
+"foreground-child@npm:^3.3.1":
version: 3.3.1
resolution: "foreground-child@npm:3.3.1"
dependencies:
@@ -2593,19 +2629,19 @@ __metadata:
languageName: node
linkType: hard
-"glob@npm:^10.2.2":
- version: 10.4.5
- resolution: "glob@npm:10.4.5"
+"glob@npm:^11.0.3":
+ version: 11.0.3
+ resolution: "glob@npm:11.0.3"
dependencies:
- foreground-child: "npm:^3.1.0"
- jackspeak: "npm:^3.1.2"
- minimatch: "npm:^9.0.4"
+ foreground-child: "npm:^3.3.1"
+ jackspeak: "npm:^4.1.1"
+ minimatch: "npm:^10.0.3"
minipass: "npm:^7.1.2"
package-json-from-dist: "npm:^1.0.0"
- path-scurry: "npm:^1.11.1"
+ path-scurry: "npm:^2.0.0"
bin:
glob: dist/esm/bin.mjs
- checksum: 10c0/19a9759ea77b8e3ca0a43c2f07ecddc2ad46216b786bb8f993c445aee80d345925a21e5280c7b7c6c59e860a0154b84e4b2b60321fea92cd3c56b4a7489f160e
+ checksum: 10c0/7d24457549ec2903920dfa3d8e76850e7c02aa709122f0164b240c712f5455c0b457e6f2a1eee39344c6148e39895be8094ae8cfef7ccc3296ed30bce250c661
languageName: node
linkType: hard
@@ -2799,9 +2835,9 @@ __metadata:
linkType: hard
"ip-address@npm:^10.0.1":
- version: 10.0.1
- resolution: "ip-address@npm:10.0.1"
- checksum: 10c0/1634d79dae18394004775cb6d699dc46b7c23df6d2083164025a2b15240c1164fccde53d0e08bd5ee4fc53913d033ab6b5e395a809ad4b956a940c446e948843
+ version: 10.1.0
+ resolution: "ip-address@npm:10.1.0"
+ checksum: 10c0/0103516cfa93f6433b3bd7333fa876eb21263912329bfa47010af5e16934eeeff86f3d2ae700a3744a137839ddfad62b900c7a445607884a49b5d1e32a3d7566
languageName: node
linkType: hard
@@ -2862,7 +2898,7 @@ __metadata:
languageName: node
linkType: hard
-"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.0":
+"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.1":
version: 2.16.1
resolution: "is-core-module@npm:2.16.1"
dependencies:
@@ -3086,16 +3122,12 @@ __metadata:
languageName: node
linkType: hard
-"jackspeak@npm:^3.1.2":
- version: 3.4.3
- resolution: "jackspeak@npm:3.4.3"
+"jackspeak@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "jackspeak@npm:4.1.1"
dependencies:
"@isaacs/cliui": "npm:^8.0.2"
- "@pkgjs/parseargs": "npm:^0.11.0"
- dependenciesMeta:
- "@pkgjs/parseargs":
- optional: true
- checksum: 10c0/6acc10d139eaefdbe04d2f679e6191b3abf073f111edf10b1de5302c97ec93fffeb2fdd8681ed17f16268aa9dd4f8c588ed9d1d3bffbbfa6e8bf897cbb3149b9
+ checksum: 10c0/84ec4f8e21d6514db24737d9caf65361511f75e5e424980eebca4199f400874f45e562ac20fa8aeb1dd20ca2f3f81f0788b6e9c3e64d216a5794fd6f30e0e042
languageName: node
linkType: hard
@@ -3228,10 +3260,10 @@ __metadata:
languageName: node
linkType: hard
-"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0":
- version: 10.4.3
- resolution: "lru-cache@npm:10.4.3"
- checksum: 10c0/ebd04fbca961e6c1d6c0af3799adcc966a1babe798f685bb84e6599266599cd95d94630b10262f5424539bc4640107e8a33aa28585374abf561d30d16f4b39fb
+"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1":
+ version: 11.2.2
+ resolution: "lru-cache@npm:11.2.2"
+ checksum: 10c0/72d7831bbebc85e2bdefe01047ee5584db69d641c48d7a509e86f66f6ee111b30af7ec3bd68a967d47b69a4b1fa8bbf3872630bd06a63b6735e6f0a5f1c8e83d
languageName: node
linkType: hard
@@ -3244,22 +3276,22 @@ __metadata:
languageName: node
linkType: hard
-"make-fetch-happen@npm:^14.0.3":
- version: 14.0.3
- resolution: "make-fetch-happen@npm:14.0.3"
+"make-fetch-happen@npm:^15.0.0":
+ version: 15.0.3
+ resolution: "make-fetch-happen@npm:15.0.3"
dependencies:
- "@npmcli/agent": "npm:^3.0.0"
- cacache: "npm:^19.0.1"
+ "@npmcli/agent": "npm:^4.0.0"
+ cacache: "npm:^20.0.1"
http-cache-semantics: "npm:^4.1.1"
minipass: "npm:^7.0.2"
- minipass-fetch: "npm:^4.0.0"
+ minipass-fetch: "npm:^5.0.0"
minipass-flush: "npm:^1.0.5"
minipass-pipeline: "npm:^1.2.4"
negotiator: "npm:^1.0.0"
- proc-log: "npm:^5.0.0"
+ proc-log: "npm:^6.0.0"
promise-retry: "npm:^2.0.1"
- ssri: "npm:^12.0.0"
- checksum: 10c0/c40efb5e5296e7feb8e37155bde8eb70bc57d731b1f7d90e35a092fde403d7697c56fb49334d92d330d6f1ca29a98142036d6480a12681133a0a1453164cb2f0
+ ssri: "npm:^13.0.0"
+ checksum: 10c0/525f74915660be60b616bcbd267c4a5b59481b073ba125e45c9c3a041bb1a47a2bd0ae79d028eb6f5f95bf9851a4158423f5068539c3093621abb64027e8e461
languageName: node
linkType: hard
@@ -3287,6 +3319,15 @@ __metadata:
languageName: node
linkType: hard
+"minimatch@npm:^10.0.3":
+ version: 10.1.1
+ resolution: "minimatch@npm:10.1.1"
+ dependencies:
+ "@isaacs/brace-expansion": "npm:^5.0.0"
+ checksum: 10c0/c85d44821c71973d636091fddbfbffe62370f5ee3caf0241c5b60c18cd289e916200acb2361b7e987558cd06896d153e25d505db9fc1e43e6b4b6752e2702902
+ languageName: node
+ linkType: hard
+
"minimatch@npm:^3.1.2":
version: 3.1.2
resolution: "minimatch@npm:3.1.2"
@@ -3314,9 +3355,9 @@ __metadata:
languageName: node
linkType: hard
-"minipass-fetch@npm:^4.0.0":
- version: 4.0.1
- resolution: "minipass-fetch@npm:4.0.1"
+"minipass-fetch@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "minipass-fetch@npm:5.0.0"
dependencies:
encoding: "npm:^0.1.13"
minipass: "npm:^7.0.3"
@@ -3325,7 +3366,7 @@ __metadata:
dependenciesMeta:
encoding:
optional: true
- checksum: 10c0/a3147b2efe8e078c9bf9d024a0059339c5a09c5b1dded6900a219c218cc8b1b78510b62dae556b507304af226b18c3f1aeb1d48660283602d5b6586c399eed5c
+ checksum: 10c0/9443aab5feab190972f84b64116e54e58dd87a58e62399cae0a4a7461b80568281039b7c3a38ba96453431ebc799d1e26999e548540156216729a4967cd5ef06
languageName: node
linkType: hard
@@ -3365,28 +3406,19 @@ __metadata:
languageName: node
linkType: hard
-"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2":
+"minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2":
version: 7.1.2
resolution: "minipass@npm:7.1.2"
checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557
languageName: node
linkType: hard
-"minizlib@npm:^3.0.1":
- version: 3.0.2
- resolution: "minizlib@npm:3.0.2"
+"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "minizlib@npm:3.1.0"
dependencies:
minipass: "npm:^7.1.2"
- checksum: 10c0/9f3bd35e41d40d02469cb30470c55ccc21cae0db40e08d1d0b1dff01cc8cc89a6f78e9c5d2b7c844e485ec0a8abc2238111213fdc5b2038e6d1012eacf316f78
- languageName: node
- linkType: hard
-
-"mkdirp@npm:^3.0.1":
- version: 3.0.1
- resolution: "mkdirp@npm:3.0.1"
- bin:
- mkdirp: dist/cjs/src/bin.js
- checksum: 10c0/9f2b975e9246351f5e3a40dcfac99fcd0baa31fbfab615fe059fb11e51f10e4803c63de1f384c54d656e4db31d000e4767e9ef076a22e12a641357602e31d57d
+ checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec
languageName: node
linkType: hard
@@ -3421,22 +3453,22 @@ __metadata:
linkType: hard
"node-gyp@npm:latest":
- version: 11.4.2
- resolution: "node-gyp@npm:11.4.2"
+ version: 12.1.0
+ resolution: "node-gyp@npm:12.1.0"
dependencies:
env-paths: "npm:^2.2.0"
exponential-backoff: "npm:^3.1.1"
graceful-fs: "npm:^4.2.6"
- make-fetch-happen: "npm:^14.0.3"
- nopt: "npm:^8.0.0"
- proc-log: "npm:^5.0.0"
+ make-fetch-happen: "npm:^15.0.0"
+ nopt: "npm:^9.0.0"
+ proc-log: "npm:^6.0.0"
semver: "npm:^7.3.5"
- tar: "npm:^7.4.3"
+ tar: "npm:^7.5.2"
tinyglobby: "npm:^0.2.12"
- which: "npm:^5.0.0"
+ which: "npm:^6.0.0"
bin:
node-gyp: bin/node-gyp.js
- checksum: 10c0/0bfd3e96770ed70f07798d881dd37b4267708966d868a0e585986baac487d9cf5831285579fd629a83dc4e434f53e6416ce301097f2ee464cb74d377e4d8bdbe
+ checksum: 10c0/f43efea8aaf0beb6b2f6184e533edad779b2ae38062953e21951f46221dd104006cc574154f2ad4a135467a5aae92c49e84ef289311a82e08481c5df0e8dc495
languageName: node
linkType: hard
@@ -3447,14 +3479,14 @@ __metadata:
languageName: node
linkType: hard
-"nopt@npm:^8.0.0":
- version: 8.1.0
- resolution: "nopt@npm:8.1.0"
+"nopt@npm:^9.0.0":
+ version: 9.0.0
+ resolution: "nopt@npm:9.0.0"
dependencies:
- abbrev: "npm:^3.0.0"
+ abbrev: "npm:^4.0.0"
bin:
nopt: bin/nopt.js
- checksum: 10c0/62e9ea70c7a3eb91d162d2c706b6606c041e4e7b547cbbb48f8b3695af457dd6479904d7ace600856bf923dd8d1ed0696f06195c8c20f02ac87c1da0e1d315ef
+ checksum: 10c0/1822eb6f9b020ef6f7a7516d7b64a8036e09666ea55ac40416c36e4b2b343122c3cff0e2f085675f53de1d2db99a2a89a60ccea1d120bcd6a5347bf6ceb4a7fd
languageName: node
linkType: hard
@@ -3573,9 +3605,9 @@ __metadata:
linkType: hard
"p-map@npm:^7.0.2":
- version: 7.0.3
- resolution: "p-map@npm:7.0.3"
- checksum: 10c0/46091610da2b38ce47bcd1d8b4835a6fa4e832848a6682cf1652bc93915770f4617afc844c10a77d1b3e56d2472bb2d5622353fa3ead01a7f42b04fc8e744a5c
+ version: 7.0.4
+ resolution: "p-map@npm:7.0.4"
+ checksum: 10c0/a5030935d3cb2919d7e89454d1ce82141e6f9955413658b8c9403cfe379283770ed3048146b44cde168aa9e8c716505f196d5689db0ae3ce9a71521a2fef3abd
languageName: node
linkType: hard
@@ -3628,13 +3660,13 @@ __metadata:
languageName: node
linkType: hard
-"path-scurry@npm:^1.11.1":
- version: 1.11.1
- resolution: "path-scurry@npm:1.11.1"
+"path-scurry@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "path-scurry@npm:2.0.1"
dependencies:
- lru-cache: "npm:^10.2.0"
- minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0"
- checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d
+ lru-cache: "npm:^11.0.0"
+ minipass: "npm:^7.1.2"
+ checksum: 10c0/2a16ed0e81fbc43513e245aa5763354e25e787dab0d539581a6c3f0f967461a159ed6236b2559de23aa5b88e7dc32b469b6c47568833dd142a4b24b4f5cd2620
languageName: node
linkType: hard
@@ -3691,10 +3723,10 @@ __metadata:
languageName: node
linkType: hard
-"proc-log@npm:^5.0.0":
- version: 5.0.0
- resolution: "proc-log@npm:5.0.0"
- checksum: 10c0/bbe5edb944b0ad63387a1d5b1911ae93e05ce8d0f60de1035b218cdcceedfe39dbd2c697853355b70f1a090f8f58fe90da487c85216bf9671f9499d1a897e9e3
+"proc-log@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "proc-log@npm:6.0.0"
+ checksum: 10c0/40c5e2b4c55e395a3bd72e38cba9c26e58598a1f4844fa6a115716d5231a0919f46aa8e351147035d91583ad39a794593615078c948bc001fe3beb99276be776
languageName: node
linkType: hard
@@ -3744,6 +3776,19 @@ __metadata:
languageName: node
linkType: hard
+"react-dropzone@npm:^14.3.8":
+ version: 14.3.8
+ resolution: "react-dropzone@npm:14.3.8"
+ dependencies:
+ attr-accept: "npm:^2.2.4"
+ file-selector: "npm:^2.1.0"
+ prop-types: "npm:^15.8.1"
+ peerDependencies:
+ react: ">= 16.8 || 18.0.0"
+ checksum: 10c0/e17b1832783cda7b8824fe9370e99185d1abbdd5e4980b2985d6321c5768c8de18ff7b9ad550c809ee9743269dea608ff74d5208062754ce8377ad022897b278
+ languageName: node
+ linkType: hard
+
"react-intersection-observer@npm:^9.16.0":
version: 9.16.0
resolution: "react-intersection-observer@npm:9.16.0"
@@ -3764,10 +3809,10 @@ __metadata:
languageName: node
linkType: hard
-"react-is@npm:^19.1.1":
- version: 19.1.1
- resolution: "react-is@npm:19.1.1"
- checksum: 10c0/3dba763fcd69835ae263dcd6727d7ffcc44c1d616f04b7329e67aefdc66a567af4f8dcecdd29454c7a707c968aa1eb85083a83fb616f01675ef25e71cf082f97
+"react-is@npm:^19.2.0":
+ version: 19.2.0
+ resolution: "react-is@npm:19.2.0"
+ checksum: 10c0/a63cb346aeced8ac0e671b0f9b33720d2906de02a066ca067075d871a5d4c64cdb328f495baf9b5842d5868c0d5edd1ce18465a7358b52f4b6aa983479c9bfa2
languageName: node
linkType: hard
@@ -3779,20 +3824,20 @@ __metadata:
linkType: hard
"react-router-dom@npm:^7.8.2":
- version: 7.8.2
- resolution: "react-router-dom@npm:7.8.2"
+ version: 7.9.6
+ resolution: "react-router-dom@npm:7.9.6"
dependencies:
- react-router: "npm:7.8.2"
+ react-router: "npm:7.9.6"
peerDependencies:
react: ">=18"
react-dom: ">=18"
- checksum: 10c0/b285182ffa1b26df5025f6e7952edca066928d5688d3447b02e4a7e699ca16941e8a42ecad65ab505914e27fed04a2023c92ae3ebf838226b4381a2e3a69ae01
+ checksum: 10c0/63984c46385da232655b9e3a8a99f6dd7b94c36827be6e954f246c362f83740b5f59b1de99cae81da3b0cef2220d701dcc22e4fafb4a84600541e1c0450b9d57
languageName: node
linkType: hard
-"react-router@npm:7.8.2":
- version: 7.8.2
- resolution: "react-router@npm:7.8.2"
+"react-router@npm:7.9.6":
+ version: 7.9.6
+ resolution: "react-router@npm:7.9.6"
dependencies:
cookie: "npm:^1.0.1"
set-cookie-parser: "npm:^2.6.0"
@@ -3802,7 +3847,7 @@ __metadata:
peerDependenciesMeta:
react-dom:
optional: true
- checksum: 10c0/e3122c2949bcad5e9c990cfb88e9cbd139e5a2a5c1d29664732623907a488634c0ddbf673d07af8f113d418f66270c174f014de8b885996722f431d09f5734be
+ checksum: 10c0/2a177bbe19021e3b8211df849ea5b3f3a4f482327e6de3341aaeaa4f1406dc9be7b675b229eefea6761e04a59a40ccaaf8188f2ee88eb2d0b2a6b6448daea368
languageName: node
linkType: hard
@@ -3866,15 +3911,15 @@ __metadata:
linkType: hard
"resolve@npm:^1.19.0":
- version: 1.22.10
- resolution: "resolve@npm:1.22.10"
+ version: 1.22.11
+ resolution: "resolve@npm:1.22.11"
dependencies:
- is-core-module: "npm:^2.16.0"
+ is-core-module: "npm:^2.16.1"
path-parse: "npm:^1.0.7"
supports-preserve-symlinks-flag: "npm:^1.0.0"
bin:
resolve: bin/resolve
- checksum: 10c0/8967e1f4e2cc40f79b7e080b4582b9a8c5ee36ffb46041dccb20e6461161adf69f843b43067b4a375de926a2cd669157e29a29578191def399dd5ef89a1b5203
+ checksum: 10c0/f657191507530f2cbecb5815b1ee99b20741ea6ee02a59c57028e9ec4c2c8d7681afcc35febbd554ac0ded459db6f2d8153382c53a2f266cee2575e512674409
languageName: node
linkType: hard
@@ -3892,15 +3937,15 @@ __metadata:
linkType: hard
"resolve@patch:resolve@npm%3A^1.19.0#optional!builtin":
- version: 1.22.10
- resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d"
+ version: 1.22.11
+ resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d"
dependencies:
- is-core-module: "npm:^2.16.0"
+ is-core-module: "npm:^2.16.1"
path-parse: "npm:^1.0.7"
supports-preserve-symlinks-flag: "npm:^1.0.0"
bin:
resolve: bin/resolve
- checksum: 10c0/52a4e505bbfc7925ac8f4cd91fd8c4e096b6a89728b9f46861d3b405ac9a1ccf4dcbf8befb4e89a2e11370dacd0160918163885cbc669369590f2f31f4c58939
+ checksum: 10c0/ee5b182f2e37cb1165465e58c6abc797fec0a80b5ba3231607beb4677db0c9291ac010c47cf092b6daa2b7f518d69a0e21888e7e2b633f68d501a874212a8c63
languageName: node
linkType: hard
@@ -4075,7 +4120,16 @@ __metadata:
languageName: node
linkType: hard
-"semver@npm:^7.3.5, semver@npm:^7.6.0":
+"semver@npm:^7.3.5":
+ version: 7.7.3
+ resolution: "semver@npm:7.7.3"
+ bin:
+ semver: bin/semver.js
+ checksum: 10c0/4afe5c986567db82f44c8c6faef8fe9df2a9b1d98098fc1721f57c696c4c21cebd572f297fc21002f81889492345b8470473bc6f4aff5fb032a6ea59ea2bc45e
+ languageName: node
+ linkType: hard
+
+"semver@npm:^7.6.0":
version: 7.7.2
resolution: "semver@npm:7.7.2"
bin:
@@ -4085,9 +4139,9 @@ __metadata:
linkType: hard
"set-cookie-parser@npm:^2.6.0":
- version: 2.7.1
- resolution: "set-cookie-parser@npm:2.7.1"
- checksum: 10c0/060c198c4c92547ac15988256f445eae523f57f2ceefeccf52d30d75dedf6bff22b9c26f756bd44e8e560d44ff4ab2130b178bd2e52ef5571bf7be3bd7632d9a
+ version: 2.7.2
+ resolution: "set-cookie-parser@npm:2.7.2"
+ checksum: 10c0/4381a9eb7ee951dfe393fe7aacf76b9a3b4e93a684d2162ab35594fa4053cc82a4d7d7582bf397718012c9adcf839b8cd8f57c6c42901ea9effe33c752da4a45
languageName: node
linkType: hard
@@ -4250,6 +4304,15 @@ __metadata:
languageName: node
linkType: hard
+"ssri@npm:^13.0.0":
+ version: 13.0.0
+ resolution: "ssri@npm:13.0.0"
+ dependencies:
+ minipass: "npm:^7.0.3"
+ checksum: 10c0/405f3a531cd98b013cecb355d63555dca42fd12c7bc6671738aaa9a82882ff41cdf0ef9a2b734ca4f9a760338f114c29d01d9238a65db3ccac27929bd6e6d4b2
+ languageName: node
+ linkType: hard
+
"stop-iteration-iterator@npm:^1.1.0":
version: 1.1.0
resolution: "stop-iteration-iterator@npm:1.1.0"
@@ -4399,17 +4462,16 @@ __metadata:
languageName: node
linkType: hard
-"tar@npm:^7.4.3":
- version: 7.4.3
- resolution: "tar@npm:7.4.3"
+"tar@npm:^7.5.2":
+ version: 7.5.2
+ resolution: "tar@npm:7.5.2"
dependencies:
"@isaacs/fs-minipass": "npm:^4.0.0"
chownr: "npm:^3.0.0"
minipass: "npm:^7.1.2"
- minizlib: "npm:^3.0.1"
- mkdirp: "npm:^3.0.1"
+ minizlib: "npm:^3.1.0"
yallist: "npm:^5.0.0"
- checksum: 10c0/d4679609bb2a9b48eeaf84632b6d844128d2412b95b6de07d53d8ee8baf4ca0857c9331dfa510390a0727b550fd543d4d1a10995ad86cdf078423fbb8d99831d
+ checksum: 10c0/a7d8b801139b52f93a7e34830db0de54c5aa45487c7cb551f6f3d44a112c67f1cb8ffdae856b05fd4f17b1749911f1c26f1e3a23bbe0279e17fd96077f13f467
languageName: node
linkType: hard
@@ -4434,6 +4496,7 @@ __metadata:
globals: "npm:^16.3.0"
react: "npm:^19.1.1"
react-dom: "npm:^19.1.1"
+ react-dropzone: "npm:^14.3.8"
react-intersection-observer: "npm:^9.16.0"
react-router-dom: "npm:^7.8.2"
typescript: "npm:~5.8.3"
@@ -4470,6 +4533,13 @@ __metadata:
languageName: node
linkType: hard
+"tslib@npm:^2.7.0":
+ version: 2.8.1
+ resolution: "tslib@npm:2.8.1"
+ checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62
+ languageName: node
+ linkType: hard
+
"type-check@npm:^0.4.0, type-check@npm:~0.4.0":
version: 0.4.0
resolution: "type-check@npm:0.4.0"
@@ -4747,14 +4817,14 @@ __metadata:
languageName: node
linkType: hard
-"which@npm:^5.0.0":
- version: 5.0.0
- resolution: "which@npm:5.0.0"
+"which@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "which@npm:6.0.0"
dependencies:
isexe: "npm:^3.1.1"
bin:
node-which: bin/which.js
- checksum: 10c0/e556e4cd8b7dbf5df52408c9a9dd5ac6518c8c5267c8953f5b0564073c66ed5bf9503b14d876d0e9c7844d4db9725fb0dcf45d6e911e17e26ab363dc3965ae7b
+ checksum: 10c0/fe9d6463fe44a76232bb6e3b3181922c87510a5b250a98f1e43a69c99c079b3f42ddeca7e03d3e5f2241bf2d334f5a7657cfa868b97c109f3870625842f4cc15
languageName: node
linkType: hard